Changeset 2771 for trunk/synergy/lib/platform/CPMScreen.cpp
- Timestamp:
- Aug 20, 2006, 8:17:41 AM (19 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/synergy/lib/platform/CPMScreen.cpp
r2765 r2771 40 40 // 41 41 42 CPMScreen* 42 CPMScreen* CPMScreen::s_screen = NULL; 43 43 44 44 CPMScreen::CPMScreen(bool isPrimary) : 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 { 71 72 45 m_isPrimary(isPrimary), 46 m_isOnScreen(m_isPrimary), 47 m_x(0), m_y(0), 48 m_cx(0), m_cy(0), 49 m_xCenter(0), m_yCenter(0), 50 m_multimon(false), 51 m_xCursor(0), m_yCursor(0), 52 m_sequenceNumber(0), 53 m_mark(0), 54 m_markReceived(0), 55 m_screensaver(NULL), 56 m_screensaverNotify(false), 57 m_screensaverActive(false), 58 m_window(NULLHANDLE), 59 m_nextClipboardWindow(NULLHANDLE), 60 m_ownClipboard(false), 61 m_hmodHook(NULLHANDLE), 62 m_init(NULL), 63 m_cleanup(NULL), 64 m_setSides(NULL), 65 m_setZone(NULL), 66 m_setMode(NULL), 67 m_keyState(NULL), 68 m_hasMouse(WinQuerySysValue(HWND_DESKTOP, SV_MOUSEPRESENT) != FALSE), 69 m_showingMouse(false) 70 { 71 assert(s_screen == NULL); 72 s_screen = this; 73 73 LOG((CLOG_DEBUG1 "CPMScreen: isPrimary=%d", isPrimary)); 74 74 75 75 // create the event queue buffer first so we know there is a message queue. 76 76 CPMEventQueueBuffer *eventQueue = new CPMEventQueueBuffer(); 77 77 78 79 80 78 // query curren thread bits. 79 m_threadID = _gettid(); 80 m_hab = WinQueryAnchorBlock(HWND_DESKTOP); 81 81 //if (m_hab == NULLHANDLE) { 82 82 // m_hab = WinInitialize(0); 83 83 //} 84 84 m_hmq = WinQueueFromID(m_hab, getpid(), _gettid()); 85 85 //if (m_hab != NULLHANDLE && m_hmq == NULLHANDLE) { 86 86 // m_hmq = WinCreateMsgQueue(m_hab, 0); 87 87 //} 88 89 88 if (m_hab == NULLHANDLE || m_hmq == NULLHANDLE) { 89 LOG((CLOG_CRIT "couldn't get the hab(%ld)/hmq(%ld) of the current thread! %d", m_hab, m_hmq)); 90 90 delete eventQueue; 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 91 s_screen = NULL; 92 throw XScreenOpenFailure(); 93 } 94 95 try { 96 m_hmodHook = openHookLibrary("synrgyhk"); 97 m_screensaver = new CPMScreenSaver(); 98 m_keyState = new CPMKeyState(getEventTarget(), m_fakeMsg); 99 updateScreenShape(); 100 m_window = createWindow("Synergy"); 101 forceShowCursor(); 102 LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_cx, m_cy, m_multimon ? "(multi-monitor)" : "")); 103 LOG((CLOG_DEBUG "window is 0x%08x", m_window)); 104 } catch (...) { 105 delete m_keyState; 106 delete m_screensaver; 107 destroyWindow(m_window); 108 closeHookLibrary(m_hmodHook); 109 109 delete eventQueue; 110 111 112 113 114 115 116 117 118 119 110 s_screen = NULL; 111 throw; 112 } 113 114 // install event handlers 115 EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(), 116 new TMethodEventJob<CPMScreen>(this, &CPMScreen::handleSystemEvent)); 117 118 // install the platform event queue 119 EVENTQUEUE->adoptBuffer(new CPMEventQueueBuffer); 120 120 } 121 121 122 122 CPMScreen::~CPMScreen() 123 123 { 124 125 126 127 128 129 130 131 132 133 124 assert(s_screen != NULL); 125 126 disable(); 127 EVENTQUEUE->adoptBuffer(NULL); 128 EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget()); 129 delete m_keyState; 130 delete m_screensaver; 131 destroyWindow(m_window); 132 closeHookLibrary(m_hmodHook); 133 s_screen = NULL; 134 134 } 135 135 … … 137 137 CPMScreen::enable() 138 138 { 139 140 141 139 assert(m_isOnScreen == m_isPrimary); 140 141 // install our clipboard snooper 142 142 HAB hab = CPMUtil::getHAB(); 143 143 m_nextClipboardWindow = WinQueryClipbrdViewer(hab); 144 144 WinSetClipbrdViewer(hab, m_window); 145 145 146 147 148 149 150 151 152 146 if (m_isPrimary) { 147 // set jump zones 148 m_setZone(m_x, m_y, m_cx, m_cy, getJumpZoneSize()); 149 150 // watch jump zones 151 m_setMode(kHOOK_WATCH_JUMP_ZONE); 152 } 153 153 } 154 154 … … 156 156 CPMScreen::disable() 157 157 { 158 159 160 161 162 163 164 165 166 167 168 169 170 171 158 if (m_isPrimary) { 159 // disable hooks 160 m_setMode(kHOOK_DISABLE); 161 } 162 163 // tell key state 164 m_keyState->disable(); 165 166 // stop snooping the clipboard 167 WinSetClipbrdViewer(m_window, m_nextClipboardWindow); 168 m_nextClipboardWindow = NULL; 169 170 m_isOnScreen = m_isPrimary; 171 forceShowCursor(); 172 172 } 173 173 … … 175 175 CPMScreen::enter() 176 176 { 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 177 // show the pointer (?), hide the synergy window and restore focus. 178 WinShowPointer(HWND_DESKTOP, TRUE); 179 WinSetWindowPos(m_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDE); 180 //?? WinSetFocus( 181 //?? WinEnableWindow 182 183 if (m_isPrimary) { 184 // watch jump zones 185 m_setMode(kHOOK_WATCH_JUMP_ZONE); 186 187 // all messages prior to now are invalid 188 nextMark(); 189 } 190 191 // now on screen 192 m_isOnScreen = true; 193 forceShowCursor(); 194 194 } 195 195 … … 197 197 CPMScreen::leave() 198 198 { 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 199 /// @todo save focus window. 200 201 if (m_isPrimary) { 202 // warp to center 203 warpCursor(m_xCenter, m_yCenter); 204 205 // all messages prior to now are invalid 206 nextMark(); 207 208 // remember the modifier state. this is the modifier state 209 // reflected in the internal keyboard state. 210 m_keyState->saveModifiers(); 211 212 // capture events 213 m_setMode(kHOOK_RELAY_EVENTS); 214 } 215 216 // now off screen 217 m_isOnScreen = false; 218 forceShowCursor(); 219 220 return true; 221 221 } 222 222 … … 224 224 CPMScreen::setClipboard(ClipboardID, const IClipboard* src) 225 225 { 226 227 228 229 230 226 CPMClipboard dst(m_window); 227 if (src != NULL) { 228 // save clipboard data 229 return CClipboard::copy(&dst, src); 230 } 231 231 // assert clipboard ownership 232 232 if (!dst.open(0)) { … … 242 242 { 243 243 // be careful, even if we don't have the NT bugs. 244 245 246 247 248 249 244 if (m_ownClipboard && !CPMClipboard::isOwnedBySynergy()) { 245 LOG((CLOG_DEBUG "clipboard changed: lost ownership and no notification received")); 246 m_ownClipboard = false; 247 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard); 248 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection); 249 } 250 250 } 251 251 … … 253 253 CPMScreen::openScreensaver(bool notify) 254 254 { 255 256 257 255 m_screensaverNotify = notify; 256 if (!m_screensaverNotify) 257 m_screensaver->disable(); 258 258 } 259 259 … … 261 261 CPMScreen::closeScreensaver() 262 262 { 263 264 263 if (!m_screensaverNotify) 264 m_screensaver->enable(); 265 265 } 266 266 … … 294 294 CPMScreen::setSequenceNumber(UInt32 seqNum) 295 295 { 296 296 m_sequenceNumber = seqNum; 297 297 } 298 298 … … 300 300 CPMScreen::isPrimary() const 301 301 { 302 302 return m_isPrimary; 303 303 } 304 304 … … 306 306 CPMScreen::getEventTarget() const 307 307 { 308 308 return const_cast<CPMScreen*>(this); 309 309 } 310 310 … … 312 312 CPMScreen::getClipboard(ClipboardID, IClipboard* dst) const 313 313 { 314 315 314 CPMClipboard src(m_window); 315 return CClipboard::copy(dst, &src); 316 316 } 317 317 … … 319 319 CPMScreen::getShape(SInt32& x, SInt32& y, SInt32& cx, SInt32& cy) const 320 320 { 321 322 323 324 321 x = m_x; 322 y = m_y; 323 cx= m_cx; 324 cy = m_cy; 325 325 } 326 326 … … 347 347 CPMScreen::warpCursor(SInt32 x, SInt32 y) 348 348 { 349 350 351 352 353 354 355 356 357 358 359 360 349 // warp mouse 350 warpCursorNoFlush(x, y); 351 352 // remove all input events before and including warp 353 QMSG qmsg; 354 while (WinPeekMsg(m_hab, &qmsg, NULLHANDLE, SYNERGY_PM_MSG_INPUT_FIRST, SYNERGY_PM_MSG_INPUT_LAST, PM_REMOVE)) { 355 // do nothing 356 } 357 358 // save position as last position 359 m_xCursor = x; 360 m_yCursor = y; 361 361 } 362 362 … … 364 364 CPMScreen::registerHotKey(KeyID key, KeyModifierMask mask) 365 365 { 366 367 368 369 370 371 372 373 374 375 376 366 // only allow certain modifiers 367 if ((mask & ~(KeyModifierShift | KeyModifierControl | 368 KeyModifierAlt | KeyModifierSuper)) != 0) { 369 LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask)); 370 return 0; 371 } 372 373 // fail if no keys 374 if (key == kKeyNone && mask == 0) { 375 return 0; 376 } 377 377 378 378 #if 1 … … 380 380 return 0; 381 381 #else 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 382 // convert to win32 383 UINT modifiers = 0; 384 if ((mask & KeyModifierShift) != 0) { 385 modifiers |= MOD_SHIFT; 386 } 387 if ((mask & KeyModifierControl) != 0) { 388 modifiers |= MOD_CONTROL; 389 } 390 if ((mask & KeyModifierAlt) != 0) { 391 modifiers |= MOD_ALT; 392 } 393 if ((mask & KeyModifierSuper) != 0) { 394 modifiers |= MOD_WIN; 395 } 396 UINT vk = m_keyState->mapKeyToVirtualKey(key); 397 if (key != kKeyNone && vk == 0) { 398 // can't map key 399 LOG((CLOG_WARN "could not map hotkey id=%04x mask=%04x", key, mask)); 400 return 0; 401 } 402 403 // choose hotkey id 404 UInt32 id; 405 if (!m_oldHotKeyIDs.empty()) { 406 id = m_oldHotKeyIDs.back(); 407 m_oldHotKeyIDs.pop_back(); 408 } 409 else { 410 id = m_hotKeys.size() + 1; 411 } 412 413 // if this hot key has modifiers only then we'll handle it specially 414 bool err; 415 if (key == kKeyNone) { 416 // check if already registered 417 err = (m_hotKeyToIDMap.count(CHotKeyItem(vk, modifiers)) > 0); 418 } 419 else { 420 // register with OS 421 err = (RegisterHotKey(NULL, id, modifiers, vk) == 0); 422 } 423 424 if (!err) { 425 m_hotKeys.insert(std::make_pair(id, CHotKeyItem(vk, modifiers))); 426 m_hotKeyToIDMap[CHotKeyItem(vk, modifiers)] = id; 427 } 428 else { 429 m_oldHotKeyIDs.push_back(id); 430 m_hotKeys.erase(id); 431 LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", CKeyMap::formatKey(key, mask).c_str(), key, mask)); 432 return 0; 433 } 434 435 LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", CKeyMap::formatKey(key, mask).c_str(), key, mask, id)); 436 return id; 437 437 #endif 438 438 } … … 441 441 CPMScreen::unregisterHotKey(UInt32 id) 442 442 { 443 444 445 446 447 448 449 450 443 // look up hotkey 444 HotKeyMap::iterator i = m_hotKeys.find(id); 445 if (i == m_hotKeys.end()) { 446 return; 447 } 448 449 // unregister with OS 450 bool err; 451 451 #if 1 452 452 err = true; 453 453 #else 454 455 456 457 458 454 if (i->second.getVirtualKey() != 0) { 455 err = !UnregisterHotKey(NULL, id); 456 } else { 457 err = false; 458 } 459 459 #endif 460 461 462 463 464 465 466 467 468 469 470 460 if (err) { 461 LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); 462 } 463 else { 464 LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); 465 } 466 467 // discard hot key from map and record old id for reuse 468 m_hotKeyToIDMap.erase(i->second); 469 m_hotKeys.erase(i); 470 m_oldHotKeyIDs.push_back(id); 471 471 } 472 472 … … 474 474 CPMScreen::fakeInputBegin() 475 475 { 476 477 478 479 480 481 476 assert(m_isPrimary); 477 478 if (!m_isOnScreen) { 479 m_keyState->useSavedModifiers(true); 480 } 481 //m_desks->fakeInputBegin(); 482 482 } 483 483 … … 485 485 CPMScreen::fakeInputEnd() 486 486 { 487 488 489 490 491 492 487 assert(m_isPrimary); 488 489 //m_desks->fakeInputEnd(); 490 if (!m_isOnScreen) { 491 m_keyState->useSavedModifiers(false); 492 } 493 493 } 494 494 … … 496 496 CPMScreen::getJumpZoneSize() const 497 497 { 498 498 return 1; 499 499 } 500 500 … … 502 502 CPMScreen::isAnyMouseButtonDown() const 503 503 { 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 504 static const char* buttonToName[] = { 505 "<invalid>", 506 "Left Button", 507 "Middle Button", 508 "Right Button", 509 "X Button 1", 510 "X Button 2" 511 }; 512 513 for (UInt32 i = 1; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) { 514 if (m_buttons[i]) { 515 LOG((CLOG_DEBUG "locked by \"%s\"", buttonToName[i])); 516 return true; 517 } 518 } 519 520 return false; 521 521 } 522 522 … … 524 524 CPMScreen::getCursorCenter(SInt32& x, SInt32& y) const 525 525 { 526 527 526 x = m_xCenter; 527 y = m_yCenter; 528 528 } 529 529 … … 535 535 * @param mp1 Message param 2. 536 536 */ 537 void 537 void 538 538 CPMScreen::fakeMessage(ULONG msg, MPARAM mp1, MPARAM mp2) const 539 539 { … … 633 633 void 634 634 CPMScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const 635 { 635 { 636 636 #if 0 /** @todo send scroll messages the the window beneath the cursor. */ 637 637 POINTL ptl; … … 652 652 } 653 653 } 654 #endif 654 #endif 655 655 } 656 656 … … 658 658 CPMScreen::updateKeys() 659 659 { 660 660 //m_desks->updateKeys(); 661 661 } 662 662 663 663 void 664 664 CPMScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, 665 666 { 667 668 665 KeyButton button) 666 { 667 CPlatformScreen::fakeKeyDown(id, mask, button); 668 updateForceShowCursor(); 669 669 } 670 670 671 671 void 672 672 CPMScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, 673 674 { 675 676 673 SInt32 count, KeyButton button) 674 { 675 CPlatformScreen::fakeKeyRepeat(id, mask, count, button); 676 updateForceShowCursor(); 677 677 } 678 678 … … 680 680 CPMScreen::fakeKeyUp(KeyButton button) 681 681 { 682 683 682 CPlatformScreen::fakeKeyUp(button); 683 updateForceShowCursor(); 684 684 } 685 685 … … 687 687 CPMScreen::fakeAllKeysUp() 688 688 { 689 690 689 CPlatformScreen::fakeAllKeysUp(); 690 updateForceShowCursor(); 691 691 } 692 692 … … 694 694 * Gets the path to the directory with the executable. 695 695 * Has trailing slash. 696 * 696 * 697 697 * @returns pszBuf. 698 698 * @returns NULL on buffer overflow. … … 721 721 { 722 722 // 723 // Load the hook dll as a global DLL. 723 // Load the hook dll as a global DLL. 724 724 // 725 725 // The kernel/PM will fuck up if it's loaded with a path (i.e. non global). 726 // What happend was that the DLL wasn't actually loaded into the other 727 // processes for some stupid reason, leading to nasty crashes and even 726 // What happend was that the DLL wasn't actually loaded into the other 727 // processes for some stupid reason, leading to nasty crashes and even 728 728 // weirder behaviour. 729 729 // … … 733 733 || getExecDir(szPath, sizeof(szPath)) == NULL 734 734 || chdir(szPath) != 0) { 735 736 737 } 738 735 LOG((CLOG_ERR "can't get cwd or exec dir or failed to change path to the exec dir!")); 736 throw XScreenOpenFailure(); 737 } 738 HMODULE hmod; 739 739 APIRET rc = DosLoadModule(NULL, 0, (PCSZ)name, &hmod); 740 740 chdir(szCwd); 741 742 743 744 745 746 747 if ( (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_fakeMsg",(PPFN)&m_fakeMsg )) != NO_ERROR748 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setSides",(PPFN)&m_setSides)) != NO_ERROR749 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setZone",(PPFN)&m_setZone )) != NO_ERROR750 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setMode",(PPFN)&m_setMode )) != NO_ERROR751 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_init",(PPFN)&m_init )) != NO_ERROR752 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_cleanup",(PPFN)&m_cleanup )) != NO_ERROR) {753 754 755 756 757 758 759 760 761 762 763 741 if (rc != NO_ERROR) { 742 LOG((CLOG_ERR "Failed to load hook library (%s), rc=%d ", name, rc)); 743 throw XScreenOpenFailure(); 744 } 745 746 // resolve the functions 747 if ( (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_fakeMsg", (PPFN)&m_fakeMsg )) != NO_ERROR 748 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setSides", (PPFN)&m_setSides)) != NO_ERROR 749 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setZone", (PPFN)&m_setZone )) != NO_ERROR 750 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setMode", (PPFN)&m_setMode )) != NO_ERROR 751 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_init", (PPFN)&m_init )) != NO_ERROR 752 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_cleanup", (PPFN)&m_cleanup )) != NO_ERROR) { 753 LOG((CLOG_ERR "Invalid hook library; use a newer %s.dll (rc=%d)", name, rc)); 754 DosFreeModule(hmod); 755 throw XScreenOpenFailure(); 756 } 757 758 // initialize hook library 759 if (m_init(m_hmq, _gettid(), getpid()) == 0) { 760 LOG((CLOG_ERR "Cannot initialize hook library; is synergy already running?")); 761 DosFreeModule(hmod); 762 throw XScreenOpenFailure(); 763 } 764 764 LOG((CLOG_DEBUG1 "openHookLibrary: hmod=%#lx '%s'", hmod, name)); 765 765 return hmod; 766 766 } 767 767 … … 770 770 { 771 771 LOG((CLOG_DEBUG1 "closeHookLibrary: hmod=%#lx\n", hmod)); 772 773 774 775 772 if (hmod != NULL) { 773 m_cleanup(m_hab); 774 DosFreeModule(hmod); 775 } 776 776 } 777 777 … … 779 779 CPMScreen::createWindow(const char* name) 780 780 { 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 781 WinRegisterClass(m_hab, (PCSZ)"Synergy", CPMScreen::wndProc, CS_MOVENOTIFY, sizeof(uintptr_t)); 782 HWND hwnd = WinCreateWindow(HWND_DESKTOP, 783 (PCSZ)"Synergy", 784 NULL, 785 0, //WS_?, 786 0, 0, 1, 1, 787 NULLHANDLE, 788 HWND_TOP, 789 0, 790 this, 791 NULL); 792 if (hwnd == NULLHANDLE) { 793 LOG((CLOG_ERR "failed to create window: %lx", WinGetLastError(m_hab))); 794 throw XScreenOpenFailure(); 795 } 796 return hwnd; 797 797 } 798 798 … … 800 800 CPMScreen::destroyWindow(HWND hwnd) const 801 801 { 802 803 804 802 if (hwnd != NULL) { 803 WinDestroyWindow(hwnd); 804 } 805 805 } 806 806 … … 808 808 CPMScreen::sendEvent(CEvent::Type type, void* data) 809 809 { 810 810 EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), data)); 811 811 } 812 812 … … 814 814 CPMScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id) 815 815 { 816 817 818 819 816 CClipboardInfo* info = (CClipboardInfo*)malloc(sizeof(CClipboardInfo)); 817 info->m_id = id; 818 info->m_sequenceNumber = m_sequenceNumber; 819 sendEvent(type, info); 820 820 } 821 821 … … 823 823 CPMScreen::handleSystemEvent(const CEvent& event, void*) 824 824 { 825 826 827 828 829 825 PQMSG pqmsg = (PQMSG)event.getData(); 826 assert(pqmsg != NULL); 827 if (onPreDispatch(pqmsg->hwnd, pqmsg->msg, pqmsg->mp1, pqmsg->mp2)) 828 return; 829 WinDispatchMsg(CPMUtil::getHAB(), pqmsg); 830 830 } 831 831 … … 833 833 CPMScreen::updateButtons() 834 834 { 835 836 837 838 839 840 835 m_buttons[kButtonNone] = false; 836 m_buttons[kButtonLeft] = (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) != 0; 837 m_buttons[kButtonRight] = (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) != 0; 838 m_buttons[kButtonMiddle] = (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000) != 0; 839 m_buttons[kButtonExtra0 + 0] = false; 840 m_buttons[kButtonExtra0 + 1] = false; 841 841 } 842 842 … … 844 844 CPMScreen::getKeyState() const 845 845 { 846 846 return m_keyState; 847 847 } 848 848 … … 850 850 CPMScreen::onPreDispatch(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) 851 851 { 852 853 854 855 856 857 858 859 860 861 862 863 852 // handle event 853 switch (msg) { 854 case SYNERGY_PM_MSG_DEBUG: 855 LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", mp1, mp2)); 856 return true; 857 } 858 859 if (m_isPrimary) { 860 return onPreDispatchPrimary(hwnd, msg, mp1, mp2); 861 } 862 863 return false; 864 864 } 865 865 … … 867 867 CPMScreen::onPreDispatchPrimary(HWND, ULONG msg, MPARAM mp1, MPARAM mp2) 868 868 { 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 869 // handle event 870 switch (msg) { 871 case SYNERGY_PM_MSG_MARK: 872 return onMark((uintptr_t)mp1); 873 874 case SYNERGY_PM_MSG_KEY: 875 return onKey(SHORT1FROMMP(mp1), CHAR3FROMMP(mp1), CHAR4FROMMP(mp1), SHORT1FROMMP(mp2), SHORT2FROMMP(mp2)); 876 877 case SYNERGY_PM_MSG_MOUSE_BUTTON: 878 return onMouseButton(SHORT1FROMMP(mp1), (SHORT)SHORT1FROMMP(mp2), m_cy - (SHORT)SHORT2FROMMP(mp2)); 879 880 case SYNERGY_PM_MSG_MOUSE_MOVE: 881 return onMouseMove(SHORT1FROMMP(mp1), (SHORT)SHORT1FROMMP(mp2), m_cy - (SHORT)SHORT2FROMMP(mp2)); 882 883 case SYNERGY_PM_MSG_PRE_WARP: 884 { 885 // Save position to compute delta of next motion 886 m_xCursor = (SInt32)mp1; 887 m_yCursor = (SInt32)mp2; 888 889 // We warped the mouse. Discard events until we find the 890 // matching post warp event. See warpCursorNoFlush() for 891 // where the events are sent. We discard the matching 892 // post warp event and can be sure we've skipped the warp 893 // event. 894 QMSG qmsg; 895 while ( WinGetMsg(m_hab, &qmsg, NULLHANDLE, SYNERGY_PM_MSG_MOUSE_MOVE, SYNERGY_PM_MSG_POST_WARP) 896 && qmsg.msg != SYNERGY_PM_MSG_POST_WARP) 897 /* nothing */; 898 } 899 return true; 900 901 case SYNERGY_PM_MSG_POST_WARP: 902 LOG((CLOG_WARN "unmatched post warp")); 903 return true; 904 } 905 906 return false; 907 907 } 908 908 … … 910 910 CPMScreen::onEvent(HWND, ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT *result) 911 911 { 912 913 914 915 916 //WinSendMessage(m_nextClipboardWindow, msg, mp1, mp2);917 918 919 920 921 922 923 912 switch (msg) { 913 case WM_DRAWCLIPBOARD: 914 //// first pass on the message 915 //if (m_nextClipboardWindow != NULL) { 916 // WinSendMessage(m_nextClipboardWindow, msg, mp1, mp2); 917 //} 918 919 // now handle the message 920 return onClipboardChange(); 921 } 922 923 return false; 924 924 } 925 925 … … 927 927 CPMScreen::onMark(UInt32 mark) 928 928 { 929 930 929 m_markReceived = mark; 930 return true; 931 931 } 932 932 … … 935 935 { 936 936 #if 0 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 937 static const KeyModifierMask s_ctrlAlt = KeyModifierControl | KeyModifierAlt; 938 939 LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, mp2=0x%08x", (mp1 & 0xff00u) >> 8, mp1 & 0xffu, (mp1 & 0x10000u) ? 1 : 0, mp2)); 940 941 // get event info 942 KeyButton button = (KeyButton)((mp2 & 0x01ff0000) >> 16); 943 bool down = ((mp2 & 0x80000000u) == 0x00000000u); 944 bool wasDown = isKeyDown(button); 945 KeyModifierMask oldState = pollActiveModifiers(); 946 947 // check for autorepeat 948 if (m_keyState->testAutoRepeat(down, (mp2 & 0x40000000u) == 1, button)) { 949 mp2 |= 0x40000000u; 950 } 951 952 // if the button is zero then guess what the button should be. 953 // these are badly synthesized key events and logitech software 954 // that maps mouse buttons to keys is known to do this. 955 // alternatively, we could just throw these events out. 956 if (button == 0) { 957 button = m_keyState->virtualKeyToButton(mp1 & 0xffu); 958 if (button == 0) { 959 return true; 960 } 961 wasDown = isKeyDown(button); 962 } 963 964 // record keyboard state 965 m_keyState->onKey(button, down, oldState); 966 967 // windows doesn't tell us the modifier key state on mouse or key 968 // events so we have to figure it out. most apps would use 969 // GetKeyState() or even GetAsyncKeyState() for that but we can't 970 // because our hook doesn't pass on key events for several modifiers. 971 // it can't otherwise the system would interpret them normally on 972 // the primary screen even when on a secondary screen. so tapping 973 // alt would activate menus and tapping the windows key would open 974 // the start menu. if you don't pass those events on in the hook 975 // then GetKeyState() understandably doesn't reflect the effect of 976 // the event. curiously, neither does GetAsyncKeyState(), which is 977 // surprising. 978 // 979 // so anyway, we have to track the modifier state ourselves for 980 // at least those modifiers we don't pass on. pollActiveModifiers() 981 // does that but we have to update the keyboard state before calling 982 // pollActiveModifiers() to get the right answer. but the only way 983 // to set the modifier state or to set the up/down state of a key 984 // is via onKey(). so we have to call onKey() twice. 985 KeyModifierMask state = pollActiveModifiers(); 986 m_keyState->onKey(button, down, state); 987 988 // check for hot keys 989 if (oldState != state) { 990 // modifier key was pressed/released 991 if (onHotKey(0, mp2)) { 992 return true; 993 } 994 } 995 else { 996 // non-modifier was pressed/released 997 if (onHotKey(mp1, mp2)) { 998 return true; 999 } 1000 } 1001 1002 // ignore message if posted prior to last mark change 1003 if (!ignore()) { 1004 // check for ctrl+alt+del. we do not want to pass that to the 1005 // client. the user can use ctrl+alt+pause to emulate it. 1006 UINT virtKey = (mp1 & 0xffu); 1007 if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) { 1008 LOG((CLOG_DEBUG "discard ctrl+alt+del")); 1009 return true; 1010 } 1011 1012 // check for ctrl+alt+del emulation 1013 if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) && 1014 (state & s_ctrlAlt) == s_ctrlAlt) { 1015 LOG((CLOG_DEBUG "emulate ctrl+alt+del")); 1016 // switch mp1 and mp2 to be as if VK_DELETE was 1017 // pressed or released. when mapping the key we require that 1018 // we not use AltGr (the 0x10000 flag in mp1) and we not 1019 // use the keypad delete key (the 0x01000000 flag in mp2). 1020 mp1 = VK_DELETE | 0x00010000u; 1021 mp2 &= 0xfe000000; 1022 mp2 |= m_keyState->virtualKeyToButton(mp1 & 0xffu) << 16; 1023 mp2 |= 0x01000001; 1024 } 1025 1026 // process key 1027 KeyModifierMask mask; 1028 KeyID key = m_keyState->mapKeyFromEvent((ULONG)mp1, (ULONG)mp2, &mask); 1029 button = static_cast<KeyButton>((mp2 & 0x01ff0000u) >> 16); 1030 if (key != kKeyNone) { 1031 // fix key up. if the key isn't down according to 1032 // our table then we never got the key press event 1033 // for it. if it's not a modifier key then we'll 1034 // synthesize the press first. only do this on 1035 // the windows 95 family, which eats certain special 1036 // keys like alt+tab, ctrl+esc, etc. 1037 if (m_is95Family && !wasDown && !down) { 1038 switch (virtKey) { 1039 case VK_SHIFT: 1040 case VK_LSHIFT: 1041 case VK_RSHIFT: 1042 case VK_CONTROL: 1043 case VK_LCONTROL: 1044 case VK_RCONTROL: 1045 case VK_MENU: 1046 case VK_LMENU: 1047 case VK_RMENU: 1048 case VK_LWIN: 1049 case VK_RWIN: 1050 case VK_CAPITAL: 1051 case VK_NUMLOCK: 1052 case VK_SCROLL: 1053 break; 1054 1055 default: 1056 m_keyState->sendKeyEvent(getEventTarget(), 1057 true, false, key, mask, 1, button); 1058 break; 1059 } 1060 } 1061 1062 // do it 1063 m_keyState->sendKeyEvent(getEventTarget(), 1064 ((mp2 & 0x80000000u) == 0), 1065 ((mp2 & 0x40000000u) != 0), 1066 key, mask, (SInt32)(mp2 & 0xffff), button); 1067 } 1068 else { 1069 LOG((CLOG_DEBUG1 "cannot map key")); 1070 } 1071 } 1072 1072 #endif 1073 1073 return true; 1074 1074 } 1075 1075 … … 1078 1078 { 1079 1079 #if 0 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1080 // get the key info 1081 KeyModifierMask state = getActiveModifiers(); 1082 UINT virtKey = (mp1 & 0xffu); 1083 UINT modifiers = 0; 1084 if ((state & KeyModifierShift) != 0) { 1085 modifiers |= MOD_SHIFT; 1086 } 1087 if ((state & KeyModifierControl) != 0) { 1088 modifiers |= MOD_CONTROL; 1089 } 1090 if ((state & KeyModifierAlt) != 0) { 1091 modifiers |= MOD_ALT; 1092 } 1093 if ((state & KeyModifierSuper) != 0) { 1094 modifiers |= MOD_WIN; 1095 } 1096 1097 // find the hot key id 1098 HotKeyToIDMap::const_iterator i = 1099 m_hotKeyToIDMap.find(CHotKeyItem(virtKey, modifiers)); 1100 if (i == m_hotKeyToIDMap.end()) { 1101 return false; 1102 } 1103 1104 // find what kind of event 1105 CEvent::Type type; 1106 if ((mp2 & 0x80000000u) == 0u) { 1107 if ((mp2 & 0x40000000u) != 0u) { 1108 // ignore key repeats but it counts as a hot key 1109 return true; 1110 } 1111 type = getHotKeyDownEvent(); 1112 } 1113 else { 1114 type = getHotKeyUpEvent(); 1115 } 1116 1117 // generate event 1118 EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), 1119 CHotKeyInfo::alloc(i->second))); 1120 1120 1121 1121 #endif 1122 1122 return true; 1123 1123 } 1124 1124 … … 1126 1126 CPMScreen::onMouseButton(ULONG msg, SInt32 ax, SInt32 ay) 1127 1127 { 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1128 // get which button 1129 bool pressed = mapPressFromEvent(msg); 1130 ButtonID button = mapButtonFromEvent(msg); 1131 1132 // keep our shadow key state up to date 1133 if (button >= kButtonLeft && button <= kButtonExtra0 + 1) { 1134 if (pressed) { 1135 m_buttons[button] = true; 1136 } 1137 else { 1138 m_buttons[button] = false; 1139 } 1140 } 1141 1142 // ignore message if posted prior to last mark change 1143 if (!ignore()) { 1144 KeyModifierMask mask = m_keyState->getActiveModifiers(); 1145 if (pressed) { 1146 LOG((CLOG_DEBUG1 "event: button press button=%d", button)); 1147 if (button != kButtonNone) { 1148 sendEvent(getButtonDownEvent(), 1149 CButtonInfo::alloc(button, mask)); 1150 } 1151 } 1152 else { 1153 LOG((CLOG_DEBUG1 "event: button release button=%d", button)); 1154 if (button != kButtonNone) { 1155 sendEvent(getButtonUpEvent(), 1156 CButtonInfo::alloc(button, mask)); 1157 } 1158 } 1159 } 1160 1161 return true; 1162 1162 } 1163 1163 … … 1165 1165 CPMScreen::onMouseMove(ULONG msg, SInt32 ax, SInt32 ay) 1166 1166 { 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1167 // compute motion delta (relative to the last known 1168 // mouse position) 1169 SInt32 x = ax - m_xCursor; 1170 SInt32 y = ay - m_yCursor; 1171 1172 // ignore if the mouse didn't move or if message posted prior 1173 // to last mark change. 1174 if (ignore() || (x == 0 && y == 0)) { 1175 return true; 1176 } 1177 1178 // save position to compute delta of next motion 1179 m_xCursor = ax; 1180 m_yCursor = ay; 1181 1182 if (m_isOnScreen) { 1183 // motion on primary screen 1184 sendEvent(getMotionOnPrimaryEvent(), CMotionInfo::alloc(m_xCursor, m_yCursor)); 1185 } 1186 else { 1187 // motion on secondary screen. warp mouse back to 1188 // center. 1189 warpCursorNoFlush(m_xCenter, m_yCenter); 1190 1191 // examine the motion. if it's about the distance 1192 // from the center of the screen to an edge then 1193 // it's probably a bogus motion that we want to 1194 // ignore (see warpCursorNoFlush() for a further 1195 // description). 1196 static SInt32 bogusZoneSize = 10; 1197 if (-x + bogusZoneSize > m_xCenter - m_x || 1198 x + bogusZoneSize > m_x + m_cx - m_xCenter || 1199 -y + bogusZoneSize > m_yCenter - m_y || 1200 y + bogusZoneSize > m_y + m_cy - m_yCenter) { 1201 LOG((CLOG_DEBUG "dropped bogus motion %+d,%+d", x, y)); 1202 } 1203 else { 1204 // send motion 1205 sendEvent(getMotionOnSecondaryEvent(), CMotionInfo::alloc(x, y)); 1206 } 1207 } 1208 1209 return true; 1210 1210 } 1211 1211 … … 1213 1213 CPMScreen::onClipboardChange() 1214 1214 { 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1215 // now notify client that somebody changed the clipboard (unless 1216 // we're the owner). 1217 if (!CPMClipboard::isOwnedBySynergy()) { 1218 if (m_ownClipboard) { 1219 LOG((CLOG_DEBUG "clipboard changed: lost ownership")); 1220 m_ownClipboard = false; 1221 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard); 1222 sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection); 1223 } 1224 } 1225 else if (!m_ownClipboard) { 1226 LOG((CLOG_DEBUG "clipboard changed: synergy owned")); 1227 m_ownClipboard = true; 1228 } 1229 1230 return true; 1231 1231 } 1232 1232 … … 1234 1234 CPMScreen::warpCursorNoFlush(SInt32 x, SInt32 y) 1235 1235 { 1236 1236 // send an event that we can recognize before the mouse warp 1237 1237 WinPostQueueMsg(m_hmq, SYNERGY_PM_MSG_PRE_WARP, (MPARAM)x, (MPARAM)y); 1238 1238 1239 1240 1239 // warp mouse. hopefully this inserts a mouse motion event 1240 // between the previous message and the following message. 1241 1241 WinSetPointerPos(HWND_DESKTOP, x, y); 1242 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1243 // yield the CPU. there's a race condition when warping: 1244 // a hardware mouse event occurs 1245 // the mouse hook is not called because that process doesn't have the CPU 1246 // we send PRE_WARP, SetCursorPos(), send POST_WARP 1247 // we process all of those events and update m_x, m_y 1248 // we finish our time slice 1249 // the hook is called 1250 // the hook sends us a mouse event from the pre-warp position 1251 // we get the CPU 1252 // we compute a bogus warp 1253 // we need the hook to process all mouse events that occur 1254 // before we warp before we do the warp but i'm not sure how 1255 // to guarantee that. yielding the CPU here may reduce the 1256 // chance of undesired behavior. we'll also check for very 1257 // large motions that look suspiciously like about half width 1258 // or height of the screen. 1259 ARCH->sleep(0.0); 1260 1261 // send an event that we can recognize after the mouse warp 1262 1262 WinPostQueueMsg(m_hmq, SYNERGY_PM_MSG_POST_WARP, 0, 0); 1263 1263 } … … 1266 1266 CPMScreen::nextMark() 1267 1267 { 1268 1269 1270 1271 1268 // next mark 1269 ++m_mark; 1270 1271 // mark point in message queue where the mark was changed 1272 1272 WinPostQueueMsg(m_hmq, SYNERGY_PM_MSG_MARK, (MPARAM)m_mark, 0); 1273 1273 } … … 1276 1276 CPMScreen::ignore() const 1277 1277 { 1278 1278 return (m_mark != m_markReceived); 1279 1279 } 1280 1280 … … 1282 1282 CPMScreen::updateScreenShape() 1283 1283 { 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1284 // get shape 1285 m_x = 0; 1286 m_y = 0; 1287 m_cx = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); 1288 m_cy = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); 1289 1290 // get center for cursor 1291 m_xCenter = m_cx / 2; 1292 m_yCenter = m_cy / 2; 1293 1294 // check for multiple monitors 1295 m_multimon = false; 1296 1296 } 1297 1297 … … 1301 1301 /** @todo query which is left and which is right. */ 1302 1302 1303 1303 switch (msg) { 1304 1304 case WM_BUTTON1DOWN: 1305 1305 case WM_BUTTON1UP: 1306 1306 case WM_BUTTON1DBLCLK: 1307 1307 case WM_BUTTON1CLICK: //?? 1308 1308 return kButtonLeft; 1309 1309 1310 1310 case WM_BUTTON2DOWN: … … 1319 1319 case WM_BUTTON3CLICK: //?? 1320 1320 return kButtonMiddle; 1321 1322 1323 1321 default: 1322 return kButtonNone; 1323 } 1324 1324 } 1325 1325 … … 1327 1327 CPMScreen::mapPressFromEvent(ULONG msg) const 1328 1328 { 1329 1329 switch (msg) { 1330 1330 case WM_BUTTON1DOWN: 1331 1331 case WM_BUTTON1CLICK: //?? … … 1344 1344 default: 1345 1345 return false; 1346 1346 } 1347 1347 } 1348 1348 … … 1350 1350 CPMScreen::updateKeysCB(void*) 1351 1351 { 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1352 // record which keys we think are down 1353 bool down[IKeyState::kNumButtons]; 1354 bool sendFixes = (isPrimary() && !m_isOnScreen); 1355 if (sendFixes) { 1356 for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { 1357 down[i] = m_keyState->isKeyDown(i); 1358 } 1359 } 1360 1361 // now update the keyboard state 1362 CPlatformScreen::updateKeyState(); 1363 1364 // now see which keys we thought were down but now think are up. 1365 // send key releases for these keys to the active client. 1366 if (sendFixes) { 1367 KeyModifierMask mask = pollActiveModifiers(); 1368 for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { 1369 if (down[i] && !m_keyState->isKeyDown(i)) { 1370 m_keyState->sendKeyEvent(getEventTarget(), 1371 false, false, kKeyNone, mask, 1, i); 1372 } 1373 } 1374 } 1375 1375 } 1376 1376 … … 1378 1378 CPMScreen::forceShowCursor() 1379 1379 { 1380 1381 1382 1383 1384 1385 1386 1387 1380 // check for mouse - probably not required. 1381 m_hasMouse = WinQuerySysValue(HWND_DESKTOP, SV_MOUSEPRESENT) != FALSE; 1382 1383 // decide if we should show the mouse 1384 bool showMouse = (!m_hasMouse && !m_isPrimary && m_isOnScreen); 1385 1386 // show/hide the mouse 1387 if (showMouse != m_showingMouse) { 1388 1388 WinShowPointer(HWND_DESKTOP, showMouse); 1389 1389 m_showingMouse = WinQuerySysValue(HWND_DESKTOP, SV_POINTERLEVEL) != 0; 1390 1390 } 1391 1391 } 1392 1392 … … 1400 1400 CPMScreen::wndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) 1401 1401 { 1402 1403 1404 1405 1406 1407 1408 1409 1402 assert(s_screen != NULL); 1403 1404 MRESULT mr = 0; 1405 if (!s_screen->onEvent(hwnd, msg, mp1, mp2, &mr)) { 1406 mr = WinDefWindowProc(hwnd, msg, mp1, mp2); 1407 } 1408 1409 return mr; 1410 1410 } 1411 1411 … … 1416 1416 1417 1417 CPMScreen::CHotKeyItem::CHotKeyItem(ULONG keycode, ULONG mask) : 1418 1419 1420 { 1421 1418 m_keycode(keycode), 1419 m_mask(mask) 1420 { 1421 // do nothing 1422 1422 } 1423 1423 … … 1425 1425 CPMScreen::CHotKeyItem::getVirtualKey() const 1426 1426 { 1427 1427 return m_keycode; 1428 1428 } 1429 1429 … … 1431 1431 CPMScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const 1432 1432 { 1433 1434 1433 return (m_keycode < x.m_keycode || 1434 (m_keycode == x.m_keycode && m_mask < x.m_mask)); 1435 1435 } 1436 1436 … … 1442 1442 * c-basic-offset: 4 1443 1443 * tab-width: 4 1444 * indent-tabs-mode: t1444 * indent-tabs-mode: s 1445 1445 * End: 1446 1446 */
Note:
See TracChangeset
for help on using the changeset viewer.