00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "CMSWindowsScreen.h"
00016 #include "CMSWindowsClipboard.h"
00017 #include "CMSWindowsDesks.h"
00018 #include "CMSWindowsEventQueueBuffer.h"
00019 #include "CMSWindowsKeyState.h"
00020 #include "CMSWindowsScreenSaver.h"
00021 #include "CClipboard.h"
00022 #include "CKeyMap.h"
00023 #include "XScreen.h"
00024 #include "CLock.h"
00025 #include "CThread.h"
00026 #include "CFunctionJob.h"
00027 #include "CLog.h"
00028 #include "CString.h"
00029 #include "CStringUtil.h"
00030 #include "IEventQueue.h"
00031 #include "TMethodEventJob.h"
00032 #include "TMethodJob.h"
00033 #include "CArch.h"
00034 #include "CArchMiscWindows.h"
00035 #include <string.h>
00036 #include <pbt.h>
00037
00038
00039
00040
00041
00042 #if defined(_MSC_VER)
00043 #pragma warning(push)
00044 #pragma warning(disable: 4706) // assignment within conditional
00045 #define COMPILE_MULTIMON_STUBS
00046 #include <multimon.h>
00047 #pragma warning(pop)
00048 #endif
00049
00050
00051 #if !defined(WM_XBUTTONDOWN)
00052 #define WM_XBUTTONDOWN 0x020B
00053 #define WM_XBUTTONUP 0x020C
00054 #define WM_XBUTTONDBLCLK 0x020D
00055 #define WM_NCXBUTTONDOWN 0x00AB
00056 #define WM_NCXBUTTONUP 0x00AC
00057 #define WM_NCXBUTTONDBLCLK 0x00AD
00058 #define MOUSEEVENTF_XDOWN 0x0080
00059 #define MOUSEEVENTF_XUP 0x0100
00060 #define XBUTTON1 0x0001
00061 #define XBUTTON2 0x0002
00062 #endif
00063 #if !defined(VK_XBUTTON1)
00064 #define VK_XBUTTON1 0x05
00065 #define VK_XBUTTON2 0x06
00066 #endif
00067
00068
00069 #if !defined(PBT_APMRESUMEAUTOMATIC)
00070 #define PBT_APMRESUMEAUTOMATIC 0x0012
00071 #endif
00072
00073
00074
00075
00076
00077 HINSTANCE CMSWindowsScreen::s_instance = NULL;
00078 CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
00079
00080 CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) :
00081 m_isPrimary(isPrimary),
00082 m_is95Family(CArchMiscWindows::isWindows95Family()),
00083 m_isOnScreen(m_isPrimary),
00084 m_class(0),
00085 m_x(0), m_y(0),
00086 m_w(0), m_h(0),
00087 m_xCenter(0), m_yCenter(0),
00088 m_multimon(false),
00089 m_xCursor(0), m_yCursor(0),
00090 m_sequenceNumber(0),
00091 m_mark(0),
00092 m_markReceived(0),
00093 m_fixTimer(NULL),
00094 m_keyLayout(NULL),
00095 m_screensaver(NULL),
00096 m_screensaverNotify(false),
00097 m_screensaverActive(false),
00098 m_window(NULL),
00099 m_nextClipboardWindow(NULL),
00100 m_ownClipboard(false),
00101 m_desks(NULL),
00102 m_hookLibrary(NULL),
00103 m_init(NULL),
00104 m_cleanup(NULL),
00105 m_setSides(NULL),
00106 m_setZone(NULL),
00107 m_setMode(NULL),
00108 m_keyState(NULL),
00109 m_hasMouse(GetSystemMetrics(SM_MOUSEPRESENT) != 0),
00110 m_showingMouse(false)
00111 {
00112 assert(s_instance != NULL);
00113 assert(s_screen == NULL);
00114
00115 s_screen = this;
00116 try {
00117 if (m_isPrimary) {
00118 m_hookLibrary = openHookLibrary("synrgyhk");
00119 }
00120 m_screensaver = new CMSWindowsScreenSaver();
00121 m_desks = new CMSWindowsDesks(m_isPrimary,
00122 m_hookLibrary, m_screensaver,
00123 new TMethodJob<CMSWindowsScreen>(this,
00124 &CMSWindowsScreen::updateKeysCB));
00125 m_keyState = new CMSWindowsKeyState(m_desks, getEventTarget());
00126 updateScreenShape();
00127 m_class = createWindowClass();
00128 m_window = createWindow(m_class, "Synergy");
00129 forceShowCursor();
00130 LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : ""));
00131 LOG((CLOG_DEBUG "window is 0x%08x", m_window));
00132 }
00133 catch (...) {
00134 delete m_keyState;
00135 delete m_desks;
00136 delete m_screensaver;
00137 destroyWindow(m_window);
00138 destroyClass(m_class);
00139 closeHookLibrary(m_hookLibrary);
00140 s_screen = NULL;
00141 throw;
00142 }
00143
00144
00145 EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(),
00146 new TMethodEventJob<CMSWindowsScreen>(this,
00147 &CMSWindowsScreen::handleSystemEvent));
00148
00149
00150 EVENTQUEUE->adoptBuffer(new CMSWindowsEventQueueBuffer);
00151 }
00152
00153 CMSWindowsScreen::~CMSWindowsScreen()
00154 {
00155 assert(s_screen != NULL);
00156
00157 disable();
00158 EVENTQUEUE->adoptBuffer(NULL);
00159 EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget());
00160 delete m_keyState;
00161 delete m_desks;
00162 delete m_screensaver;
00163 destroyWindow(m_window);
00164 destroyClass(m_class);
00165 closeHookLibrary(m_hookLibrary);
00166 s_screen = NULL;
00167 }
00168
00169 void
00170 CMSWindowsScreen::init(HINSTANCE instance)
00171 {
00172 assert(s_instance == NULL);
00173 assert(instance != NULL);
00174
00175 s_instance = instance;
00176 }
00177
00178 HINSTANCE
00179 CMSWindowsScreen::getInstance()
00180 {
00181 return s_instance;
00182 }
00183
00184 void
00185 CMSWindowsScreen::enable()
00186 {
00187 assert(m_isOnScreen == m_isPrimary);
00188
00189
00190 m_fixTimer = EVENTQUEUE->newTimer(1.0, NULL);
00191 EVENTQUEUE->adoptHandler(CEvent::kTimer, m_fixTimer,
00192 new TMethodEventJob<CMSWindowsScreen>(this,
00193 &CMSWindowsScreen::handleFixes));
00194
00195
00196 m_nextClipboardWindow = SetClipboardViewer(m_window);
00197
00198
00199 m_desks->enable();
00200
00201 if (m_isPrimary) {
00202
00203 m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
00204
00205
00206 m_setMode(kHOOK_WATCH_JUMP_ZONE);
00207 }
00208 else {
00209
00210
00211
00212 CArchMiscWindows::addBusyState(CArchMiscWindows::kSYSTEM);
00213 }
00214 }
00215
00216 void
00217 CMSWindowsScreen::disable()
00218 {
00219
00220 m_desks->disable();
00221
00222 if (m_isPrimary) {
00223
00224 m_setMode(kHOOK_DISABLE);
00225
00226
00227 enableSpecialKeys(true);
00228 }
00229 else {
00230
00231 CArchMiscWindows::removeBusyState(CArchMiscWindows::kSYSTEM |
00232 CArchMiscWindows::kDISPLAY);
00233 }
00234
00235
00236 m_keyState->disable();
00237
00238
00239 ChangeClipboardChain(m_window, m_nextClipboardWindow);
00240 m_nextClipboardWindow = NULL;
00241
00242
00243 if (m_fixTimer != NULL) {
00244 EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
00245 EVENTQUEUE->deleteTimer(m_fixTimer);
00246 m_fixTimer = NULL;
00247 }
00248
00249 m_isOnScreen = m_isPrimary;
00250 forceShowCursor();
00251 }
00252
00253 void
00254 CMSWindowsScreen::enter()
00255 {
00256 m_desks->enter();
00257 if (m_isPrimary) {
00258
00259 enableSpecialKeys(true);
00260
00261
00262 m_setMode(kHOOK_WATCH_JUMP_ZONE);
00263
00264
00265 nextMark();
00266 } else {
00267
00268
00269 CArchMiscWindows::wakeupDisplay();
00270
00271 if(m_screensaver != NULL && m_screensaverActive)
00272 {
00273 m_screensaver->deactivate();
00274 m_screensaverActive = 0;
00275 }
00276 }
00277
00278
00279 m_isOnScreen = true;
00280 forceShowCursor();
00281 }
00282
00283 bool
00284 CMSWindowsScreen::leave()
00285 {
00286
00287
00288 HWND window = GetForegroundWindow();
00289 DWORD thread = GetWindowThreadProcessId(window, NULL);
00290 m_keyLayout = GetKeyboardLayout(thread);
00291
00292
00293 m_keyState->setKeyLayout(m_keyLayout);
00294
00295
00296 m_desks->leave(m_keyLayout);
00297
00298 if (m_isPrimary) {
00299
00300 warpCursor(m_xCenter, m_yCenter);
00301
00302
00303 enableSpecialKeys(false);
00304
00305
00306 nextMark();
00307
00308
00309
00310 m_keyState->saveModifiers();
00311
00312
00313 m_setMode(kHOOK_RELAY_EVENTS);
00314 }
00315
00316
00317 m_isOnScreen = false;
00318 forceShowCursor();
00319
00320 return true;
00321 }
00322
00323 bool
00324 CMSWindowsScreen::setClipboard(ClipboardID, const IClipboard* src)
00325 {
00326 CMSWindowsClipboard dst(m_window);
00327 if (src != NULL) {
00328
00329 return CClipboard::copy(&dst, src);
00330 }
00331 else {
00332
00333 if (!dst.open(0)) {
00334 return false;
00335 }
00336 dst.empty();
00337 dst.close();
00338 return true;
00339 }
00340 }
00341
00342 void
00343 CMSWindowsScreen::checkClipboards()
00344 {
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 if (m_ownClipboard && !CMSWindowsClipboard::isOwnedBySynergy()) {
00357 LOG((CLOG_DEBUG "clipboard changed: lost ownership and no notification received"));
00358 m_ownClipboard = false;
00359 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
00360 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
00361 }
00362 }
00363
00364 void
00365 CMSWindowsScreen::openScreensaver(bool notify)
00366 {
00367 assert(m_screensaver != NULL);
00368
00369 m_screensaverNotify = notify;
00370 if (m_screensaverNotify) {
00371 m_desks->installScreensaverHooks(true);
00372 }
00373 else {
00374 m_screensaver->disable();
00375 }
00376 }
00377
00378 void
00379 CMSWindowsScreen::closeScreensaver()
00380 {
00381 if (m_screensaver != NULL) {
00382 if (m_screensaverNotify) {
00383 m_desks->installScreensaverHooks(false);
00384 }
00385 else {
00386 m_screensaver->enable();
00387 }
00388 }
00389 m_screensaverNotify = false;
00390 }
00391
00392 void
00393 CMSWindowsScreen::screensaver(bool activate)
00394 {
00395 assert(m_screensaver != NULL);
00396
00397 if (activate) {
00398 m_screensaver->activate();
00399 }
00400 else {
00401 m_screensaver->deactivate();
00402 }
00403 }
00404
00405 void
00406 CMSWindowsScreen::resetOptions()
00407 {
00408 m_desks->resetOptions();
00409 }
00410
00411 void
00412 CMSWindowsScreen::setOptions(const COptionsList& options)
00413 {
00414 m_desks->setOptions(options);
00415 }
00416
00417 void
00418 CMSWindowsScreen::setSequenceNumber(UInt32 seqNum)
00419 {
00420 m_sequenceNumber = seqNum;
00421 }
00422
00423 bool
00424 CMSWindowsScreen::isPrimary() const
00425 {
00426 return m_isPrimary;
00427 }
00428
00429 void*
00430 CMSWindowsScreen::getEventTarget() const
00431 {
00432 return const_cast<CMSWindowsScreen*>(this);
00433 }
00434
00435 bool
00436 CMSWindowsScreen::getClipboard(ClipboardID, IClipboard* dst) const
00437 {
00438 CMSWindowsClipboard src(m_window);
00439 CClipboard::copy(dst, &src);
00440 return true;
00441 }
00442
00443 void
00444 CMSWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
00445 {
00446 assert(m_class != 0);
00447
00448 x = m_x;
00449 y = m_y;
00450 w = m_w;
00451 h = m_h;
00452 }
00453
00454 void
00455 CMSWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
00456 {
00457 m_desks->getCursorPos(x, y);
00458 }
00459
00460 void
00461 CMSWindowsScreen::reconfigure(UInt32 activeSides)
00462 {
00463 assert(m_isPrimary);
00464
00465 LOG((CLOG_DEBUG "active sides: %x", activeSides));
00466 m_setSides(activeSides);
00467 }
00468
00469 void
00470 CMSWindowsScreen::warpCursor(SInt32 x, SInt32 y)
00471 {
00472
00473 warpCursorNoFlush(x, y);
00474
00475
00476 MSG msg;
00477 while (PeekMessage(&msg, NULL, SYNERGY_MSG_INPUT_FIRST,
00478 SYNERGY_MSG_INPUT_LAST, PM_REMOVE)) {
00479
00480 }
00481
00482
00483 m_xCursor = x;
00484 m_yCursor = y;
00485 }
00486
00487 UInt32
00488 CMSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
00489 {
00490
00491 if ((mask & ~(KeyModifierShift | KeyModifierControl |
00492 KeyModifierAlt | KeyModifierSuper)) != 0) {
00493 LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
00494 return 0;
00495 }
00496
00497
00498 if (key == kKeyNone && mask == 0) {
00499 return 0;
00500 }
00501
00502
00503 UINT modifiers = 0;
00504 if ((mask & KeyModifierShift) != 0) {
00505 modifiers |= MOD_SHIFT;
00506 }
00507 if ((mask & KeyModifierControl) != 0) {
00508 modifiers |= MOD_CONTROL;
00509 }
00510 if ((mask & KeyModifierAlt) != 0) {
00511 modifiers |= MOD_ALT;
00512 }
00513 if ((mask & KeyModifierSuper) != 0) {
00514 modifiers |= MOD_WIN;
00515 }
00516 UINT vk = m_keyState->mapKeyToVirtualKey(key);
00517 if (key != kKeyNone && vk == 0) {
00518
00519 LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask));
00520 return 0;
00521 }
00522
00523
00524 UInt32 id;
00525 if (!m_oldHotKeyIDs.empty()) {
00526 id = m_oldHotKeyIDs.back();
00527 m_oldHotKeyIDs.pop_back();
00528 }
00529 else {
00530 id = m_hotKeys.size() + 1;
00531 }
00532
00533
00534 bool err;
00535 if (key == kKeyNone) {
00536
00537 err = (m_hotKeyToIDMap.count(CHotKeyItem(vk, modifiers)) > 0);
00538 }
00539 else {
00540
00541 err = (RegisterHotKey(NULL, id, modifiers, vk) == 0);
00542 }
00543
00544 if (!err) {
00545 m_hotKeys.insert(std::make_pair(id, CHotKeyItem(vk, modifiers)));
00546 m_hotKeyToIDMap[CHotKeyItem(vk, modifiers)] = id;
00547 }
00548 else {
00549 m_oldHotKeyIDs.push_back(id);
00550 m_hotKeys.erase(id);
00551 LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", CKeyMap::formatKey(key, mask).c_str(), key, mask));
00552 return 0;
00553 }
00554
00555 LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", CKeyMap::formatKey(key, mask).c_str(), key, mask, id));
00556 return id;
00557 }
00558
00559 void
00560 CMSWindowsScreen::unregisterHotKey(UInt32 id)
00561 {
00562
00563 HotKeyMap::iterator i = m_hotKeys.find(id);
00564 if (i == m_hotKeys.end()) {
00565 return;
00566 }
00567
00568
00569 bool err;
00570 if (i->second.getVirtualKey() != 0) {
00571 err = !UnregisterHotKey(NULL, id);
00572 }
00573 else {
00574 err = false;
00575 }
00576 if (err) {
00577 LOG((CLOG_WARN "failed to unregister hotkey id=%d", id));
00578 }
00579 else {
00580 LOG((CLOG_DEBUG "unregistered hotkey id=%d", id));
00581 }
00582
00583
00584 m_hotKeyToIDMap.erase(i->second);
00585 m_hotKeys.erase(i);
00586 m_oldHotKeyIDs.push_back(id);
00587 }
00588
00589 void
00590 CMSWindowsScreen::fakeInputBegin()
00591 {
00592 assert(m_isPrimary);
00593
00594 if (!m_isOnScreen) {
00595 m_keyState->useSavedModifiers(true);
00596 }
00597 m_desks->fakeInputBegin();
00598 }
00599
00600 void
00601 CMSWindowsScreen::fakeInputEnd()
00602 {
00603 assert(m_isPrimary);
00604
00605 m_desks->fakeInputEnd();
00606 if (!m_isOnScreen) {
00607 m_keyState->useSavedModifiers(false);
00608 }
00609 }
00610
00611 SInt32
00612 CMSWindowsScreen::getJumpZoneSize() const
00613 {
00614 return 1;
00615 }
00616
00617 bool
00618 CMSWindowsScreen::isAnyMouseButtonDown() const
00619 {
00620 static const char* buttonToName[] = {
00621 "<invalid>",
00622 "Left Button",
00623 "Middle Button",
00624 "Right Button",
00625 "X Button 1",
00626 "X Button 2"
00627 };
00628
00629 for (UInt32 i = 1; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
00630 if (m_buttons[i]) {
00631 LOG((CLOG_DEBUG "locked by \"%s\"", buttonToName[i]));
00632 return true;
00633 }
00634 }
00635
00636 return false;
00637 }
00638
00639 void
00640 CMSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
00641 {
00642 x = m_xCenter;
00643 y = m_yCenter;
00644 }
00645
00646 void
00647 CMSWindowsScreen::fakeMouseButton(ButtonID id, bool press) const
00648 {
00649 m_desks->fakeMouseButton(id, press);
00650 }
00651
00652 void
00653 CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const
00654 {
00655 m_desks->fakeMouseMove(x, y);
00656 }
00657
00658 void
00659 CMSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
00660 {
00661 m_desks->fakeMouseRelativeMove(dx, dy);
00662 }
00663
00664 void
00665 CMSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
00666 {
00667 m_desks->fakeMouseWheel(xDelta, yDelta);
00668 }
00669
00670 void
00671 CMSWindowsScreen::updateKeys()
00672 {
00673 m_desks->updateKeys();
00674 }
00675
00676 void
00677 CMSWindowsScreen::fakeKeyDown(KeyID id, KeyModifierMask mask,
00678 KeyButton button)
00679 {
00680 CPlatformScreen::fakeKeyDown(id, mask, button);
00681 updateForceShowCursor();
00682 }
00683
00684 void
00685 CMSWindowsScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask,
00686 SInt32 count, KeyButton button)
00687 {
00688 CPlatformScreen::fakeKeyRepeat(id, mask, count, button);
00689 updateForceShowCursor();
00690 }
00691
00692 void
00693 CMSWindowsScreen::fakeKeyUp(KeyButton button)
00694 {
00695 CPlatformScreen::fakeKeyUp(button);
00696 updateForceShowCursor();
00697 }
00698
00699 void
00700 CMSWindowsScreen::fakeAllKeysUp()
00701 {
00702 CPlatformScreen::fakeAllKeysUp();
00703 updateForceShowCursor();
00704 }
00705
00706 HINSTANCE
00707 CMSWindowsScreen::openHookLibrary(const char* name)
00708 {
00709
00710 HINSTANCE hookLibrary = LoadLibrary(name);
00711 if (hookLibrary == NULL) {
00712 LOG((CLOG_ERR "Failed to load hook library; %s.dll is missing", name));
00713 throw XScreenOpenFailure();
00714 }
00715
00716
00717 m_setSides = (SetSidesFunc)GetProcAddress(hookLibrary, "setSides");
00718 m_setZone = (SetZoneFunc)GetProcAddress(hookLibrary, "setZone");
00719 m_setMode = (SetModeFunc)GetProcAddress(hookLibrary, "setMode");
00720 m_init = (InitFunc)GetProcAddress(hookLibrary, "init");
00721 m_cleanup = (CleanupFunc)GetProcAddress(hookLibrary, "cleanup");
00722 if (m_setSides == NULL ||
00723 m_setZone == NULL ||
00724 m_setMode == NULL ||
00725 m_init == NULL ||
00726 m_cleanup == NULL) {
00727 LOG((CLOG_ERR "Invalid hook library; use a newer %s.dll", name));
00728 throw XScreenOpenFailure();
00729 }
00730
00731
00732 if (m_init(GetCurrentThreadId()) == 0) {
00733 LOG((CLOG_ERR "Cannot initialize hook library; is synergy already running?"));
00734 throw XScreenOpenFailure();
00735 }
00736
00737 return hookLibrary;
00738 }
00739
00740 void
00741 CMSWindowsScreen::closeHookLibrary(HINSTANCE hookLibrary) const
00742 {
00743 if (hookLibrary != NULL) {
00744 m_cleanup();
00745 FreeLibrary(hookLibrary);
00746 }
00747 }
00748
00749 HCURSOR
00750 CMSWindowsScreen::createBlankCursor() const
00751 {
00752
00753 int cw = GetSystemMetrics(SM_CXCURSOR);
00754 int ch = GetSystemMetrics(SM_CYCURSOR);
00755 UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
00756 UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
00757 memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
00758 memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2));
00759 HCURSOR c = CreateCursor(s_instance, 0, 0, cw, ch, cursorAND, cursorXOR);
00760 delete[] cursorXOR;
00761 delete[] cursorAND;
00762 return c;
00763 }
00764
00765 void
00766 CMSWindowsScreen::destroyCursor(HCURSOR cursor) const
00767 {
00768 if (cursor != NULL) {
00769 DestroyCursor(cursor);
00770 }
00771 }
00772
00773 ATOM
00774 CMSWindowsScreen::createWindowClass() const
00775 {
00776 WNDCLASSEX classInfo;
00777 classInfo.cbSize = sizeof(classInfo);
00778 classInfo.style = CS_DBLCLKS | CS_NOCLOSE;
00779 classInfo.lpfnWndProc = &CMSWindowsScreen::wndProc;
00780 classInfo.cbClsExtra = 0;
00781 classInfo.cbWndExtra = 0;
00782 classInfo.hInstance = s_instance;
00783 classInfo.hIcon = NULL;
00784 classInfo.hCursor = NULL;
00785 classInfo.hbrBackground = NULL;
00786 classInfo.lpszMenuName = NULL;
00787 classInfo.lpszClassName = "Synergy";
00788 classInfo.hIconSm = NULL;
00789 return RegisterClassEx(&classInfo);
00790 }
00791
00792 void
00793 CMSWindowsScreen::destroyClass(ATOM windowClass) const
00794 {
00795 if (windowClass != 0) {
00796 UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_instance);
00797 }
00798 }
00799
00800 HWND
00801 CMSWindowsScreen::createWindow(ATOM windowClass, const char* name) const
00802 {
00803 HWND window = CreateWindowEx(WS_EX_TOPMOST |
00804 WS_EX_TRANSPARENT |
00805 WS_EX_TOOLWINDOW,
00806 reinterpret_cast<LPCTSTR>(windowClass),
00807 name,
00808 WS_POPUP,
00809 0, 0, 1, 1,
00810 NULL, NULL,
00811 s_instance,
00812 NULL);
00813 if (window == NULL) {
00814 LOG((CLOG_ERR "failed to create window: %d", GetLastError()));
00815 throw XScreenOpenFailure();
00816 }
00817 return window;
00818 }
00819
00820 void
00821 CMSWindowsScreen::destroyWindow(HWND hwnd) const
00822 {
00823 if (hwnd != NULL) {
00824 DestroyWindow(hwnd);
00825 }
00826 }
00827
00828 void
00829 CMSWindowsScreen::sendEvent(CEvent::Type type, void* data)
00830 {
00831 EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), data));
00832 }
00833
00834 void
00835 CMSWindowsScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id)
00836 {
00837 CClipboardInfo* info = (CClipboardInfo*)malloc(sizeof(CClipboardInfo));
00838 info->m_id = id;
00839 info->m_sequenceNumber = m_sequenceNumber;
00840 sendEvent(type, info);
00841 }
00842
00843 void
00844 CMSWindowsScreen::handleSystemEvent(const CEvent& event, void*)
00845 {
00846 MSG* msg = reinterpret_cast<MSG*>(event.getData());
00847 assert(msg != NULL);
00848
00849 if (CArchMiscWindows::processDialog(msg)) {
00850 return;
00851 }
00852 if (onPreDispatch(msg->hwnd, msg->message, msg->wParam, msg->lParam)) {
00853 return;
00854 }
00855 TranslateMessage(msg);
00856 DispatchMessage(msg);
00857 }
00858
00859 void
00860 CMSWindowsScreen::updateButtons()
00861 {
00862 int numButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
00863 m_buttons[kButtonNone] = false;
00864 m_buttons[kButtonLeft] = (GetKeyState(VK_LBUTTON) < 0);
00865 m_buttons[kButtonRight] = (GetKeyState(VK_RBUTTON) < 0);
00866 m_buttons[kButtonMiddle] = (GetKeyState(VK_MBUTTON) < 0);
00867 m_buttons[kButtonExtra0 + 0] = (numButtons >= 4) &&
00868 (GetKeyState(VK_XBUTTON1) < 0);
00869 m_buttons[kButtonExtra0 + 1] = (numButtons >= 5) &&
00870 (GetKeyState(VK_XBUTTON2) < 0);
00871 }
00872
00873 IKeyState*
00874 CMSWindowsScreen::getKeyState() const
00875 {
00876 return m_keyState;
00877 }
00878
00879 bool
00880 CMSWindowsScreen::onPreDispatch(HWND hwnd,
00881 UINT message, WPARAM wParam, LPARAM lParam)
00882 {
00883
00884 switch (message) {
00885 case SYNERGY_MSG_SCREEN_SAVER:
00886 return onScreensaver(wParam != 0);
00887
00888 case SYNERGY_MSG_DEBUG:
00889 LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", wParam, lParam));
00890 return true;
00891 }
00892
00893 if (m_isPrimary) {
00894 return onPreDispatchPrimary(hwnd, message, wParam, lParam);
00895 }
00896
00897 return false;
00898 }
00899
00900 bool
00901 CMSWindowsScreen::onPreDispatchPrimary(HWND,
00902 UINT message, WPARAM wParam, LPARAM lParam)
00903 {
00904
00905 switch (message) {
00906 case SYNERGY_MSG_MARK:
00907 return onMark(static_cast<UInt32>(wParam));
00908
00909 case SYNERGY_MSG_KEY:
00910 return onKey(wParam, lParam);
00911
00912 case SYNERGY_MSG_MOUSE_BUTTON:
00913 return onMouseButton(wParam, lParam);
00914
00915 case SYNERGY_MSG_MOUSE_MOVE:
00916 return onMouseMove(static_cast<SInt32>(wParam),
00917 static_cast<SInt32>(lParam));
00918
00919 case SYNERGY_MSG_MOUSE_WHEEL:
00920
00921 return onMouseWheel(0, static_cast<SInt32>(wParam));
00922
00923 case SYNERGY_MSG_PRE_WARP:
00924 {
00925
00926 m_xCursor = static_cast<SInt32>(wParam);
00927 m_yCursor = static_cast<SInt32>(lParam);
00928
00929
00930
00931
00932
00933
00934 MSG msg;
00935 do {
00936 GetMessage(&msg, NULL, SYNERGY_MSG_MOUSE_MOVE,
00937 SYNERGY_MSG_POST_WARP);
00938 } while (msg.message != SYNERGY_MSG_POST_WARP);
00939 }
00940 return true;
00941
00942 case SYNERGY_MSG_POST_WARP:
00943 LOG((CLOG_WARN "unmatched post warp"));
00944 return true;
00945
00946 case WM_HOTKEY:
00947
00948
00949
00950
00951 break;
00952 }
00953
00954 return false;
00955 }
00956
00957 bool
00958 CMSWindowsScreen::onEvent(HWND, UINT msg,
00959 WPARAM wParam, LPARAM lParam, LRESULT* result)
00960 {
00961 switch (msg) {
00962 case WM_QUERYENDSESSION:
00963 if (m_is95Family) {
00964 *result = TRUE;
00965 return true;
00966 }
00967 break;
00968
00969 case WM_ENDSESSION:
00970 if (m_is95Family) {
00971 if (wParam == TRUE && lParam == 0) {
00972 EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00973 }
00974 return true;
00975 }
00976 break;
00977
00978 case WM_DRAWCLIPBOARD:
00979
00980 if (m_nextClipboardWindow != NULL) {
00981 SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
00982 }
00983
00984
00985 return onClipboardChange();
00986
00987 case WM_CHANGECBCHAIN:
00988 if (m_nextClipboardWindow == (HWND)wParam) {
00989 m_nextClipboardWindow = (HWND)lParam;
00990 LOG((CLOG_DEBUG "clipboard chain: new next: 0x%08x", m_nextClipboardWindow));
00991 }
00992 else if (m_nextClipboardWindow != NULL) {
00993 SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
00994 }
00995 return true;
00996
00997 case WM_DISPLAYCHANGE:
00998 return onDisplayChange();
00999
01000 case WM_POWERBROADCAST:
01001 switch (wParam) {
01002 case PBT_APMRESUMEAUTOMATIC:
01003 case PBT_APMRESUMECRITICAL:
01004 case PBT_APMRESUMESUSPEND:
01005 EVENTQUEUE->addEvent(CEvent(IScreen::getResumeEvent(),
01006 getEventTarget(), NULL,
01007 CEvent::kDeliverImmediately));
01008 break;
01009
01010 case PBT_APMSUSPEND:
01011 EVENTQUEUE->addEvent(CEvent(IScreen::getSuspendEvent(),
01012 getEventTarget(), NULL,
01013 CEvent::kDeliverImmediately));
01014 break;
01015 }
01016 *result = TRUE;
01017 return true;
01018
01019 case WM_DEVICECHANGE:
01020 forceShowCursor();
01021 break;
01022
01023 case WM_SETTINGCHANGE:
01024 if (wParam == SPI_SETMOUSEKEYS) {
01025 forceShowCursor();
01026 }
01027 break;
01028 }
01029
01030 return false;
01031 }
01032
01033 bool
01034 CMSWindowsScreen::onMark(UInt32 mark)
01035 {
01036 m_markReceived = mark;
01037 return true;
01038 }
01039
01040 bool
01041 CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
01042 {
01043 static const KeyModifierMask s_ctrlAlt =
01044 KeyModifierControl | KeyModifierAlt;
01045
01046 LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, (wParam & 0x10000u) ? 1 : 0, lParam));
01047
01048
01049 KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16);
01050 bool down = ((lParam & 0x80000000u) == 0x00000000u);
01051 bool wasDown = isKeyDown(button);
01052 KeyModifierMask oldState = pollActiveModifiers();
01053
01054
01055 if (m_keyState->testAutoRepeat(down, (lParam & 0x40000000u) == 1, button)) {
01056 lParam |= 0x40000000u;
01057 }
01058
01059
01060
01061
01062
01063 if (button == 0) {
01064 button = m_keyState->virtualKeyToButton(wParam & 0xffu);
01065 if (button == 0) {
01066 return true;
01067 }
01068 wasDown = isKeyDown(button);
01069 }
01070
01071
01072 m_keyState->onKey(button, down, oldState);
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092 KeyModifierMask state = pollActiveModifiers();
01093 m_keyState->onKey(button, down, state);
01094
01095
01096 if (oldState != state) {
01097
01098 if (onHotKey(0, lParam)) {
01099 return true;
01100 }
01101 }
01102 else {
01103
01104 if (onHotKey(wParam, lParam)) {
01105 return true;
01106 }
01107 }
01108
01109
01110 if (!ignore()) {
01111
01112
01113 UINT virtKey = (wParam & 0xffu);
01114 if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) {
01115 LOG((CLOG_DEBUG "discard ctrl+alt+del"));
01116 return true;
01117 }
01118
01119
01120 if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) &&
01121 (state & s_ctrlAlt) == s_ctrlAlt) {
01122 LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
01123
01124
01125
01126
01127 wParam = VK_DELETE | 0x00010000u;
01128 lParam &= 0xfe000000;
01129 lParam |= m_keyState->virtualKeyToButton(wParam & 0xffu) << 16;
01130 lParam |= 0x01000001;
01131 }
01132
01133
01134 KeyModifierMask mask;
01135 KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask);
01136 button = static_cast<KeyButton>((lParam & 0x01ff0000u) >> 16);
01137 if (key != kKeyNone) {
01138
01139
01140
01141
01142
01143
01144 if (m_is95Family && !wasDown && !down) {
01145 switch (virtKey) {
01146 case VK_SHIFT:
01147 case VK_LSHIFT:
01148 case VK_RSHIFT:
01149 case VK_CONTROL:
01150 case VK_LCONTROL:
01151 case VK_RCONTROL:
01152 case VK_MENU:
01153 case VK_LMENU:
01154 case VK_RMENU:
01155 case VK_LWIN:
01156 case VK_RWIN:
01157 case VK_CAPITAL:
01158 case VK_NUMLOCK:
01159 case VK_SCROLL:
01160 break;
01161
01162 default:
01163 m_keyState->sendKeyEvent(getEventTarget(),
01164 true, false, key, mask, 1, button);
01165 break;
01166 }
01167 }
01168
01169
01170 m_keyState->sendKeyEvent(getEventTarget(),
01171 ((lParam & 0x80000000u) == 0),
01172 ((lParam & 0x40000000u) != 0),
01173 key, mask, (SInt32)(lParam & 0xffff), button);
01174 }
01175 else {
01176 LOG((CLOG_DEBUG1 "cannot map key"));
01177 }
01178 }
01179
01180 return true;
01181 }
01182
01183 bool
01184 CMSWindowsScreen::onHotKey(WPARAM wParam, LPARAM lParam)
01185 {
01186
01187 KeyModifierMask state = getActiveModifiers();
01188 UINT virtKey = (wParam & 0xffu);
01189 UINT modifiers = 0;
01190 if ((state & KeyModifierShift) != 0) {
01191 modifiers |= MOD_SHIFT;
01192 }
01193 if ((state & KeyModifierControl) != 0) {
01194 modifiers |= MOD_CONTROL;
01195 }
01196 if ((state & KeyModifierAlt) != 0) {
01197 modifiers |= MOD_ALT;
01198 }
01199 if ((state & KeyModifierSuper) != 0) {
01200 modifiers |= MOD_WIN;
01201 }
01202
01203
01204 HotKeyToIDMap::const_iterator i =
01205 m_hotKeyToIDMap.find(CHotKeyItem(virtKey, modifiers));
01206 if (i == m_hotKeyToIDMap.end()) {
01207 return false;
01208 }
01209
01210
01211 CEvent::Type type;
01212 if ((lParam & 0x80000000u) == 0u) {
01213 if ((lParam & 0x40000000u) != 0u) {
01214
01215 return true;
01216 }
01217 type = getHotKeyDownEvent();
01218 }
01219 else {
01220 type = getHotKeyUpEvent();
01221 }
01222
01223
01224 EVENTQUEUE->addEvent(CEvent(type, getEventTarget(),
01225 CHotKeyInfo::alloc(i->second)));
01226
01227 return true;
01228 }
01229
01230 bool
01231 CMSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam)
01232 {
01233
01234 bool pressed = mapPressFromEvent(wParam, lParam);
01235 ButtonID button = mapButtonFromEvent(wParam, lParam);
01236
01237
01238 if (button >= kButtonLeft && button <= kButtonExtra0 + 1) {
01239 if (pressed) {
01240 m_buttons[button] = true;
01241 }
01242 else {
01243 m_buttons[button] = false;
01244 }
01245 }
01246
01247
01248 if (!ignore()) {
01249 KeyModifierMask mask = m_keyState->getActiveModifiers();
01250 if (pressed) {
01251 LOG((CLOG_DEBUG1 "event: button press button=%d", button));
01252 if (button != kButtonNone) {
01253 sendEvent(getButtonDownEvent(),
01254 CButtonInfo::alloc(button, mask));
01255 }
01256 }
01257 else {
01258 LOG((CLOG_DEBUG1 "event: button release button=%d", button));
01259 if (button != kButtonNone) {
01260 sendEvent(getButtonUpEvent(),
01261 CButtonInfo::alloc(button, mask));
01262 }
01263 }
01264 }
01265
01266 return true;
01267 }
01268
01269 bool
01270 CMSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
01271 {
01272
01273
01274 SInt32 x = mx - m_xCursor;
01275 SInt32 y = my - m_yCursor;
01276
01277
01278
01279 if (ignore() || (x == 0 && y == 0)) {
01280 return true;
01281 }
01282
01283
01284 m_xCursor = mx;
01285 m_yCursor = my;
01286
01287 if (m_isOnScreen) {
01288
01289 sendEvent(getMotionOnPrimaryEvent(),
01290 CMotionInfo::alloc(m_xCursor, m_yCursor));
01291 }
01292 else {
01293
01294
01295 warpCursorNoFlush(m_xCenter, m_yCenter);
01296
01297
01298
01299
01300
01301
01302 static SInt32 bogusZoneSize = 10;
01303 if (-x + bogusZoneSize > m_xCenter - m_x ||
01304 x + bogusZoneSize > m_x + m_w - m_xCenter ||
01305 -y + bogusZoneSize > m_yCenter - m_y ||
01306 y + bogusZoneSize > m_y + m_h - m_yCenter) {
01307 LOG((CLOG_DEBUG "dropped bogus motion %+d,%+d", x, y));
01308 }
01309 else {
01310
01311 sendEvent(getMotionOnSecondaryEvent(), CMotionInfo::alloc(x, y));
01312 }
01313 }
01314
01315 return true;
01316 }
01317
01318 bool
01319 CMSWindowsScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta)
01320 {
01321
01322 if (!ignore()) {
01323 LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta));
01324 sendEvent(getWheelEvent(), CWheelInfo::alloc(xDelta, yDelta));
01325 }
01326 return true;
01327 }
01328
01329 bool
01330 CMSWindowsScreen::onScreensaver(bool activated)
01331 {
01332
01333
01334
01335
01336
01337
01338
01339
01340 MSG msg;
01341 if (PeekMessage(&msg, NULL, SYNERGY_MSG_SCREEN_SAVER,
01342 SYNERGY_MSG_SCREEN_SAVER, PM_NOREMOVE)) {
01343 return true;
01344 }
01345
01346 if (activated) {
01347 if (!m_screensaverActive &&
01348 m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) {
01349 m_screensaverActive = true;
01350 sendEvent(getScreensaverActivatedEvent());
01351
01352
01353 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
01354 }
01355 }
01356 else {
01357 if (m_screensaverActive) {
01358 m_screensaverActive = false;
01359 sendEvent(getScreensaverDeactivatedEvent());
01360
01361
01362 CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);
01363 }
01364 }
01365
01366 return true;
01367 }
01368
01369 bool
01370 CMSWindowsScreen::onDisplayChange()
01371 {
01372
01373 SInt32 xOld = m_x, yOld = m_y, wOld = m_w, hOld = m_h;
01374
01375
01376 updateScreenShape();
01377
01378
01379 if (xOld != m_x || yOld != m_y || wOld != m_w || hOld != m_h) {
01380 if (m_isPrimary) {
01381
01382 if (!m_isOnScreen) {
01383 warpCursor(m_xCenter, m_yCenter);
01384 }
01385
01386
01387 else {
01388 m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
01389 }
01390 }
01391
01392
01393 sendEvent(getShapeChangedEvent());
01394
01395 LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : ""));
01396 }
01397
01398 return true;
01399 }
01400
01401 bool
01402 CMSWindowsScreen::onClipboardChange()
01403 {
01404
01405
01406 if (!CMSWindowsClipboard::isOwnedBySynergy()) {
01407 if (m_ownClipboard) {
01408 LOG((CLOG_DEBUG "clipboard changed: lost ownership"));
01409 m_ownClipboard = false;
01410 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
01411 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
01412 }
01413 }
01414 else if (!m_ownClipboard) {
01415 LOG((CLOG_DEBUG "clipboard changed: synergy owned"));
01416 m_ownClipboard = true;
01417 }
01418
01419 return true;
01420 }
01421
01422 void
01423 CMSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
01424 {
01425
01426 PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_PRE_WARP, x, y);
01427
01428
01429
01430 SetCursorPos(x, y);
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448 ARCH->sleep(0.0);
01449
01450
01451 PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_POST_WARP, 0, 0);
01452 }
01453
01454 void
01455 CMSWindowsScreen::nextMark()
01456 {
01457
01458 ++m_mark;
01459
01460
01461 PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_MARK, m_mark, 0);
01462 }
01463
01464 bool
01465 CMSWindowsScreen::ignore() const
01466 {
01467 return (m_mark != m_markReceived);
01468 }
01469
01470 void
01471 CMSWindowsScreen::updateScreenShape()
01472 {
01473
01474 m_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
01475 m_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
01476 m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
01477 m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
01478
01479
01480 m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1;
01481 m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1;
01482
01483
01484 m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) ||
01485 m_h != GetSystemMetrics(SM_CYSCREEN));
01486
01487
01488 m_desks->setShape(m_x, m_y, m_w, m_h, m_xCenter, m_yCenter, m_multimon);
01489 }
01490
01491 void
01492 CMSWindowsScreen::handleFixes(const CEvent&, void*)
01493 {
01494
01495 fixClipboardViewer();
01496
01497
01498 if (m_keyState->didGroupsChange()) {
01499 updateKeys();
01500 }
01501 }
01502
01503 void
01504 CMSWindowsScreen::fixClipboardViewer()
01505 {
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518 }
01519
01520 void
01521 CMSWindowsScreen::enableSpecialKeys(bool enable) const
01522 {
01523
01524
01525
01526
01527 if (m_is95Family) {
01528 DWORD dummy = 0;
01529 SystemParametersInfo(SPI_SETSCREENSAVERRUNNING,
01530 enable ? FALSE : TRUE, &dummy, 0);
01531 }
01532 }
01533
01534 ButtonID
01535 CMSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const
01536 {
01537 switch (msg) {
01538 case WM_LBUTTONDOWN:
01539 case WM_LBUTTONDBLCLK:
01540 case WM_LBUTTONUP:
01541 case WM_NCLBUTTONDOWN:
01542 case WM_NCLBUTTONDBLCLK:
01543 case WM_NCLBUTTONUP:
01544 return kButtonLeft;
01545
01546 case WM_MBUTTONDOWN:
01547 case WM_MBUTTONDBLCLK:
01548 case WM_MBUTTONUP:
01549 case WM_NCMBUTTONDOWN:
01550 case WM_NCMBUTTONDBLCLK:
01551 case WM_NCMBUTTONUP:
01552 return kButtonMiddle;
01553
01554 case WM_RBUTTONDOWN:
01555 case WM_RBUTTONDBLCLK:
01556 case WM_RBUTTONUP:
01557 case WM_NCRBUTTONDOWN:
01558 case WM_NCRBUTTONDBLCLK:
01559 case WM_NCRBUTTONUP:
01560 return kButtonRight;
01561
01562 case WM_XBUTTONDOWN:
01563 case WM_XBUTTONDBLCLK:
01564 case WM_XBUTTONUP:
01565 case WM_NCXBUTTONDOWN:
01566 case WM_NCXBUTTONDBLCLK:
01567 case WM_NCXBUTTONUP:
01568 switch (button) {
01569 case XBUTTON1:
01570 if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 4) {
01571 return kButtonExtra0 + 0;
01572 }
01573 break;
01574
01575 case XBUTTON2:
01576 if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 5) {
01577 return kButtonExtra0 + 1;
01578 }
01579 break;
01580 }
01581 return kButtonNone;
01582
01583 default:
01584 return kButtonNone;
01585 }
01586 }
01587
01588 bool
01589 CMSWindowsScreen::mapPressFromEvent(WPARAM msg, LPARAM) const
01590 {
01591 switch (msg) {
01592 case WM_LBUTTONDOWN:
01593 case WM_MBUTTONDOWN:
01594 case WM_RBUTTONDOWN:
01595 case WM_XBUTTONDOWN:
01596 case WM_LBUTTONDBLCLK:
01597 case WM_MBUTTONDBLCLK:
01598 case WM_RBUTTONDBLCLK:
01599 case WM_XBUTTONDBLCLK:
01600 case WM_NCLBUTTONDOWN:
01601 case WM_NCMBUTTONDOWN:
01602 case WM_NCRBUTTONDOWN:
01603 case WM_NCXBUTTONDOWN:
01604 case WM_NCLBUTTONDBLCLK:
01605 case WM_NCMBUTTONDBLCLK:
01606 case WM_NCRBUTTONDBLCLK:
01607 case WM_NCXBUTTONDBLCLK:
01608 return true;
01609
01610 case WM_LBUTTONUP:
01611 case WM_MBUTTONUP:
01612 case WM_RBUTTONUP:
01613 case WM_XBUTTONUP:
01614 case WM_NCLBUTTONUP:
01615 case WM_NCMBUTTONUP:
01616 case WM_NCRBUTTONUP:
01617 case WM_NCXBUTTONUP:
01618 return false;
01619
01620 default:
01621 return false;
01622 }
01623 }
01624
01625 void
01626 CMSWindowsScreen::updateKeysCB(void*)
01627 {
01628
01629 bool down[IKeyState::kNumButtons];
01630 bool sendFixes = (isPrimary() && !m_isOnScreen);
01631 if (sendFixes) {
01632 for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) {
01633 down[i] = m_keyState->isKeyDown(i);
01634 }
01635 }
01636
01637
01638 if (m_keyState->didGroupsChange()) {
01639 CPlatformScreen::updateKeyMap();
01640 }
01641
01642
01643 CPlatformScreen::updateKeyState();
01644
01645
01646
01647 if (sendFixes) {
01648 KeyModifierMask mask = pollActiveModifiers();
01649 for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) {
01650 if (down[i] && !m_keyState->isKeyDown(i)) {
01651 m_keyState->sendKeyEvent(getEventTarget(),
01652 false, false, kKeyNone, mask, 1, i);
01653 }
01654 }
01655 }
01656 }
01657
01658 void
01659 CMSWindowsScreen::forceShowCursor()
01660 {
01661
01662 m_hasMouse = (GetSystemMetrics(SM_MOUSEPRESENT) != 0);
01663
01664
01665 bool showMouse = (!m_hasMouse && !m_isPrimary && m_isOnScreen);
01666
01667
01668 if (showMouse != m_showingMouse) {
01669 if (showMouse) {
01670 m_oldMouseKeys.cbSize = sizeof(m_oldMouseKeys);
01671 m_gotOldMouseKeys =
01672 (SystemParametersInfo(SPI_GETMOUSEKEYS,
01673 m_oldMouseKeys.cbSize, &m_oldMouseKeys, 0) != 0);
01674 if (m_gotOldMouseKeys) {
01675 m_mouseKeys = m_oldMouseKeys;
01676 m_showingMouse = true;
01677 updateForceShowCursor();
01678 }
01679 }
01680 else {
01681 if (m_gotOldMouseKeys) {
01682 SystemParametersInfo(SPI_SETMOUSEKEYS,
01683 m_oldMouseKeys.cbSize,
01684 &m_oldMouseKeys, SPIF_SENDCHANGE);
01685 m_showingMouse = false;
01686 }
01687 }
01688 }
01689 }
01690
01691 void
01692 CMSWindowsScreen::updateForceShowCursor()
01693 {
01694 DWORD oldFlags = m_mouseKeys.dwFlags;
01695
01696
01697 m_mouseKeys.dwFlags = MKF_AVAILABLE | MKF_MOUSEKEYSON;
01698
01699
01700
01701 if ((m_keyState->getActiveModifiers() & KeyModifierNumLock) != 0) {
01702 m_mouseKeys.dwFlags |= MKF_REPLACENUMBERS;
01703 }
01704
01705
01706 if (oldFlags != m_mouseKeys.dwFlags) {
01707 SystemParametersInfo(SPI_SETMOUSEKEYS,
01708 m_mouseKeys.cbSize, &m_mouseKeys, SPIF_SENDCHANGE);
01709 }
01710 }
01711
01712 LRESULT CALLBACK
01713 CMSWindowsScreen::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
01714 {
01715 assert(s_screen != NULL);
01716
01717 LRESULT result = 0;
01718 if (!s_screen->onEvent(hwnd, msg, wParam, lParam, &result)) {
01719 result = DefWindowProc(hwnd, msg, wParam, lParam);
01720 }
01721
01722 return result;
01723 }
01724
01725
01726
01727
01728
01729
01730 CMSWindowsScreen::CHotKeyItem::CHotKeyItem(UINT keycode, UINT mask) :
01731 m_keycode(keycode),
01732 m_mask(mask)
01733 {
01734
01735 }
01736
01737 UINT
01738 CMSWindowsScreen::CHotKeyItem::getVirtualKey() const
01739 {
01740 return m_keycode;
01741 }
01742
01743 bool
01744 CMSWindowsScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
01745 {
01746 return (m_keycode < x.m_keycode ||
01747 (m_keycode == x.m_keycode && m_mask < x.m_mask));
01748 }