- Timestamp:
- Jul 31, 2006, 5:21:38 AM (19 years ago)
- Location:
- trunk/synergy
- Files:
-
- 2 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/synergy/Makefile.kmk
r2753 r2755 163 163 lib/platform/CPMEventQueueBuffer.cpp \ 164 164 lib/platform/CPMScreenSaver.cpp \ 165 lib/platform/CPMScreen.cpp \ 166 lib/platform/CPMKeyState.cpp \ 165 167 lib/platform/CPMUtil.cpp 166 168 # todo: 167 # lib/platform/CPMKeyState.cpp \168 # lib/platform/CPMScreen.cpp169 169 platform_SOURCES.nt = \ 170 170 lib/platform/CMSWindowsClipboard.cpp \ … … 235 235 236 236 237 # 238 # The hook DLLs. 239 # 240 DLLS = synrgyhk 241 242 synrgyhk_DEFS = SYNRGYHK_EXPORTS 243 synrgyhk_ASTOOL.os2 = NASM 244 synrgyhk_ASFLAGS.os2 = -f obj 245 synrgyhk_SOURCES.nt = \ 246 lib/platform/CSynergyHook.cpp 247 synrgyhk_SOURCES.os2 = \ 248 lib/platform/CPMSynergyHook.cpp \ 249 lib/platform/CPMSynergyHookData.asm \ 250 lib/platform/CPMSynergyHook.def 251 237 252 include $(PATH_KBUILD)/footer.kmk -
trunk/synergy/lib/platform/CPMEventQueueBuffer.cpp
r2752 r2755 3 3 * Copyright (C) 2004 Chris Schoeneman 4 4 * Copyright (C) 2006 Knut St. Osmundsen 5 * 5 * 6 6 * This package is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU General Public License 8 8 * found in the file COPYING that should have accompanied this file. 9 * 9 * 10 10 * This package is distributed in the hope that it will be useful, 11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 59 59 CPMEventQueueBuffer::waitForEvent(double timeout) 60 60 { 61 // check if messages are available first. 61 // check if messages are available first. 62 62 ULONG fStatus = WinQueryQueueStatus(HWND_DESKTOP); 63 63 if (!fStatus) { 64 64 // convert timeout and wait. 65 ULONG ulPMTimeout = timeout < 0.0 65 ULONG ulPMTimeout = timeout < 0.0 66 66 ? SEM_INDEFINITE_WAIT 67 67 : (ULONG)(1000.0 * timeout); … … 85 85 return kSystem; 86 86 } 87 87 88 88 if (m_event.msg == m_userEvent) { 89 89 dataID = (UInt32)(uintptr_t)m_event.mp1; 90 90 return kUser; 91 91 } 92 92 93 93 event = CEvent(CEvent::kSystem, IEventQueue::getSystemTarget(), &m_event); 94 94 return kSystem; … … 105 105 { 106 106 ULONG fStatus = WinQueryQueueStatus(HWND_DESKTOP); 107 return fStatus != 0; 107 return fStatus != 0; 108 108 } 109 109 … … 120 120 } 121 121 122 /* 123 * Local Variables: 124 * mode: c 125 * c-file-style: "k&r" 126 * c-basic-offset: 4 127 * tab-width: 4 128 * indent-tabs-mode: t 129 * End: 130 */ 131 -
trunk/synergy/lib/platform/CPMKeyState.cpp
r2752 r2755 3 3 * Copyright (C) 2003 Chris Schoeneman 4 4 * Copyright (C) 2006 Knut St. Osmundsen 5 * 5 * 6 6 * This package is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU General Public License 8 8 * found in the file COPYING that should have accompanied this file. 9 * 9 * 10 10 * This package is distributed in the hope that it will be useful, 11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 30 30 { 31 31 /* 0x000 */ kKeyNone, // reserved 32 /* 0x001 */ kKeyNone, // VK_BUTTON1 VK_BUTTON1 0x000133 /* 0x002 */ kKeyNone, // VK_BUTTON2 VK_BUTTON2 0x000234 /* 0x003 */ kKeyNone, // VK_BUTTON3 VK_BUTTON3 0x000335 /* 0x004 */ kKeyBreak, // VK_BREAK VK_BREAK 0x000432 /* 0x001 */ kKeyNone, // VK_BUTTON1 33 /* 0x002 */ kKeyNone, // VK_BUTTON2 34 /* 0x003 */ kKeyNone, // VK_BUTTON3 35 /* 0x004 */ kKeyBreak, // VK_BREAK 36 36 /* 0x005 */ kKeyBackSpace, // VK_BACKSPACE 37 37 /* 0x006 */ kKeyTab, // VK_TAB … … 39 39 /* 0x008 */ kKeyReturn, // VK_NEWLINE 40 40 /* 0x009 */ kKeyShift_L, // VK_SHIFT 41 /* 0x00a */ kKeyControl_L, // VK_CTRL 0x000a42 /* 0x00b */ kKeyAlt_L, // VK_ALT 0x000b43 /* 0x00c */ kKeyAltGr, // VK_ALTGRAF 0x000c44 /* 0x00d */ kKeyPause, // VK_PAUSE 0x000d45 /* 0x00e */ kKeyCapsLock, // VK_CAPSLOCK 0x000e46 /* 0x00f */ kKeyEscape, // VK_ESC 0x000f47 /* 0x010 */ kKeyNone, // VK_SPACE 0x001048 /* 0x011 */ kKeyPageUp, // VK_PAGEUP 0x001149 /* 0x012 */ kKeyPageDown, // VK_PAGEDOWN 0x001250 /* 0x013 */ kKeyEnd, // VK_END 0x001351 /* 0x014 */ kKeyHome, // VK_HOME 0x001452 /* 0x015 */ kKeyLeft, // VK_LEFT 0x001553 /* 0x016 */ kKeyUp, // VK_UP 0x001654 /* 0x017 */ kKeyRight, // VK_RIGHT 0x001755 /* 0x018 */ kKeyDown, // VK_DOWN 0x001856 /* 0x019 */ kKeyNone, // VK_PRINTSCRN 0x001957 /* 0x01a */ kKeyInsert, // VK_INSERT 0x001a58 /* 0x01b */ kKeyDelete, // VK_DELETE 0x001b59 /* 0x01c */ kKeyScrollLock, // VK_SCRLLOCK 0x001c60 /* 0x01d */ kKeyNumLock, // VK_NUMLOCK 0x001d61 /* 0x01e */ kKeyKP_Enter, // VK_ENTER 0x001e62 /* 0x01f */ kKeySysReq, // VK_SYSRQ 0x001f63 /* 0x020 */ kKeyF1, // VK_F1 0x002064 /* 0x021 */ kKeyF2, // VK_F2 0x002165 /* 0x022 */ kKeyF3, // VK_F3 0x002266 /* 0x023 */ kKeyF4, // VK_F4 0x002367 /* 0x024 */ kKeyF5, // VK_F5 0x002468 /* 0x025 */ kKeyF6, // VK_F6 0x002569 /* 0x026 */ kKeyF7, // VK_F7 0x002670 /* 0x027 */ kKeyF8, // VK_F8 0x002771 /* 0x028 */ kKeyF9, // VK_F9 0x002872 /* 0x029 */ kKeyF10, // VK_F10 0x002973 /* 0x02a */ kKeyF11, // VK_F11 0x002a74 /* 0x02b */ kKeyF12, // VK_F12 0x002b75 /* 0x02c */ kKeyF13, // VK_F13 0x002c76 /* 0x02d */ kKeyF14, // VK_F14 0x002d77 /* 0x02e */ kKeyF15, // VK_F15 0x002e78 /* 0x02f */ kKeyF16, // VK_F16 0x002f79 /* 0x030 */ kKeyF17, // VK_F17 0x003080 /* 0x031 */ kKeyF18, // VK_F18 0x003181 /* 0x032 */ kKeyF19, // VK_F19 0x003282 /* 0x033 */ kKeyF20, // VK_F20 0x003383 /* 0x034 */ kKeyF21, // VK_F21 0x003484 /* 0x035 */ kKeyF22, // VK_F22 0x003585 /* 0x036 */ kKeyF23, // VK_F23 0x003686 /* 0x037 */ kKeyF24, // VK_F24 0x003787 /* 0x038 */ kKeyNone, // VK_ENDDRAG 0x003888 /* 0x039 */ kKeyClear, // VK_CLEAR 0x003989 /* 0x03a */ kKeyNone, // VK_EREOF 0x003a90 /* 0x03b */ kKeyNone, // VK_PA1 0x003b91 /* 0x03c */ kKeyNone, // VK_ATTN 0x003c92 /* 0x03d */ kKeyNone, // VK_CRSEL 0x003d93 /* 0x03e */ kKeyNone, // VK_EXSEL 0x003e94 /* 0x03f */ kKeyNone, // VK_COPY 0x003f95 /* 0x040 */ kKeyNone, // VK_BLK1 0x004096 /* 0x041 */ kKeyNone // VK_BLK2 0x004141 /* 0x00a */ kKeyControl_L, // VK_CTRL 42 /* 0x00b */ kKeyAlt_L, // VK_ALT 43 /* 0x00c */ kKeyAltGr, // VK_ALTGRAF 44 /* 0x00d */ kKeyPause, // VK_PAUSE 45 /* 0x00e */ kKeyCapsLock, // VK_CAPSLOCK 46 /* 0x00f */ kKeyEscape, // VK_ESC 47 /* 0x010 */ kKeyNone, // VK_SPACE 48 /* 0x011 */ kKeyPageUp, // VK_PAGEUP 49 /* 0x012 */ kKeyPageDown, // VK_PAGEDOWN 50 /* 0x013 */ kKeyEnd, // VK_END 51 /* 0x014 */ kKeyHome, // VK_HOME 52 /* 0x015 */ kKeyLeft, // VK_LEFT 53 /* 0x016 */ kKeyUp, // VK_UP 54 /* 0x017 */ kKeyRight, // VK_RIGHT 55 /* 0x018 */ kKeyDown, // VK_DOWN 56 /* 0x019 */ kKeyNone, // VK_PRINTSCRN 57 /* 0x01a */ kKeyInsert, // VK_INSERT 58 /* 0x01b */ kKeyDelete, // VK_DELETE 59 /* 0x01c */ kKeyScrollLock, // VK_SCRLLOCK 60 /* 0x01d */ kKeyNumLock, // VK_NUMLOCK 61 /* 0x01e */ kKeyKP_Enter, // VK_ENTER 62 /* 0x01f */ kKeySysReq, // VK_SYSRQ 63 /* 0x020 */ kKeyF1, // VK_F1 64 /* 0x021 */ kKeyF2, // VK_F2 65 /* 0x022 */ kKeyF3, // VK_F3 66 /* 0x023 */ kKeyF4, // VK_F4 67 /* 0x024 */ kKeyF5, // VK_F5 68 /* 0x025 */ kKeyF6, // VK_F6 69 /* 0x026 */ kKeyF7, // VK_F7 70 /* 0x027 */ kKeyF8, // VK_F8 71 /* 0x028 */ kKeyF9, // VK_F9 72 /* 0x029 */ kKeyF10, // VK_F10 73 /* 0x02a */ kKeyF11, // VK_F11 74 /* 0x02b */ kKeyF12, // VK_F12 75 /* 0x02c */ kKeyF13, // VK_F13 76 /* 0x02d */ kKeyF14, // VK_F14 77 /* 0x02e */ kKeyF15, // VK_F15 78 /* 0x02f */ kKeyF16, // VK_F16 79 /* 0x030 */ kKeyF17, // VK_F17 80 /* 0x031 */ kKeyF18, // VK_F18 81 /* 0x032 */ kKeyF19, // VK_F19 82 /* 0x033 */ kKeyF20, // VK_F20 83 /* 0x034 */ kKeyF21, // VK_F21 84 /* 0x035 */ kKeyF22, // VK_F22 85 /* 0x036 */ kKeyF23, // VK_F23 86 /* 0x037 */ kKeyF24, // VK_F24 87 /* 0x038 */ kKeyNone, // VK_ENDDRAG 88 /* 0x039 */ kKeyClear, // VK_CLEAR 89 /* 0x03a */ kKeyNone, // VK_EREOF 90 /* 0x03b */ kKeyNone, // VK_PA1 91 /* 0x03c */ kKeyNone, // VK_ATTN 92 /* 0x03d */ kKeyNone, // VK_CRSEL 93 /* 0x03e */ kKeyNone, // VK_EXSEL 94 /* 0x03f */ kKeyNone, // VK_COPY 95 /* 0x040 */ kKeyNone, // VK_BLK1 96 /* 0x041 */ kKeyNone // VK_BLK2 97 97 }; 98 98 … … 114 114 m_eventTarget(eventTarget), 115 115 m_fixTimer(NULL), 116 m_lastDown( 0),116 m_lastDown(kKeyNone), 117 117 m_useSavedModifiers(false), 118 118 m_savedModifiers(0), … … 135 135 m_fixTimer = NULL; 136 136 } 137 m_lastDown = 0;137 m_lastDown = kKeyNone; 138 138 } 139 139 … … 147 147 CPMKeyState::testAutoRepeat(bool press, bool isRepeat, KeyButton button) 148 148 { 149 if (!isRepeat) { 150 isRepeat = (press && m_lastDown != 0 && button == m_lastDown); 151 } 152 if (press) { 153 m_lastDown = button; 154 } 155 else { 156 m_lastDown = 0; 157 } 149 if (!isRepeat) 150 isRepeat = press && button == m_lastDown && button != kKeyNone; 151 m_lastDown = press ? button : kKeyNone; 158 152 return isRepeat; 159 153 } … … 174 168 // transfer any modifier state changes to CKeyState's state 175 169 KeyModifierMask mask = m_originalSavedModifiers ^ m_savedModifiers; 176 getActiveModifiersRValue() = 177 (getActiveModifiers() & ~mask) | (m_savedModifiers & mask); 170 getActiveModifiersRValue() = (getActiveModifiers() & ~mask) | (m_savedModifiers & mask); 178 171 } 179 172 } … … 181 174 182 175 KeyID 183 CPMKeyState::mapKeyFromEvent(MPARAM charAndVirtKey, MPARAM info, KeyModifierMask* maskOut) const 184 { 176 CPMKeyState::mapKeyFromEvent(USHORT fsFlags, UCHAR ucRepeat, UCHAR ucScanCode, USHORT usch, USHORT usvk, KeyModifierMask* maskOut) const 177 { 178 #if 0 /** @todo */ 185 179 static const KeyModifierMask s_controlAlt = KeyModifierControl | KeyModifierAlt; 186 180 … … 228 222 *maskOut = active; 229 223 } 230 231 224 return id; 232 } 233 234 bool 235 CPMKeyState::didGroupsChange() const 236 { 237 GroupList groups; 238 return (getGroups(groups) && groups != m_groups); 239 } 240 241 UINT 225 #else 226 return kKeyNone; 227 #endif 228 } 229 230 ULONG 242 231 CPMKeyState::mapKeyToVirtualKey(KeyID key) const 243 232 { 244 if (key == kKeyNone) {233 if (key == kKeyNone) 245 234 return 0; 246 }247 235 KeyToVKMap::const_iterator i = m_keyToVKMap.find(key); 248 if (i == m_keyToVKMap.end()) {236 if (i == m_keyToVKMap.end()) 249 237 return 0; 250 } 251 else { 252 return i->second; 253 } 238 return i->second; 254 239 } 255 240 … … 272 257 // send key 273 258 if (press && !isAutoRepeat) { 274 CKeyState::sendKeyEvent(target, true, false, 275 key, mask, 1, button); 259 CKeyState::sendKeyEvent(target, true, false, key, mask, 1, button); 276 260 if (count > 0) { 277 261 --count; … … 279 263 } 280 264 if (count >= 1) { 281 CKeyState::sendKeyEvent(target, true, true, 282 key, mask, count, button); 265 CKeyState::sendKeyEvent(target, true, true, key, mask, count, button); 283 266 } 284 267 } … … 290 273 291 274 void 292 CPMKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, 293 KeyButton button) 275 CPMKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button) 294 276 { 295 277 CKeyState::fakeKeyDown(id, mask, button); … … 297 279 298 280 void 299 CPMKeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask, 300 SInt32 count, KeyButton button) 281 CPMKeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) 301 282 { 302 283 CKeyState::fakeKeyRepeat(id, mask, count, button); … … 323 304 324 305 // we can get toggle modifiers from the system 325 if (WinGetKeyState(HWND_DESKTOP, VK_CAP ITAL) & 1) {306 if (WinGetKeyState(HWND_DESKTOP, VK_CAPSLOCK) & 1) 326 307 state |= KeyModifierCapsLock; 327 } 328 if (WinGetKeyState(HWND_DESKTOP, VK_NUMLOCK) & 1) { 308 if (WinGetKeyState(HWND_DESKTOP, VK_NUMLOCK) & 1) 329 309 state |= KeyModifierNumLock; 330 } 331 if (WinGetKeyState(HWND_DESKTOP, VK_SCROLL) & 1) { 310 if (WinGetKeyState(HWND_DESKTOP, VK_SCRLLOCK) & 1) 332 311 state |= KeyModifierScrollLock; 333 }334 335 312 return state; 336 313 } … … 623 600 } 624 601 } 625 602 626 603 // save each key. the map will automatically discard 627 604 // duplicates, like an unshift and shifted version of … … 742 719 } 743 720 744 bool745 CPMKeyState::getGroups(GroupList& groups) const746 {747 // get keyboard layouts748 UInt32 newNumLayouts = GetKeyboardLayoutList(0, NULL);749 if (newNumLayouts == 0) {750 LOG((CLOG_DEBUG1 "can't get keyboard layouts"));751 return false;752 }753 HKL* newLayouts = new HKL[newNumLayouts];754 newNumLayouts = GetKeyboardLayoutList(newNumLayouts, newLayouts);755 if (newNumLayouts == 0) {756 LOG((CLOG_DEBUG1 "can't get keyboard layouts"));757 delete[] newLayouts;758 return false;759 }760 761 groups.clear();762 groups.insert(groups.end(), newLayouts, newLayouts + newNumLayouts);763 delete[] newLayouts;764 return true;765 }766 767 void768 CPMKeyState::setWindowGroup(SInt32 group)769 {770 HWND targetWindow = GetForegroundWindow();771 772 bool sysCharSet = true;773 // XXX -- determine if m_groups[group] can be used with the system774 // character set.775 776 PostMessage(targetWindow, WM_INPUTLANGCHANGEREQUEST,777 sysCharSet ? 1 : 0, (LPARAM)m_groups[group]);778 779 // XXX -- use a short delay to let the target window process the message780 // before it sees the keyboard events. i'm not sure why this is781 // necessary since the messages should arrive in order. if we don't782 // delay, though, some of our keyboard events may disappear.783 Sleep(100);784 }785 786 721 void 787 722 CPMKeyState::fixKeys() … … 822 757 LOG((CLOG_DEBUG1 "event: fake key release left windows key (0x%03x)", leftButton)); 823 758 CKeyState::onKey(leftButton, false, state); 824 CKeyState::sendKeyEvent(m_eventTarget, false, false, 825 kKeySuper_L, state, 1, leftButton); 759 CKeyState::sendKeyEvent(m_eventTarget, false, false, kKeySuper_L, state, 1, leftButton); 826 760 } 827 761 if (rightDown && !rightAsyncDown) { 828 762 LOG((CLOG_DEBUG1 "event: fake key release right windows key (0x%03x)", rightButton)); 829 763 CKeyState::onKey(rightButton, false, state); 830 CKeyState::sendKeyEvent(m_eventTarget, false, false, 831 kKeySuper_R, state, 1, rightButton); 764 CKeyState::sendKeyEvent(m_eventTarget, false, false, kKeySuper_R, state, 1, rightButton); 832 765 } 833 766 } … … 910 843 } 911 844 } 845 846 /* 847 * Local Variables: 848 * mode: c 849 * c-file-style: "k&r" 850 * c-basic-offset: 4 851 * tab-width: 4 852 * indent-tabs-mode: t 853 * End: 854 */ 855 -
trunk/synergy/lib/platform/CPMKeyState.h
r2752 r2755 3 3 * Copyright (C) 2003 Chris Schoeneman 4 4 * Copyright (C) 2006 Knut St. Osmundsen 5 * 5 * 6 6 * This package is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU General Public License 8 8 * found in the file COPYING that should have accompanied this file. 9 * 9 * 10 10 * This package is distributed in the hope that it will be useful, 11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 90 90 to a modifier mask. 91 91 */ 92 KeyID mapKeyFromEvent(MPARAM charAndVirtKey, MPARAM info, KeyModifierMask* maskOut) const;92 KeyID mapKeyFromEvent(USHORT fsFlags, UCHAR ucRepeat, UCHAR ucScanCode, USHORT usch, USHORT usvk, KeyModifierMask* maskOut) const; 93 93 94 94 //! Check if keyboard groups have changed … … 183 183 }; 184 184 185 /* 186 * Local Variables: 187 * mode: c 188 * c-file-style: "k&r" 189 * c-basic-offset: 4 190 * tab-width: 4 191 * indent-tabs-mode: t 192 * End: 193 */ 194 195 185 196 #endif -
trunk/synergy/lib/platform/CPMScreen.cpp
r2754 r2755 34 34 #include "CPMUtil.h" 35 35 #include <string.h> 36 #include <unistd.h> 36 37 37 38 // … … 44 45 m_isPrimary(isPrimary), 45 46 m_isOnScreen(m_isPrimary), 46 m_class(0),47 47 m_x(0), m_y(0), 48 48 m_cx(0), m_cy(0), … … 53 53 m_mark(0), 54 54 m_markReceived(0), 55 m_fixTimer(NULL),56 55 m_screensaver(NULL), 57 56 m_screensaverNotify(false), … … 73 72 74 73 s_screen = this; 74 75 // query curren thread bits. 76 m_threadID = _gettid(); 77 m_hab = WinQueryAnchorBlock(HWND_DESKTOP); 78 m_hmq = WinQueueFromID(m_hab, getpid(), _gettid()); 79 if (m_hab == NULLHANDLE || m_hmq == NULLHANDLE) { 80 LOG((CLOG_CRIT "couldn't get the hab/hmq of the current thread!\n")); 81 throw XScreenOpenFailure(); 82 } 83 75 84 try { 76 if (m_isPrimary) {85 if (m_isPrimary) 77 86 m_hmodHook = openHookLibrary("synrgyhk"); 78 }79 87 m_screensaver = new CPMScreenSaver(); 80 88 m_keyState = new CPMKeyState(getEventTarget()); 81 89 updateScreenShape(); 82 m_class = createWindowClass(); 83 m_window = createWindow(m_class, "Synergy"); 90 m_window = createWindow("Synergy"); 84 91 forceShowCursor(); 85 92 LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_cx, m_cy, m_multimon ? "(multi-monitor)" : "")); 86 93 LOG((CLOG_DEBUG "window is 0x%08x", m_window)); 87 } 88 catch (...) { 94 } catch (...) { 89 95 delete m_keyState; 90 96 delete m_screensaver; 91 97 destroyWindow(m_window); 92 destroyClass(m_class);93 98 closeHookLibrary(m_hmodHook); 94 99 s_screen = NULL; … … 98 103 // install event handlers 99 104 EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(), 100 new TMethodEventJob<CPMScreen>(this, 101 &CPMScreen::handleSystemEvent)); 105 new TMethodEventJob<CPMScreen>(this, &CPMScreen::handleSystemEvent)); 102 106 103 107 // install the platform event queue … … 115 119 delete m_screensaver; 116 120 destroyWindow(m_window); 117 destroyClass(m_class);118 121 closeHookLibrary(m_hmodHook); 119 122 s_screen = NULL; … … 124 127 { 125 128 assert(m_isOnScreen == m_isPrimary); 126 127 // we need to poll some things to fix them128 m_fixTimer = EVENTQUEUE->newTimer(1.0, NULL);129 EVENTQUEUE->adoptHandler(CEvent::kTimer, m_fixTimer,130 new TMethodEventJob<CPMScreen>(this, &CPMScreen::handleFixes));131 129 132 130 // install our clipboard snooper … … 135 133 WinSetClipbrdViewer(hab, m_window); 136 134 137 /// @todo start here!138 // track the active desk and (re)install the hooks139 m_desks->enable();140 141 135 if (m_isPrimary) { 142 136 // set jump zones … … 151 145 CPMScreen::disable() 152 146 { 153 // stop tracking the active desk154 m_desks->disable();155 156 147 if (m_isPrimary) { 157 148 // disable hooks … … 166 157 m_nextClipboardWindow = NULL; 167 158 168 // uninstall fix timer169 if (m_fixTimer != NULL) {170 EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);171 EVENTQUEUE->deleteTimer(m_fixTimer);172 m_fixTimer = NULL;173 }174 175 159 m_isOnScreen = m_isPrimary; 176 160 forceShowCursor(); … … 180 164 CPMScreen::enter() 181 165 { 182 m_desks->enter(); 166 // show the pointer (?), hide the synergy window and restore focus. 167 WinShowPointer(HWND_DESKTOP, TRUE); 168 WinSetWindowPos(m_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDE); 169 //?? WinSetFocus( 170 //?? WinEnableWindow 171 183 172 if (m_isPrimary) { 184 173 // watch jump zones … … 197 186 CPMScreen::leave() 198 187 { 188 /// @todo save focus window. 189 199 190 if (m_isPrimary) { 200 191 // warp to center … … 252 243 { 253 244 m_screensaverNotify = notify; 254 if (!m_screensaverNotify) {245 if (!m_screensaverNotify) 255 246 m_screensaver->disable(); 256 }257 247 } 258 248 … … 260 250 CPMScreen::closeScreensaver() 261 251 { 262 if (!m_screensaverNotify) {252 if (!m_screensaverNotify) 263 253 m_screensaver->enable(); 264 }265 254 } 266 255 … … 268 257 CPMScreen::screensaver(bool activate) 269 258 { 270 if (activate) {259 if (activate) 271 260 m_screensaver->activate(); 272 } 273 else { 261 else 274 262 m_screensaver->deactivate(); 275 }276 263 } 277 264 … … 321 308 CPMScreen::getShape(SInt32& x, SInt32& y, SInt32& cx, SInt32& cy) const 322 309 { 323 assert(m_class != 0);324 325 310 x = m_x; 326 311 y = m_y; … … 356 341 // remove all input events before and including warp 357 342 QMSG qmsg; 358 while (WinPeekMsg(m_hab, &qmsg, NULLHANDLE, SYNERGY_ MSG_INPUT_FIRST, SYNERGY_MSG_INPUT_LAST, PM_REMOVE)) {343 while (WinPeekMsg(m_hab, &qmsg, NULLHANDLE, SYNERGY_PM_MSG_INPUT_FIRST, SYNERGY_PM_MSG_INPUT_LAST, PM_REMOVE)) { 359 344 // do nothing 360 345 } … … 483 468 m_keyState->useSavedModifiers(true); 484 469 } 485 m_desks->fakeInputBegin();470 //m_desks->fakeInputBegin(); 486 471 } 487 472 … … 491 476 assert(m_isPrimary); 492 477 493 m_desks->fakeInputEnd();478 //m_desks->fakeInputEnd(); 494 479 if (!m_isOnScreen) { 495 480 m_keyState->useSavedModifiers(false); … … 535 520 CPMScreen::fakeMouseButton(ButtonID id, bool press) const 536 521 { 537 m_desks->fakeMouseButton(id, press);522 //m_desks->fakeMouseButton(id, press); 538 523 } 539 524 … … 541 526 CPMScreen::fakeMouseMove(SInt32 x, SInt32 y) const 542 527 { 543 m_desks->fakeMouseMove(x, y);528 //m_desks->fakeMouseMove(x, y); 544 529 } 545 530 … … 547 532 CPMScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const 548 533 { 549 m_desks->fakeMouseRelativeMove(dx, dy);534 //m_desks->fakeMouseRelativeMove(dx, dy); 550 535 } 551 536 … … 553 538 CPMScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const 554 539 { 555 m_desks->fakeMouseWheel(xDelta, yDelta);540 //m_desks->fakeMouseWheel(xDelta, yDelta); 556 541 } 557 542 … … 559 544 CPMScreen::updateKeys() 560 545 { 561 m_desks->updateKeys();546 //m_desks->updateKeys(); 562 547 } 563 548 … … 592 577 } 593 578 594 H INSTANCE579 HMODULE 595 580 CPMScreen::openHookLibrary(const char* name) 596 581 { 597 582 // load the hook library 598 HINSTANCE hookLibrary = LoadLibrary(name); 599 if (hookLibrary == NULL) { 600 LOG((CLOG_ERR "Failed to load hook library; %s.dll is missing", name)); 583 HMODULE hmod; 584 APIRET rc = DosLoadModule(NULL, 0, (PCSZ)name, &hmod); 585 if (rc != NO_ERROR) { 586 LOG((CLOG_ERR "Failed to load hook library (%s), rc=%d ", name, rc)); 601 587 throw XScreenOpenFailure(); 602 588 } 603 589 604 590 // look up functions 605 m_setSides = (SetSidesFunc)GetProcAddress(hookLibrary, "setSides"); 606 m_setZone = (SetZoneFunc)GetProcAddress(hookLibrary, "setZone"); 607 m_setMode = (SetModeFunc)GetProcAddress(hookLibrary, "setMode"); 608 m_init = (InitFunc)GetProcAddress(hookLibrary, "init"); 609 m_cleanup = (CleanupFunc)GetProcAddress(hookLibrary, "cleanup"); 610 if (m_setSides == NULL || 611 m_setZone == NULL || 612 m_setMode == NULL || 613 m_init == NULL || 614 m_cleanup == NULL) { 615 LOG((CLOG_ERR "Invalid hook library; use a newer %s.dll", name)); 591 if ( (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setSides", (PPFN)&m_setSides)) != NO_ERROR 592 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setZone", (PPFN)&m_setZone )) != NO_ERROR 593 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_setMode", (PPFN)&m_setMode )) != NO_ERROR 594 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_init", (PPFN)&m_init )) != NO_ERROR 595 || (rc = DosQueryProcAddr(hmod, 0, (PCSZ)"_cleanup", (PPFN)&m_cleanup )) != NO_ERROR) { 596 LOG((CLOG_ERR "Invalid hook library; use a newer %s.dll (rc=%d)", name, rc)); 597 DosFreeModule(hmod); 616 598 throw XScreenOpenFailure(); 617 599 } 618 600 619 601 // initialize hook library 620 if (m_init(GetCurrentThreadId()) == 0) { 621 LOG((CLOG_ERR "Cannot initialize hook library; is synergy already running?")); 602 if (m_init(m_hmq, _gettid(), getpid()) == 0) { 603 LOG((CLOG_ERR "Cannot initialize hook library; is synergy already running?")); 604 DosFreeModule(hmod); 622 605 throw XScreenOpenFailure(); 623 606 } 624 625 return hookLibrary; 626 } 627 628 void 629 CPMScreen::closeHookLibrary(HINSTANCE hookLibrary) const 630 { 631 if (hookLibrary != NULL) { 632 m_cleanup(); 633 FreeLibrary(hookLibrary); 634 } 635 } 636 637 ATOM 638 CPMScreen::createWindowClass() const 639 { 640 WNDCLASSEX classInfo; 641 classInfo.cbSize = sizeof(classInfo); 642 classInfo.style = CS_DBLCLKS | CS_NOCLOSE; 643 classInfo.lpfnWndProc = &CPMScreen::wndProc; 644 classInfo.cbClsExtra = 0; 645 classInfo.cbWndExtra = 0; 646 classInfo.hInstance = s_instance; 647 classInfo.hIcon = NULL; 648 classInfo.hCursor = NULL; 649 classInfo.hbrBackground = NULL; 650 classInfo.lpszMenuName = NULL; 651 classInfo.lpszClassName = "Synergy"; 652 classInfo.hIconSm = NULL; 653 return RegisterClassEx(&classInfo); 654 } 655 656 void 657 CPMScreen::destroyClass(ATOM windowClass) const 658 { 659 if (windowClass != 0) { 660 UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_instance); 607 return hmod; 608 } 609 610 void 611 CPMScreen::closeHookLibrary(HMODULE hmod) const 612 { 613 if (hmod != NULL) { 614 m_cleanup(m_hab); 615 DosFreeModule(hmod); 661 616 } 662 617 } 663 618 664 619 HWND 665 CPMScreen::createWindow(ATOM windowClass, const char* name) const 666 { 667 HWND window = CreateWindowEx(WS_EX_TOPMOST | 668 WS_EX_TRANSPARENT | 669 WS_EX_TOOLWINDOW, 670 reinterpret_cast<LPCTSTR>(windowClass), 671 name, 672 WS_POPUP, 620 CPMScreen::createWindow(const char* name) 621 { 622 WinRegisterClass(m_hab, (PCSZ)"Synergy", CPMScreen::wndProc, CS_MOVENOTIFY, sizeof(uintptr_t)); 623 HWND hwnd = WinCreateWindow(HWND_DESKTOP, 624 (PCSZ)"Synergy", 625 NULL, 626 0, //WS_?, 673 627 0, 0, 1, 1, 674 NULL, NULL, 675 s_instance, 628 HWND_DESKTOP, 629 NULLHANDLE, 630 0, 631 this, 676 632 NULL); 677 if ( window == NULL) {678 LOG((CLOG_ERR "failed to create window: % d", GetLastError()));633 if (hwnd == NULLHANDLE) { 634 LOG((CLOG_ERR "failed to create window: %ld", WinGetLastError(m_hab))); 679 635 throw XScreenOpenFailure(); 680 636 } 681 return window;637 return hwnd; 682 638 } 683 639 … … 686 642 { 687 643 if (hwnd != NULL) { 688 DestroyWindow(hwnd);644 WinDestroyWindow(hwnd); 689 645 } 690 646 } … … 708 664 CPMScreen::handleSystemEvent(const CEvent& event, void*) 709 665 { 710 MSG* msg = reinterpret_cast<MSG*>(event.getData()); 711 assert(msg != NULL); 712 713 if (CArchMiscWindows::processDialog(msg)) { 666 PQMSG pqmsg = (PQMSG)event.getData(); 667 assert(pqmsg != NULL); 668 if (onPreDispatch(pqmsg->hwnd, pqmsg->msg, pqmsg->mp1, pqmsg->mp2)) 714 669 return; 715 } 716 if (onPreDispatch(msg->hwnd, msg->message, msg->wParam, msg->lParam)) { 717 return; 718 } 719 TranslateMessage(msg); 720 DispatchMessage(msg); 670 WinDispatchMsg(CPMUtil::getHAB(), pqmsg); 721 671 } 722 672 … … 724 674 CPMScreen::updateButtons() 725 675 { 726 int numButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);727 676 m_buttons[kButtonNone] = false; 728 m_buttons[kButtonLeft] = (GetKeyState(VK_LBUTTON) < 0); 729 m_buttons[kButtonRight] = (GetKeyState(VK_RBUTTON) < 0); 730 m_buttons[kButtonMiddle] = (GetKeyState(VK_MBUTTON) < 0); 731 m_buttons[kButtonExtra0 + 0] = (numButtons >= 4) && 732 (GetKeyState(VK_XBUTTON1) < 0); 733 m_buttons[kButtonExtra0 + 1] = (numButtons >= 5) && 734 (GetKeyState(VK_XBUTTON2) < 0); 677 m_buttons[kButtonLeft] = (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) != 0; 678 m_buttons[kButtonRight] = (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) != 0; 679 m_buttons[kButtonMiddle] = (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000) != 0; 680 m_buttons[kButtonExtra0 + 0] = false; 681 m_buttons[kButtonExtra0 + 1] = false; 735 682 } 736 683 … … 742 689 743 690 bool 744 CPMScreen::onPreDispatch(HWND hwnd, 745 UINT message, WPARAM wParam, LPARAM lParam) 691 CPMScreen::onPreDispatch(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) 746 692 { 747 693 // handle event 748 switch (message) { 749 case SYNERGY_MSG_SCREEN_SAVER: 750 return onScreensaver(wParam != 0); 751 752 case SYNERGY_MSG_DEBUG: 753 LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", wParam, lParam)); 694 switch (msg) { 695 case SYNERGY_PM_MSG_DEBUG: 696 LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", mp1, mp2)); 754 697 return true; 755 698 } 756 699 757 700 if (m_isPrimary) { 758 return onPreDispatchPrimary(hwnd, m essage, wParam, lParam);701 return onPreDispatchPrimary(hwnd, msg, mp1, mp2); 759 702 } 760 703 … … 763 706 764 707 bool 765 CPMScreen::onPreDispatchPrimary(HWND, 766 UINT message, WPARAM wParam, LPARAM lParam) 708 CPMScreen::onPreDispatchPrimary(HWND, ULONG msg, MPARAM mp1, MPARAM mp2) 767 709 { 768 710 // handle event 769 switch (message) { 770 case SYNERGY_MSG_MARK: 771 return onMark(static_cast<UInt32>(wParam)); 772 773 case SYNERGY_MSG_KEY: 774 return onKey(wParam, lParam); 775 776 case SYNERGY_MSG_MOUSE_BUTTON: 777 return onMouseButton(wParam, lParam); 778 779 case SYNERGY_MSG_MOUSE_MOVE: 780 return onMouseMove(static_cast<SInt32>(wParam), 781 static_cast<SInt32>(lParam)); 782 783 case SYNERGY_MSG_MOUSE_WHEEL: 784 // XXX -- support x-axis scrolling 785 return onMouseWheel(0, static_cast<SInt32>(wParam)); 786 787 case SYNERGY_MSG_PRE_WARP: 711 switch (msg) { 712 case SYNERGY_PM_MSG_MARK: 713 return onMark((uintptr_t)mp1); 714 715 case SYNERGY_PM_MSG_KEY: 716 return onKey(SHORT1FROMMP(mp1), CHAR3FROMMP(mp1), CHAR4FROMMP(mp1), SHORT1FROMMP(mp2), SHORT2FROMMP(mp2)); 717 718 case SYNERGY_PM_MSG_MOUSE_BUTTON: 719 return onMouseButton(SHORT1FROMMP(mp1), (SHORT)SHORT1FROMMP(mp2), m_cy - (SHORT)SHORT2FROMMP(mp2)); 720 721 case SYNERGY_PM_MSG_MOUSE_MOVE: 722 return onMouseMove(SHORT1FROMMP(mp1), (SHORT)SHORT1FROMMP(mp2), m_cy - (SHORT)SHORT2FROMMP(mp2)); 723 724 case SYNERGY_PM_MSG_PRE_WARP: 788 725 { 789 // save position to compute delta of next motion790 m_xCursor = static_cast<SInt32>(wParam);791 m_yCursor = static_cast<SInt32>(lParam);792 793 // we warped the mouse. discard events until we find the794 // matching post warp event. see warpCursorNoFlush() for795 // where the events are sent. we discard the matching726 // Save position to compute delta of next motion 727 m_xCursor = (SInt32)mp1; 728 m_yCursor = (SInt32)mp2; 729 730 // We warped the mouse. Discard events until we find the 731 // matching post warp event. See warpCursorNoFlush() for 732 // where the events are sent. We discard the matching 796 733 // post warp event and can be sure we've skipped the warp 797 734 // event. 798 MSG msg; 799 do { 800 GetMessage(&msg, NULL, SYNERGY_MSG_MOUSE_MOVE, 801 SYNERGY_MSG_POST_WARP); 802 } while (msg.message != SYNERGY_MSG_POST_WARP); 735 QMSG qmsg; 736 while ( WinGetMsg(m_hab, &qmsg, NULLHANDLE, SYNERGY_PM_MSG_MOUSE_MOVE, SYNERGY_PM_MSG_POST_WARP) 737 && qmsg.msg != SYNERGY_PM_MSG_POST_WARP) 738 /* nothing */; 803 739 } 804 740 return true; 805 741 806 case SYNERGY_ MSG_POST_WARP:742 case SYNERGY_PM_MSG_POST_WARP: 807 743 LOG((CLOG_WARN "unmatched post warp")); 808 744 return true; 809 810 case WM_HOTKEY:811 // we discard these messages. we'll catch the hot key in the812 // regular key event handling, where we can detect both key813 // press and release. we only register the hot key so no other814 // app will act on the key combination.815 break;816 745 } 817 746 … … 820 749 821 750 bool 822 CPMScreen::onEvent(HWND, UINT msg, 823 WPARAM wParam, LPARAM lParam, LRESULT* result) 751 CPMScreen::onEvent(HWND, ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT *result) 824 752 { 825 753 switch (msg) { 826 case WM_QUERYENDSESSION:827 if (m_is95Family) {828 *result = TRUE;829 return true;830 }831 break;832 833 case WM_ENDSESSION:834 if (m_is95Family) {835 if (wParam == TRUE && lParam == 0) {836 EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));837 }838 return true;839 }840 break;841 842 754 case WM_DRAWCLIPBOARD: 843 // first pass on the message844 if (m_nextClipboardWindow != NULL) {845 SendMessage(m_nextClipboardWindow, msg, wParam, lParam);846 }755 //// first pass on the message 756 //if (m_nextClipboardWindow != NULL) { 757 // WinSendMessage(m_nextClipboardWindow, msg, mp1, mp2); 758 //} 847 759 848 760 // now handle the message 849 761 return onClipboardChange(); 850 851 case WM_CHANGECBCHAIN:852 if (m_nextClipboardWindow == (HWND)wParam) {853 m_nextClipboardWindow = (HWND)lParam;854 LOG((CLOG_DEBUG "clipboard chain: new next: 0x%08x", m_nextClipboardWindow));855 }856 else if (m_nextClipboardWindow != NULL) {857 SendMessage(m_nextClipboardWindow, msg, wParam, lParam);858 }859 return true;860 861 case WM_DISPLAYCHANGE:862 return onDisplayChange();863 864 case WM_POWERBROADCAST:865 switch (wParam) {866 case PBT_APMRESUMEAUTOMATIC:867 case PBT_APMRESUMECRITICAL:868 case PBT_APMRESUMESUSPEND:869 EVENTQUEUE->addEvent(CEvent(IScreen::getResumeEvent(),870 getEventTarget(), NULL,871 CEvent::kDeliverImmediately));872 break;873 874 case PBT_APMSUSPEND:875 EVENTQUEUE->addEvent(CEvent(IScreen::getSuspendEvent(),876 getEventTarget(), NULL,877 CEvent::kDeliverImmediately));878 break;879 }880 *result = TRUE;881 return true;882 762 } 883 763 … … 893 773 894 774 bool 895 CPMScreen::onKey( WPARAM wParam, LPARAM lParam)896 { 897 static const KeyModifierMask s_ctrlAlt = 898 899 900 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));775 CPMScreen::onKey(USHORT fsFlags, UCHAR ucRepeat, UCHAR ucScanCode, USHORT usch, USHORT usvk) 776 { 777 #if 0 778 static const KeyModifierMask s_ctrlAlt = KeyModifierControl | KeyModifierAlt; 779 780 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)); 901 781 902 782 // get event info 903 KeyButton button = (KeyButton)(( lParam& 0x01ff0000) >> 16);904 bool down = (( lParam& 0x80000000u) == 0x00000000u);783 KeyButton button = (KeyButton)((mp2 & 0x01ff0000) >> 16); 784 bool down = ((mp2 & 0x80000000u) == 0x00000000u); 905 785 bool wasDown = isKeyDown(button); 906 786 KeyModifierMask oldState = pollActiveModifiers(); 907 787 908 788 // check for autorepeat 909 if (m_keyState->testAutoRepeat(down, ( lParam& 0x40000000u) == 1, button)) {910 lParam|= 0x40000000u;789 if (m_keyState->testAutoRepeat(down, (mp2 & 0x40000000u) == 1, button)) { 790 mp2 |= 0x40000000u; 911 791 } 912 792 … … 916 796 // alternatively, we could just throw these events out. 917 797 if (button == 0) { 918 button = m_keyState->virtualKeyToButton( wParam& 0xffu);798 button = m_keyState->virtualKeyToButton(mp1 & 0xffu); 919 799 if (button == 0) { 920 800 return true; … … 950 830 if (oldState != state) { 951 831 // modifier key was pressed/released 952 if (onHotKey(0, lParam)) {832 if (onHotKey(0, mp2)) { 953 833 return true; 954 834 } … … 956 836 else { 957 837 // non-modifier was pressed/released 958 if (onHotKey( wParam, lParam)) {838 if (onHotKey(mp1, mp2)) { 959 839 return true; 960 840 } … … 965 845 // check for ctrl+alt+del. we do not want to pass that to the 966 846 // client. the user can use ctrl+alt+pause to emulate it. 967 UINT virtKey = ( wParam& 0xffu);847 UINT virtKey = (mp1 & 0xffu); 968 848 if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) { 969 849 LOG((CLOG_DEBUG "discard ctrl+alt+del")); … … 975 855 (state & s_ctrlAlt) == s_ctrlAlt) { 976 856 LOG((CLOG_DEBUG "emulate ctrl+alt+del")); 977 // switch wParam and lParamto be as if VK_DELETE was857 // switch mp1 and mp2 to be as if VK_DELETE was 978 858 // pressed or released. when mapping the key we require that 979 // we not use AltGr (the 0x10000 flag in wParam) and we not980 // use the keypad delete key (the 0x01000000 flag in lParam).981 wParam= VK_DELETE | 0x00010000u;982 lParam&= 0xfe000000;983 lParam |= m_keyState->virtualKeyToButton(wParam& 0xffu) << 16;984 lParam|= 0x01000001;859 // we not use AltGr (the 0x10000 flag in mp1) and we not 860 // use the keypad delete key (the 0x01000000 flag in mp2). 861 mp1 = VK_DELETE | 0x00010000u; 862 mp2 &= 0xfe000000; 863 mp2 |= m_keyState->virtualKeyToButton(mp1 & 0xffu) << 16; 864 mp2 |= 0x01000001; 985 865 } 986 866 987 867 // process key 988 868 KeyModifierMask mask; 989 KeyID key = m_keyState->mapKeyFromEvent( wParam, lParam, &mask);990 button = static_cast<KeyButton>(( lParam& 0x01ff0000u) >> 16);869 KeyID key = m_keyState->mapKeyFromEvent((ULONG)mp1, (ULONG)mp2, &mask); 870 button = static_cast<KeyButton>((mp2 & 0x01ff0000u) >> 16); 991 871 if (key != kKeyNone) { 992 872 // fix key up. if the key isn't down according to … … 1023 903 // do it 1024 904 m_keyState->sendKeyEvent(getEventTarget(), 1025 (( lParam& 0x80000000u) == 0),1026 (( lParam& 0x40000000u) != 0),1027 key, mask, (SInt32)( lParam& 0xffff), button);905 ((mp2 & 0x80000000u) == 0), 906 ((mp2 & 0x40000000u) != 0), 907 key, mask, (SInt32)(mp2 & 0xffff), button); 1028 908 } 1029 909 else { … … 1031 911 } 1032 912 } 1033 913 #endif 1034 914 return true; 1035 915 } 1036 916 1037 917 bool 1038 CPMScreen::onHotKey(WPARAM wParam, LPARAM lParam) 1039 { 918 CPMScreen::onHotKey(MPARAM mp1, MPARAM mp2) 919 { 920 #if 0 1040 921 // get the key info 1041 922 KeyModifierMask state = getActiveModifiers(); 1042 UINT virtKey = ( wParam& 0xffu);923 UINT virtKey = (mp1 & 0xffu); 1043 924 UINT modifiers = 0; 1044 925 if ((state & KeyModifierShift) != 0) { … … 1064 945 // find what kind of event 1065 946 CEvent::Type type; 1066 if (( lParam& 0x80000000u) == 0u) {1067 if (( lParam& 0x40000000u) != 0u) {947 if ((mp2 & 0x80000000u) == 0u) { 948 if ((mp2 & 0x40000000u) != 0u) { 1068 949 // ignore key repeats but it counts as a hot key 1069 950 return true; … … 1079 960 CHotKeyInfo::alloc(i->second))); 1080 961 962 #endif 1081 963 return true; 1082 964 } 1083 965 1084 966 bool 1085 CPMScreen::onMouseButton( WPARAM wParam, LPARAM lParam)967 CPMScreen::onMouseButton(ULONG msg, SInt32 ax, SInt32 ay) 1086 968 { 1087 969 // get which button 1088 bool pressed = mapPressFromEvent( (ULONG)wParam, lParam);1089 ButtonID button = mapButtonFromEvent( (ULONG)wParam, lParam);970 bool pressed = mapPressFromEvent(msg); 971 ButtonID button = mapButtonFromEvent(msg); 1090 972 1091 973 // keep our shadow key state up to date … … 1122 1004 1123 1005 bool 1124 CPMScreen::onMouseMove( SInt32 mx, SInt32 my)1006 CPMScreen::onMouseMove(ULONG msg, SInt32 ax, SInt32 ay) 1125 1007 { 1126 1008 // compute motion delta (relative to the last known 1127 1009 // mouse position) 1128 SInt32 x = mx - m_xCursor;1129 SInt32 y = my - m_yCursor;1010 SInt32 x = ax - m_xCursor; 1011 SInt32 y = ay - m_yCursor; 1130 1012 1131 1013 // ignore if the mouse didn't move or if message posted prior … … 1136 1018 1137 1019 // save position to compute delta of next motion 1138 m_xCursor = mx;1139 m_yCursor = my;1020 m_xCursor = ax; 1021 m_yCursor = ay; 1140 1022 1141 1023 if (m_isOnScreen) { 1142 1024 // motion on primary screen 1143 sendEvent(getMotionOnPrimaryEvent(), 1144 CMotionInfo::alloc(m_xCursor, m_yCursor)); 1025 sendEvent(getMotionOnPrimaryEvent(), CMotionInfo::alloc(m_xCursor, m_yCursor)); 1145 1026 } 1146 1027 else { … … 1171 1052 1172 1053 bool 1173 CPMScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta)1174 {1175 // ignore message if posted prior to last mark change1176 if (!ignore()) {1177 LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta));1178 sendEvent(getWheelEvent(), CWheelInfo::alloc(xDelta, yDelta));1179 }1180 return true;1181 }1182 1183 bool1184 CPMScreen::onScreensaver(bool activated)1185 {1186 // ignore this message if there are any other screen saver1187 // messages already in the queue. this is important because1188 // our checkStarted() function has a deliberate delay, so it1189 // can't respond to events at full CPU speed and will fall1190 // behind if a lot of screen saver events are generated.1191 // that can easily happen because windows will continually1192 // send SC_SCREENSAVE until the screen saver starts, even if1193 // the screen saver is disabled!1194 MSG msg;1195 if (PeekMessage(&msg, NULL, SYNERGY_MSG_SCREEN_SAVER,1196 SYNERGY_MSG_SCREEN_SAVER, PM_NOREMOVE)) {1197 return true;1198 }1199 1200 if (activated) {1201 if (!m_screensaverActive &&1202 m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) {1203 m_screensaverActive = true;1204 sendEvent(getScreensaverActivatedEvent());1205 1206 // enable display power down1207 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);1208 }1209 }1210 else {1211 if (m_screensaverActive) {1212 m_screensaverActive = false;1213 sendEvent(getScreensaverDeactivatedEvent());1214 1215 // disable display power down1216 CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);1217 }1218 }1219 1220 return true;1221 }1222 1223 bool1224 CPMScreen::onDisplayChange()1225 {1226 // screen resolution may have changed. save old shape.1227 SInt32 xOld = m_x, yOld = m_y, wOld = m_cx, hOld = m_cy;1228 1229 // update shape1230 updateScreenShape();1231 1232 // do nothing if resolution hasn't changed1233 if (xOld != m_x || yOld != m_y || wOld != m_cx || hOld != m_cy) {1234 if (m_isPrimary) {1235 // warp mouse to center if off screen1236 if (!m_isOnScreen) {1237 warpCursor(m_xCenter, m_yCenter);1238 }1239 1240 // tell hook about resize if on screen1241 else {1242 m_setZone(m_x, m_y, m_cx, m_cy, getJumpZoneSize());1243 }1244 }1245 1246 // send new screen info1247 sendEvent(getShapeChangedEvent());1248 1249 LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_cx, m_cy, m_multimon ? "(multi-monitor)" : ""));1250 }1251 1252 return true;1253 }1254 1255 bool1256 1054 CPMScreen::onClipboardChange() 1257 1055 { … … 1278 1076 { 1279 1077 // send an event that we can recognize before the mouse warp 1280 WinPostQueueMsg(m_hmq, SYNERGY_ MSG_PRE_WARP, (MPARAM)x, (MPARAM)y);1078 WinPostQueueMsg(m_hmq, SYNERGY_PM_MSG_PRE_WARP, (MPARAM)x, (MPARAM)y); 1281 1079 1282 1080 // warp mouse. hopefully this inserts a mouse motion event … … 1303 1101 1304 1102 // send an event that we can recognize after the mouse warp 1305 WinPostQueueMsg(m_hmq, SYNERGY_ MSG_POST_WARP, 0, 0);1103 WinPostQueueMsg(m_hmq, SYNERGY_PM_MSG_POST_WARP, 0, 0); 1306 1104 } 1307 1105 … … 1313 1111 1314 1112 // mark point in message queue where the mark was changed 1315 WinPostQueueMsg(m_hmq, SYNERGY_ MSG_MARK, (MPARAM)m_mark, 0);1113 WinPostQueueMsg(m_hmq, SYNERGY_PM_MSG_MARK, (MPARAM)m_mark, 0); 1316 1114 } 1317 1115 … … 1339 1137 } 1340 1138 1341 void1342 CPMScreen::handleFixes(const CEvent&, void*)1343 {1344 // update keys if keyboard layouts have changed1345 if (m_keyState->didGroupsChange()) {1346 updateKeys();1347 }1348 }1349 1350 1139 ButtonID 1351 CPMScreen::mapButtonFromEvent(ULONG msg , MPARAM button) const1140 CPMScreen::mapButtonFromEvent(ULONG msg) const 1352 1141 { 1353 1142 /** @todo query which is left and which is right. */ … … 1377 1166 1378 1167 bool 1379 CPMScreen::mapPressFromEvent(ULONG msg , LPARAM) const1168 CPMScreen::mapPressFromEvent(ULONG msg) const 1380 1169 { 1381 1170 switch (msg) { … … 1411 1200 } 1412 1201 1413 // update layouts if necessary1414 if (m_keyState->didGroupsChange()) {1415 CPlatformScreen::updateKeyMap();1416 }1417 1418 1202 // now update the keyboard state 1419 1203 CPlatformScreen::updateKeyState(); … … 1454 1238 } 1455 1239 1456 HRESULT EXPENTRY1457 CPMScreen::wndProc(HWND hwnd, U INTmsg, MPARAM mp1, MPARAM mp2)1240 MRESULT EXPENTRY 1241 CPMScreen::wndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) 1458 1242 { 1459 1243 assert(s_screen != NULL); 1460 1244 1461 HRESULT mr = 0;1462 if (!s_screen->onEvent(hwnd, msg, mp1, mp2, & result)) {1245 MRESULT mr = 0; 1246 if (!s_screen->onEvent(hwnd, msg, mp1, mp2, &mr)) { 1463 1247 mr = WinDefWindowProc(hwnd, msg, mp1, mp2); 1464 1248 } … … 1472 1256 // 1473 1257 1474 CPMScreen::CHotKeyItem::CHotKeyItem(U INT keycode, UINTmask) :1258 CPMScreen::CHotKeyItem::CHotKeyItem(ULONG keycode, ULONG mask) : 1475 1259 m_keycode(keycode), 1476 1260 m_mask(mask) … … 1479 1263 } 1480 1264 1481 U INT1265 ULONG 1482 1266 CPMScreen::CHotKeyItem::getVirtualKey() const 1483 1267 { -
trunk/synergy/lib/platform/CPMScreen.h
r2752 r2755 3 3 * Copyright (C) 2002 Chris Schoeneman 4 4 * Copyright (C) 2006 Knut St. Osmundsen 5 * 5 * 6 6 * This package is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU General Public License 8 8 * found in the file COPYING that should have accompanied this file. 9 * 9 * 10 10 * This package is distributed in the hope that it will be useful, 11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 98 98 HMODULE openHookLibrary(const char* name); 99 99 void closeHookLibrary(HMODULE hookLibrary) const; 100 ATOM createWindowClass() const; 101 ATOM createDeskWindowClass(bool isPrimary) const; 102 void destroyClass(ATOM windowClass) const; 103 HWND createWindow(ATOM windowClass, const char* name) const; 100 HWND createWindow(const char* name); 104 101 void destroyWindow(HWND) const; 105 102 … … 122 119 // message handlers 123 120 bool onMark(UInt32 mark); 124 bool onKey( MPARAM, MPARAM);121 bool onKey(USHORT fsFlags, UCHAR ucRepeat, UCHAR ucScanCode, USHORT usch, USHORT usvk); 125 122 bool onHotKey(MPARAM, MPARAM); 126 bool onMouseButton(MPARAM, MPARAM); 127 bool onMouseMove(SInt32 x, SInt32 y); 128 bool onMouseWheel(SInt32 xDelta, SInt32 yDelta); 129 bool onScreensaver(bool activated); 130 bool onDisplayChange(); 123 bool onMouseButton(ULONG msg, SInt32 ax, SInt32 ay); 124 bool onMouseMove(ULONG msg, SInt32 ax, SInt32 ay); 131 125 bool onClipboardChange(); 132 126 … … 150 144 151 145 // map a button event to a button ID 152 ButtonID mapButtonFromEvent(ULONG msg , MPARAM button) const;146 ButtonID mapButtonFromEvent(ULONG msg) const; 153 147 154 148 // map a button event to a press (true) or release (false) 155 bool mapPressFromEvent(ULONG msg , MPARAM button) const;149 bool mapPressFromEvent(ULONG msg) const; 156 150 157 151 // job to update the key state … … 192 186 bool m_isOnScreen; 193 187 194 // our resources195 ATOM m_class;196 197 188 // screen shape stuff 198 189 SInt32 m_x, m_y; … … 213 204 UInt32 m_markReceived; 214 205 215 // the main loop's thread id 206 // the main loop's thread id, anchor block and message queue. 216 207 int m_threadID; 217 218 // timer for periodically checking stuff that requires polling 219 CEventQueueTimer* m_fixTimer; 208 HAB m_hab; 209 HMQ m_hmq; 220 210 221 211 // screen saver stuff 222 CPMScreenSaver* m_screensaver;223 bool 224 bool 212 CPMScreenSaver* m_screensaver; 213 bool m_screensaverNotify; 214 bool m_screensaverActive; 225 215 226 216 // clipboard stuff. our window is used mainly as a clipboard … … 255 245 }; 256 246 247 /* 248 * Local Variables: 249 * mode: c 250 * c-file-style: "k&r" 251 * c-basic-offset: 4 252 * tab-width: 4 253 * indent-tabs-mode: t 254 * End: 255 */ 256 257 257 #endif -
trunk/synergy/lib/platform/CPMSynergyHook.cpp
r2752 r2755 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2002 Chris Schoeneman 4 * 4 * Copyright (C) 2006 Knut St. Osmundsen 5 * 5 6 * This package is free software; you can redistribute it and/or 6 7 * modify it under the terms of the GNU General Public License 7 8 * found in the file COPYING that should have accompanied this file. 8 * 9 * 9 10 * This package is distributed in the hope that it will be useful, 10 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 13 14 */ 14 15 15 #include "C SynergyHook.h"16 #include "CPMSynergyHook.h" 16 17 #include "ProtocolTypes.h" 17 #include <zmouse.h> 18 19 // 20 // debugging compile flag. when not zero the server doesn't grab 21 // the keyboard when the mouse leaves the server screen. this 22 // makes it possible to use the debugger (via the keyboard) when 23 // all user input would normally be caught by the hook procedures. 24 // 25 #define NO_GRAB_KEYBOARD 0 26 27 // 28 // debugging compile flag. when not zero the server will not 29 // install low level hooks. 30 // 31 #define NO_LOWLEVEL_HOOKS 0 32 33 // 34 // extra mouse wheel stuff 35 // 36 37 enum EWheelSupport { 38 kWheelNone, 39 kWheelOld, 40 kWheelWin2000, 41 kWheelModern 42 }; 43 44 // declare extended mouse hook struct. useable on win2k 45 typedef struct tagMOUSEHOOKSTRUCTWin2000 { 46 MOUSEHOOKSTRUCT mhs; 47 DWORD mouseData; 48 } MOUSEHOOKSTRUCTWin2000; 49 50 #if !defined(SM_MOUSEWHEELPRESENT) 51 #define SM_MOUSEWHEELPRESENT 75 52 #endif 53 54 // X button stuff 55 #if !defined(WM_XBUTTONDOWN) 56 #define WM_XBUTTONDOWN 0x020B 57 #define WM_XBUTTONUP 0x020C 58 #define WM_XBUTTONDBLCLK 0x020D 59 #define WM_NCXBUTTONDOWN 0x00AB 60 #define WM_NCXBUTTONUP 0x00AC 61 #define WM_NCXBUTTONDBLCLK 0x00AD 62 #define MOUSEEVENTF_XDOWN 0x0080 63 #define MOUSEEVENTF_XUP 0x0100 64 #define XBUTTON1 0x0001 65 #define XBUTTON2 0x0002 66 #endif 67 68 69 // 70 // globals 71 // 72 73 #if defined(_MSC_VER) 74 #pragma comment(linker, "-section:shared,rws") 75 #pragma data_seg("shared") 76 #endif 77 // all data in this shared section *must* be initialized 78 79 static HINSTANCE g_hinstance = NULL; 80 static DWORD g_processID = 0; 81 static EWheelSupport g_wheelSupport = kWheelNone; 82 static UINT g_wmMouseWheel = 0; 83 static DWORD g_threadID = 0; 84 static HHOOK g_keyboard = NULL; 85 static HHOOK g_mouse = NULL; 86 static HHOOK g_getMessage = NULL; 87 static HHOOK g_keyboardLL = NULL; 88 static HHOOK g_mouseLL = NULL; 89 static bool g_screenSaver = false; 90 static EHookMode g_mode = kHOOK_DISABLE; 91 static UInt32 g_zoneSides = 0; 92 static SInt32 g_zoneSize = 0; 93 static SInt32 g_xScreen = 0; 94 static SInt32 g_yScreen = 0; 95 static SInt32 g_wScreen = 0; 96 static SInt32 g_hScreen = 0; 97 static WPARAM g_deadVirtKey = 0; 98 static LPARAM g_deadLParam = 0; 99 static BYTE g_deadKeyState[256] = { 0 }; 100 static DWORD g_hookThread = 0; 101 static DWORD g_attachedThread = 0; 102 static bool g_fakeInput = false; 103 104 #if defined(_MSC_VER) 105 #pragma data_seg() 106 #endif 107 108 // keep linker quiet about floating point stuff. we don't use any 109 // floating point operations but our includes may define some 110 // (unused) floating point values. 111 #ifndef _DEBUG 18 #include <sys/builtin.h> 19 #include <stdlib.h> 20 #include <unistd.h> 21 22 // 23 // globals - system wide (defined in .asm) 24 // 112 25 extern "C" { 113 int _fltused=0; 114 } 115 #endif 116 117 118 // 119 // internal functions 120 // 121 122 static 123 void 124 detachThread() 125 { 126 if (g_attachedThread != 0 && g_hookThread != g_attachedThread) { 127 AttachThreadInput(g_hookThread, g_attachedThread, FALSE); 128 g_attachedThread = 0; 129 } 130 } 131 132 static 133 bool 134 attachThreadToForeground() 135 { 136 // only attach threads if using low level hooks. a low level hook 137 // runs in the thread that installed the hook but we have to make 138 // changes that require being attached to the target thread (which 139 // should be the foreground window). a regular hook runs in the 140 // thread that just removed the event from its queue so we're 141 // already in the right thread. 142 if (g_hookThread != 0) { 143 HWND window = GetForegroundWindow(); 144 DWORD threadID = GetWindowThreadProcessId(window, NULL); 145 // skip if no change 146 if (g_attachedThread != threadID) { 147 // detach from previous thread 148 detachThread(); 149 150 // attach to new thread 151 if (threadID != 0 && threadID != g_hookThread) { 152 AttachThreadInput(g_hookThread, threadID, TRUE); 153 g_attachedThread = threadID; 154 } 155 return true; 156 } 157 } 158 return false; 159 } 160 161 #if !NO_GRAB_KEYBOARD 162 static 163 WPARAM 164 makeKeyMsg(UINT virtKey, char c, bool noAltGr) 165 { 166 return MAKEWPARAM(MAKEWORD(virtKey & 0xff, (BYTE)c), noAltGr ? 1 : 0); 167 } 168 169 static 170 void 171 keyboardGetState(BYTE keys[256]) 172 { 173 // we have to use GetAsyncKeyState() rather than GetKeyState() because 174 // we don't pass through most keys so the event synchronous state 175 // doesn't get updated. we do that because certain modifier keys have 176 // side effects, like alt and the windows key. 177 SHORT key; 178 for (int i = 0; i < 256; ++i) { 179 key = GetAsyncKeyState(i); 180 keys[i] = (BYTE)((key < 0) ? 0x80u : 0); 181 } 182 key = GetKeyState(VK_CAPITAL); 183 keys[VK_CAPITAL] = (BYTE)(((key < 0) ? 0x80 : 0) | (key & 1)); 184 } 185 186 static 187 bool 188 doKeyboardHookHandler(WPARAM wParam, LPARAM lParam) 189 { 190 // check for special events indicating if we should start or stop 191 // passing events through and not report them to the server. this 192 // is used to allow the server to synthesize events locally but 193 // not pick them up as user events. 194 if (wParam == SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY && 195 ((lParam >> 16) & 0xffu) == SYNERGY_HOOK_FAKE_INPUT_SCANCODE) { 196 // update flag 197 g_fakeInput = ((lParam & 0x80000000u) == 0); 198 PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 199 0xff000000u | wParam, lParam); 200 201 // discard event 202 return true; 203 } 204 205 // if we're expecting fake input then just pass the event through 206 // and do not forward to the server 207 if (g_fakeInput) { 208 PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 209 0xfe000000u | wParam, lParam); 210 return false; 211 } 212 213 // VK_RSHIFT may be sent with an extended scan code but right shift 214 // is not an extended key so we reset that bit. 215 if (wParam == VK_RSHIFT) { 216 lParam &= ~0x01000000u; 217 } 218 219 // tell server about event 220 PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam, lParam); 221 222 // ignore dead key release 223 if (g_deadVirtKey == wParam && 224 (lParam & 0x80000000u) != 0) { 225 PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 226 wParam | 0x04000000, lParam); 227 return false; 228 } 229 230 // we need the keyboard state for ToAscii() 231 BYTE keys[256]; 232 keyboardGetState(keys); 233 234 // ToAscii() maps ctrl+letter to the corresponding control code 235 // and ctrl+backspace to delete. we don't want those translations 236 // so clear the control modifier state. however, if we want to 237 // simulate AltGr (which is ctrl+alt) then we must not clear it. 238 UINT control = keys[VK_CONTROL] | keys[VK_LCONTROL] | keys[VK_RCONTROL]; 239 UINT menu = keys[VK_MENU] | keys[VK_LMENU] | keys[VK_RMENU]; 240 if ((control & 0x80) == 0 || (menu & 0x80) == 0) { 241 keys[VK_LCONTROL] = 0; 242 keys[VK_RCONTROL] = 0; 243 keys[VK_CONTROL] = 0; 244 } 245 else { 246 keys[VK_LCONTROL] = 0x80; 247 keys[VK_RCONTROL] = 0x80; 248 keys[VK_CONTROL] = 0x80; 249 keys[VK_LMENU] = 0x80; 250 keys[VK_RMENU] = 0x80; 251 keys[VK_MENU] = 0x80; 252 } 253 254 // ToAscii() needs to know if a menu is active for some reason. 255 // we don't know and there doesn't appear to be any way to find 256 // out. so we'll just assume a menu is active if the menu key 257 // is down. 258 // FIXME -- figure out some way to check if a menu is active 259 UINT flags = 0; 260 if ((menu & 0x80) != 0) 261 flags |= 1; 262 263 // if we're on the server screen then just pass numpad keys with alt 264 // key down as-is. we won't pick up the resulting character but the 265 // local app will. if on a client screen then grab keys as usual; 266 // if the client is a windows system it'll synthesize the expected 267 // character. if not then it'll probably just do nothing. 268 if (g_mode != kHOOK_RELAY_EVENTS) { 269 // we don't use virtual keys because we don't know what the 270 // state of the numlock key is. we'll hard code the scan codes 271 // instead. hopefully this works across all keyboards. 272 UINT sc = (lParam & 0x01ff0000u) >> 16; 273 if (menu && 274 (sc >= 0x47u && sc <= 0x52u && sc != 0x4au && sc != 0x4eu)) { 275 return false; 276 } 277 } 278 279 // map the key event to a character. we have to put the dead 280 // key back first and this has the side effect of removing it. 281 if (g_deadVirtKey != 0) { 282 WORD c = 0; 283 ToAscii(g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, 284 g_deadKeyState, &c, flags); 285 } 286 WORD c = 0; 287 UINT scanCode = ((lParam & 0x10ff0000u) >> 16); 288 int n = ToAscii(wParam, scanCode, keys, &c, flags); 289 290 // if mapping failed and ctrl and alt are pressed then try again 291 // with both not pressed. this handles the case where ctrl and 292 // alt are being used as individual modifiers rather than AltGr. 293 // we note that's the case in the message sent back to synergy 294 // because there's no simple way to deduce it after the fact. 295 // we have to put the dead key back first, if there was one. 296 bool noAltGr = false; 297 if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) { 298 noAltGr = true; 299 PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 300 wParam | 0x05000000, lParam); 301 if (g_deadVirtKey != 0) { 302 ToAscii(g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, 303 g_deadKeyState, &c, flags); 304 } 305 BYTE keys2[256]; 306 for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { 307 keys2[i] = keys[i]; 308 } 309 keys2[VK_LCONTROL] = 0; 310 keys2[VK_RCONTROL] = 0; 311 keys2[VK_CONTROL] = 0; 312 keys2[VK_LMENU] = 0; 313 keys2[VK_RMENU] = 0; 314 keys2[VK_MENU] = 0; 315 n = ToAscii(wParam, scanCode, keys2, &c, flags); 316 } 317 318 PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 319 wParam | ((c & 0xff) << 8) | 320 ((n & 0xff) << 16) | 0x06000000, 321 lParam); 322 WPARAM charAndVirtKey = 0; 323 bool clearDeadKey = false; 324 switch (n) { 325 default: 326 // key is a dead key 327 g_deadVirtKey = wParam; 328 g_deadLParam = lParam; 329 for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { 330 g_deadKeyState[i] = keys[i]; 331 } 332 break; 333 334 case 0: 335 // key doesn't map to a character. this can happen if 336 // non-character keys are pressed after a dead key. 337 charAndVirtKey = makeKeyMsg(wParam, (char)0, noAltGr); 338 break; 339 340 case 1: 341 // key maps to a character composed with dead key 342 charAndVirtKey = makeKeyMsg(wParam, (char)LOBYTE(c), noAltGr); 343 clearDeadKey = true; 344 break; 345 346 case 2: { 347 // previous dead key not composed. send a fake key press 348 // and release for the dead key to our window. 349 WPARAM deadCharAndVirtKey = 350 makeKeyMsg(g_deadVirtKey, (char)LOBYTE(c), noAltGr); 351 PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, 352 deadCharAndVirtKey, g_deadLParam & 0x7fffffffu); 353 PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, 354 deadCharAndVirtKey, g_deadLParam | 0x80000000u); 355 356 // use uncomposed character 357 charAndVirtKey = makeKeyMsg(wParam, (char)HIBYTE(c), noAltGr); 358 clearDeadKey = true; 359 break; 360 } 361 } 362 363 // put back the dead key, if any, for the application to use 364 if (g_deadVirtKey != 0) { 365 ToAscii(g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, 366 g_deadKeyState, &c, flags); 367 } 368 369 // clear out old dead key state 370 if (clearDeadKey) { 371 g_deadVirtKey = 0; 372 g_deadLParam = 0; 373 } 374 375 // forward message to our window. do this whether or not we're 376 // forwarding events to clients because this'll keep our thread's 377 // key state table up to date. that's important for querying 378 // the scroll lock toggle state. 379 // XXX -- with hot keys for actions we may only need to do this when 380 // forwarding. 381 if (charAndVirtKey != 0) { 382 PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 383 charAndVirtKey | 0x07000000, lParam); 384 PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam); 385 } 386 387 if (g_mode == kHOOK_RELAY_EVENTS) { 388 // let certain keys pass through 389 switch (wParam) { 390 case VK_CAPITAL: 391 case VK_NUMLOCK: 392 case VK_SCROLL: 393 // pass event on. we want to let these through to 394 // the window proc because otherwise the keyboard 395 // lights may not stay synchronized. 396 break; 397 398 case VK_HANGUL: 399 // pass these modifiers if using a low level hook, discard 400 // them if not. 401 if (g_hookThread == 0) { 402 return true; 403 } 404 break; 405 406 default: 407 // discard 408 return true; 409 } 410 } 411 412 return false; 413 } 414 415 static 416 bool 417 keyboardHookHandler(WPARAM wParam, LPARAM lParam) 418 { 419 attachThreadToForeground(); 420 return doKeyboardHookHandler(wParam, lParam); 421 } 422 #endif 423 424 static 425 bool 426 doMouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) 427 { 428 switch (wParam) { 429 case WM_LBUTTONDOWN: 430 case WM_MBUTTONDOWN: 431 case WM_RBUTTONDOWN: 432 case WM_XBUTTONDOWN: 433 case WM_LBUTTONDBLCLK: 434 case WM_MBUTTONDBLCLK: 435 case WM_RBUTTONDBLCLK: 436 case WM_XBUTTONDBLCLK: 437 case WM_LBUTTONUP: 438 case WM_MBUTTONUP: 439 case WM_RBUTTONUP: 440 case WM_XBUTTONUP: 441 case WM_NCLBUTTONDOWN: 442 case WM_NCMBUTTONDOWN: 443 case WM_NCRBUTTONDOWN: 444 case WM_NCXBUTTONDOWN: 445 case WM_NCLBUTTONDBLCLK: 446 case WM_NCMBUTTONDBLCLK: 447 case WM_NCRBUTTONDBLCLK: 448 case WM_NCXBUTTONDBLCLK: 449 case WM_NCLBUTTONUP: 450 case WM_NCMBUTTONUP: 451 case WM_NCRBUTTONUP: 452 case WM_NCXBUTTONUP: 453 // always relay the event. eat it if relaying. 454 PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data); 455 return (g_mode == kHOOK_RELAY_EVENTS); 456 457 case WM_MOUSEWHEEL: 458 if (g_mode == kHOOK_RELAY_EVENTS) { 459 // relay event 460 PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0); 461 } 462 return (g_mode == kHOOK_RELAY_EVENTS); 463 464 case WM_NCMOUSEMOVE: 465 case WM_MOUSEMOVE: 466 if (g_mode == kHOOK_RELAY_EVENTS) { 467 // relay and eat event 468 PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); 469 return true; 470 } 471 else if (g_mode == kHOOK_WATCH_JUMP_ZONE) { 472 // low level hooks can report bogus mouse positions that are 473 // outside of the screen. jeez. naturally we end up getting 474 // fake motion in the other direction to get the position back 475 // on the screen, which plays havoc with switch on double tap. 476 // CServer deals with that. we'll clamp positions onto the 477 // screen. also, if we discard events for positions outside 478 // of the screen then the mouse appears to get a bit jerky 479 // near the edge. we can either accept that or pass the bogus 480 // events. we'll try passing the events. 481 bool bogus = false; 482 if (x < g_xScreen) { 483 x = g_xScreen; 484 bogus = true; 485 } 486 else if (x >= g_xScreen + g_wScreen) { 487 x = g_xScreen + g_wScreen - 1; 488 bogus = true; 489 } 490 if (y < g_yScreen) { 491 y = g_yScreen; 492 bogus = true; 493 } 494 else if (y >= g_yScreen + g_hScreen) { 495 y = g_yScreen + g_hScreen - 1; 496 bogus = true; 497 } 498 499 // check for mouse inside jump zone 500 bool inside = false; 501 if (!inside && (g_zoneSides & kLeftMask) != 0) { 502 inside = (x < g_xScreen + g_zoneSize); 503 } 504 if (!inside && (g_zoneSides & kRightMask) != 0) { 505 inside = (x >= g_xScreen + g_wScreen - g_zoneSize); 506 } 507 if (!inside && (g_zoneSides & kTopMask) != 0) { 508 inside = (y < g_yScreen + g_zoneSize); 509 } 510 if (!inside && (g_zoneSides & kBottomMask) != 0) { 511 inside = (y >= g_yScreen + g_hScreen - g_zoneSize); 512 } 513 514 // relay the event 515 PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); 516 517 // if inside and not bogus then eat the event 518 return inside && !bogus; 519 } 520 } 521 522 // pass the event 523 return false; 524 } 525 526 static 527 bool 528 mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) 529 { 530 // attachThreadToForeground(); 531 return doMouseHookHandler(wParam, x, y, data); 532 } 533 534 #if !NO_GRAB_KEYBOARD 535 static 536 LRESULT CALLBACK 537 keyboardHook(int code, WPARAM wParam, LPARAM lParam) 538 { 539 if (code >= 0) { 540 // handle the message 541 if (keyboardHookHandler(wParam, lParam)) { 542 return 1; 543 } 544 } 545 546 return CallNextHookEx(g_keyboard, code, wParam, lParam); 547 } 548 #endif 549 550 static 551 LRESULT CALLBACK 552 mouseHook(int code, WPARAM wParam, LPARAM lParam) 553 { 554 if (code >= 0) { 555 // decode message 556 const MOUSEHOOKSTRUCT* info = (const MOUSEHOOKSTRUCT*)lParam; 557 SInt32 x = (SInt32)info->pt.x; 558 SInt32 y = (SInt32)info->pt.y; 559 SInt32 w = 0; 560 if (wParam == WM_MOUSEWHEEL) { 561 // win2k and other systems supporting WM_MOUSEWHEEL in 562 // the mouse hook are gratuitously different (and poorly 563 // documented). if a low-level mouse hook is in place 564 // it should capture these events so we'll never see 565 // them. 566 switch (g_wheelSupport) { 567 case kWheelModern: 568 w = static_cast<SInt16>(LOWORD(info->dwExtraInfo)); 569 break; 570 571 case kWheelWin2000: { 572 const MOUSEHOOKSTRUCTWin2000* info2k = 573 (const MOUSEHOOKSTRUCTWin2000*)lParam; 574 w = static_cast<SInt16>(HIWORD(info2k->mouseData)); 575 break; 576 } 577 578 default: 579 break; 580 } 581 } 582 583 // handle the message. note that we don't handle X buttons 584 // here. that's okay because they're only supported on 585 // win2k and winxp and up and on those platforms we'll get 586 // get the mouse events through the low level hook. 587 if (mouseHookHandler(wParam, x, y, w)) { 588 return 1; 589 } 590 } 591 592 return CallNextHookEx(g_mouse, code, wParam, lParam); 593 } 594 595 static 596 LRESULT CALLBACK 597 getMessageHook(int code, WPARAM wParam, LPARAM lParam) 598 { 599 if (code >= 0) { 600 if (g_screenSaver) { 601 MSG* msg = reinterpret_cast<MSG*>(lParam); 602 if (msg->message == WM_SYSCOMMAND && 603 msg->wParam == SC_SCREENSAVE) { 604 // broadcast screen saver started message 605 PostThreadMessage(g_threadID, 606 SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); 607 } 608 } 609 if (g_mode == kHOOK_RELAY_EVENTS) { 610 MSG* msg = reinterpret_cast<MSG*>(lParam); 611 if (g_wheelSupport == kWheelOld && msg->message == g_wmMouseWheel) { 612 // post message to our window 613 PostThreadMessage(g_threadID, 614 SYNERGY_MSG_MOUSE_WHEEL, 615 static_cast<SInt16>(msg->wParam & 0xffffu), 0); 616 617 // zero out the delta in the message so it's (hopefully) 618 // ignored 619 msg->wParam = 0; 620 } 621 } 622 } 623 624 return CallNextHookEx(g_getMessage, code, wParam, lParam); 625 } 626 627 #if (_WIN32_WINNT >= 0x0400) && defined(_MSC_VER) && !NO_LOWLEVEL_HOOKS 628 629 // 630 // low-level keyboard hook -- this allows us to capture and handle 631 // alt+tab, alt+esc, ctrl+esc, and windows key hot keys. on the down 632 // side, key repeats are not reported to us. 633 // 634 635 #if !NO_GRAB_KEYBOARD 636 static 637 LRESULT CALLBACK 638 keyboardLLHook(int code, WPARAM wParam, LPARAM lParam) 639 { 640 if (code >= 0) { 641 // decode the message 642 KBDLLHOOKSTRUCT* info = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); 643 WPARAM wParam = info->vkCode; 644 LPARAM lParam = 1; // repeat code 645 lParam |= (info->scanCode << 16); // scan code 646 if (info->flags & LLKHF_EXTENDED) { 647 lParam |= (1lu << 24); // extended key 648 } 649 if (info->flags & LLKHF_ALTDOWN) { 650 lParam |= (1lu << 29); // context code 651 } 652 if (info->flags & LLKHF_UP) { 653 lParam |= (1lu << 31); // transition 654 } 655 // FIXME -- bit 30 should be set if key was already down but 656 // we don't know that info. as a result we'll never generate 657 // key repeat events. 658 659 // handle the message 660 if (keyboardHookHandler(wParam, lParam)) { 661 return 1; 662 } 663 } 664 665 return CallNextHookEx(g_keyboardLL, code, wParam, lParam); 666 } 667 #endif 668 669 // 670 // low-level mouse hook -- this allows us to capture and handle mouse 671 // events very early. the earlier the better. 672 // 673 674 static 675 LRESULT CALLBACK 676 mouseLLHook(int code, WPARAM wParam, LPARAM lParam) 677 { 678 if (code >= 0) { 679 // decode the message 680 MSLLHOOKSTRUCT* info = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam); 681 SInt32 x = static_cast<SInt32>(info->pt.x); 682 SInt32 y = static_cast<SInt32>(info->pt.y); 683 SInt32 w = static_cast<SInt16>(HIWORD(info->mouseData)); 684 685 // handle the message 686 if (mouseHookHandler(wParam, x, y, w)) { 687 return 1; 688 } 689 } 690 691 return CallNextHookEx(g_mouseLL, code, wParam, lParam); 692 } 693 694 #endif 695 696 static 697 EWheelSupport 698 getWheelSupport() 699 { 700 // get operating system 701 OSVERSIONINFO info; 702 info.dwOSVersionInfoSize = sizeof(info); 703 if (!GetVersionEx(&info)) { 704 return kWheelNone; 705 } 706 707 // see if modern wheel is present 708 if (GetSystemMetrics(SM_MOUSEWHEELPRESENT)) { 709 // note if running on win2k 710 if (info.dwPlatformId == VER_PLATFORM_WIN32_NT && 711 info.dwMajorVersion == 5 && 712 info.dwMinorVersion == 0) { 713 return kWheelWin2000; 714 } 715 return kWheelModern; 716 } 717 718 // not modern. see if we've got old-style support. 719 #if defined(MSH_WHEELSUPPORT) 720 UINT wheelSupportMsg = RegisterWindowMessage(MSH_WHEELSUPPORT); 721 HWND wheelSupportWindow = FindWindow(MSH_WHEELMODULE_CLASS, 722 MSH_WHEELMODULE_TITLE); 723 if (wheelSupportWindow != NULL && wheelSupportMsg != 0) { 724 if (SendMessage(wheelSupportWindow, wheelSupportMsg, 0, 0) != 0) { 725 g_wmMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL); 726 if (g_wmMouseWheel != 0) { 727 return kWheelOld; 728 } 729 } 730 } 731 #endif 732 733 // assume modern. we don't do anything special in this case 734 // except respond to WM_MOUSEWHEEL messages. GetSystemMetrics() 735 // can apparently return FALSE even if a mouse wheel is present 736 // though i'm not sure exactly when it does that (WinME returns 737 // FALSE for my logitech USB trackball). 738 return kWheelModern; 26 /** @name The synergy server/client thread 27 * @{ */ 28 extern HMQ g_hmqSynergy; 29 extern int g_pidSynergy; 30 extern int g_tidSynergy; 31 /** @} */ 32 33 /** The current mode.*/ 34 extern EHookMode volatile g_enmMode; 35 36 /** Which sides do we have warp zones on. */ 37 extern UInt32 g_zoneSides; 38 /** The warp zone size in pixels. */ 39 extern SInt32 g_zoneSize; 40 /** @name The screen size. 41 * @{ */ 42 extern SInt32 g_xScreen; 43 extern SInt32 g_yScreen; 44 extern SInt32 g_cxScreen; 45 extern SInt32 g_cyScreen; 46 /** @} */ 47 48 /** Set if the hook is installed. */ 49 extern bool g_fInputHookInstalled; 50 /** Set if we're faking input. */ 51 extern bool g_fFakingInput; 52 53 } /* extern "C" */ 54 55 56 // 57 // Globals - per process. 58 // 59 60 /** The handle of the hook dll. */ 61 static HMODULE g_hmod = NULLHANDLE; 62 /** The pid of the current process. */ 63 static int g_pid = 0; 64 65 66 /** 67 * Deal with keyboard messages. 68 * 69 * @param pQmsg The WM_CHAR message. 70 */ 71 static bool InputHookKeyboardMsg(PQMSG pQmsg) 72 { 73 /* 74 * Check for special events indicating if we should start or stop 75 * passing events through and not report them to the server. 76 * 77 * This is used to allow the server to synthesize events locally but 78 * not pick them up as user events. 79 */ 80 if (pQmsg->mp1 == SYNERGY_PM_HOOK_FAKE_INPUT_MP1_FIXED) { 81 if (pQmsg->mp2 == SYNERGY_PM_HOOK_FAKE_INPUT_MP2_SET) { 82 g_fFakingInput = true; 83 return true; 84 } 85 if (pQmsg->mp2 == SYNERGY_PM_HOOK_FAKE_INPUT_MP2_CLEAR) { 86 g_fFakingInput = false; 87 return true; 88 } 89 } 90 91 /* 92 * If we're expecting fake input then just pass the event through 93 * and do not forward to the server 94 */ 95 if (g_fFakingInput) 96 return false; 97 98 /* 99 * Send the key to the server without any more work. 100 * This is probably to simplified, but it'll have to do for now because I'm lazy. 101 */ 102 WinPostQueueMsg(g_hmqSynergy, SYNERGY_PM_MSG_KEY, pQmsg->mp1, pQmsg->mp2); 103 return true; 104 } 105 106 107 /** 108 * Checks if the specified mouse position is in a jump zone. 109 * 110 * @returns true if we're in the jump zone, false if we aren't 111 * @param x X coordinate. 112 * @param y Y coordinate. (1st quadrant) 113 */ 114 static bool isInJumpZone(SInt32 x, SInt32 y) 115 { 116 /* any jump zones at all? */ 117 if (g_zoneSides == 0) 118 return false; 119 120 /* 121 * Normalize the coordinates. 122 */ 123 bool fBogus = false; 124 if (x < g_xScreen) { 125 x = g_xScreen; 126 fBogus = true; 127 } else if (x >= g_xScreen + g_cxScreen) { 128 x = g_xScreen + g_cxScreen - 1; 129 fBogus = true; 130 } 131 132 if (y < g_yScreen) { 133 y = g_yScreen; 134 fBogus = true; 135 } else if (y >= g_yScreen + g_cyScreen) { 136 y = g_yScreen + g_cyScreen - 1; 137 fBogus = true; 138 } 139 140 /* 141 * check if the mouse is in any of the jump zones. 142 */ 143 bool fJump = false; 144 if (g_zoneSides & kLeftMask) 145 fJump |= (unsigned)x - (unsigned)g_xScreen < (unsigned)g_zoneSize; 146 if (g_zoneSides & kRightMask) 147 fJump |= (unsigned)(g_xScreen + g_cxScreen) - (unsigned)x < (unsigned)g_zoneSize; 148 if (g_zoneSides & kTopMask) 149 fJump |= (unsigned)(g_yScreen + g_cyScreen) - (unsigned)y < (unsigned)g_zoneSize; 150 if (g_zoneSides & kBottomMask) 151 fJump |= (unsigned)y - (unsigned)(g_yScreen) < (unsigned)g_zoneSize; 152 153 return fJump && !fBogus; 154 } 155 156 157 /** 158 * The input hook procedure (any context). 159 * 160 * @returns Processed indicator; TRUE if processed and should be discarded, FALSE if should be passed on. 161 * 162 * @param hab The anchor block of the current thread. 163 * @param pQmsg The message structure containing the message we're called for. 164 * @param fs The removal options (PM_REMOVE / PM_NOREMOVE). 165 */ 166 BOOL EXPENTRY InputHook(HAB hab, PQMSG pQmsg, ULONG fs) 167 { 168 /* 169 * Get hook mode and check if it's enabled. 170 */ 171 const EHookMode enmMode = g_enmMode; 172 if (enmMode == kHOOK_DISABLE) 173 return FALSE; 174 175 176 switch (pQmsg->msg) { 177 /* 178 * Keyboard message. 179 */ 180 case WM_CHAR: 181 if (enmMode == kHOOK_RELAY_EVENTS) 182 return InputHookKeyboardMsg(pQmsg); 183 break; 184 185 /* 186 * Mouse message. 187 */ 188 case WM_MOUSEMOVE: 189 if ( enmMode == kHOOK_RELAY_EVENTS 190 || enmMode == kHOOK_WATCH_JUMP_ZONE) { 191 WinPostQueueMsg(g_hmqSynergy, SYNERGY_PM_MSG_MOUSE_MOVE, MPFROM2SHORT(pQmsg->msg, 0), MPFROM2SHORT(pQmsg->ptl.x, pQmsg->ptl.y)); 192 return enmMode == kHOOK_RELAY_EVENTS 193 || isInJumpZone(pQmsg->ptl.x, pQmsg->ptl.y); 194 } 195 break; 196 197 /* 198 * Mouse click message. 199 */ 200 case WM_BUTTON1DOWN: 201 case WM_BUTTON1UP: 202 case WM_BUTTON1DBLCLK: 203 case WM_BUTTON2DOWN: 204 case WM_BUTTON2UP: 205 case WM_BUTTON2DBLCLK: 206 case WM_BUTTON3DOWN: 207 case WM_BUTTON3UP: 208 case WM_BUTTON3DBLCLK: 209 if ( enmMode == kHOOK_RELAY_EVENTS 210 || enmMode == kHOOK_WATCH_JUMP_ZONE) { 211 WinPostQueueMsg(g_hmqSynergy, SYNERGY_PM_MSG_MOUSE_BUTTON, MPFROM2SHORT(pQmsg->msg, 0), MPFROM2SHORT(pQmsg->ptl.x, pQmsg->ptl.y)); 212 return enmMode == kHOOK_RELAY_EVENTS; 213 } 214 break; 215 216 /* 217 * If I understand it correctly these messages are created 218 * from the ones above and should be discarded. (If I'm wrong, 219 * we'll not be able to drag stuff or open the window list.) 220 */ 221 case WM_CHORD: 222 case WM_BUTTON1MOTIONSTART: 223 case WM_BUTTON1MOTIONEND: 224 case WM_BUTTON1CLICK: 225 case WM_BUTTON2MOTIONSTART: 226 case WM_BUTTON2MOTIONEND: 227 case WM_BUTTON2CLICK: 228 case WM_BUTTON3MOTIONSTART: 229 case WM_BUTTON3MOTIONEND: 230 case WM_BUTTON3CLICK: 231 if (enmMode == kHOOK_RELAY_EVENTS) { 232 return true; 233 } 234 break; 235 236 default: 237 // log these. 238 break; 239 } 240 241 /* don't eat it. */ 242 return false; 739 243 } 740 244 … … 744 248 // 745 249 746 BOOL WINAPI 747 DllMain(HINSTANCE instance, DWORD reason, LPVOID) 748 { 749 if (reason == DLL_PROCESS_ATTACH) { 750 DisableThreadLibraryCalls(instance); 751 if (g_processID == 0) { 752 g_hinstance = instance; 753 g_processID = GetCurrentProcessId(); 754 } 755 } 756 else if (reason == DLL_PROCESS_DETACH) { 757 if (g_processID == GetCurrentProcessId()) { 758 uninstall(); 759 uninstallScreenSaver(); 760 g_processID = 0; 761 g_hinstance = NULL; 762 } 763 } 764 return TRUE; 765 } 766 767 extern "C" { 768 769 int 770 init(DWORD threadID) 771 { 772 assert(g_hinstance != NULL); 773 774 // try to open process that last called init() to see if it's 775 // still running or if it died without cleaning up. 776 if (g_processID != 0 && g_processID != GetCurrentProcessId()) { 777 HANDLE process = OpenProcess(STANDARD_RIGHTS_REQUIRED, 778 FALSE, g_processID); 779 if (process != NULL) { 780 // old process (probably) still exists so refuse to 781 // reinitialize this DLL (and thus steal it from the 782 // old process). 783 CloseHandle(process); 784 return 0; 785 } 786 787 // clean up after old process. the system should've already 788 // removed the hooks so we just need to reset our state. 789 g_hinstance = GetModuleHandle("synrgyhk"); 790 g_processID = GetCurrentProcessId(); 791 g_wheelSupport = kWheelNone; 792 g_threadID = 0; 793 g_keyboard = NULL; 794 g_mouse = NULL; 795 g_getMessage = NULL; 796 g_keyboardLL = NULL; 797 g_mouseLL = NULL; 798 g_screenSaver = false; 799 } 800 801 // save thread id. we'll post messages to this thread's 802 // message queue. 803 g_threadID = threadID; 804 805 // set defaults 806 g_mode = kHOOK_DISABLE; 807 g_zoneSides = 0; 808 g_zoneSize = 0; 809 g_xScreen = 0; 810 g_yScreen = 0; 811 g_wScreen = 0; 812 g_hScreen = 0; 813 814 return 1; 815 } 816 817 int 818 cleanup(void) 819 { 820 assert(g_hinstance != NULL); 821 822 if (g_processID == GetCurrentProcessId()) { 823 g_threadID = 0; 824 } 825 826 return 1; 827 } 828 829 EHookResult 830 install() 831 { 832 assert(g_hinstance != NULL); 833 assert(g_keyboard == NULL); 834 assert(g_mouse == NULL); 835 assert(g_getMessage == NULL || g_screenSaver); 836 837 // must be initialized 838 if (g_threadID == 0) { 839 return kHOOK_FAILED; 840 } 841 842 // discard old dead keys 843 g_deadVirtKey = 0; 844 g_deadLParam = 0; 845 846 // reset fake input flag 847 g_fakeInput = false; 848 849 // check for mouse wheel support 850 g_wheelSupport = getWheelSupport(); 851 852 // install GetMessage hook (unless already installed) 853 if (g_wheelSupport == kWheelOld && g_getMessage == NULL) { 854 g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, 855 &getMessageHook, 856 g_hinstance, 857 0); 858 } 859 860 // install low-level hooks. we require that they both get installed. 861 #if (_WIN32_WINNT >= 0x0400) && defined(_MSC_VER) && !NO_LOWLEVEL_HOOKS 862 g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL, 863 &mouseLLHook, 864 g_hinstance, 865 0); 866 #if !NO_GRAB_KEYBOARD 867 g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL, 868 &keyboardLLHook, 869 g_hinstance, 870 0); 871 if (g_mouseLL == NULL || g_keyboardLL == NULL) { 872 if (g_keyboardLL != NULL) { 873 UnhookWindowsHookEx(g_keyboardLL); 874 g_keyboardLL = NULL; 875 } 876 if (g_mouseLL != NULL) { 877 UnhookWindowsHookEx(g_mouseLL); 878 g_mouseLL = NULL; 879 } 880 } 881 #endif 882 #endif 883 884 // install regular hooks 885 if (g_mouseLL == NULL) { 886 g_mouse = SetWindowsHookEx(WH_MOUSE, 887 &mouseHook, 888 g_hinstance, 889 0); 890 } 891 #if !NO_GRAB_KEYBOARD 892 if (g_keyboardLL == NULL) { 893 g_keyboard = SetWindowsHookEx(WH_KEYBOARD, 894 &keyboardHook, 895 g_hinstance, 896 0); 897 } 898 #endif 899 900 // check that we got all the hooks we wanted 901 if ((g_getMessage == NULL && g_wheelSupport == kWheelOld) || 902 #if !NO_GRAB_KEYBOARD 903 (g_keyboardLL == NULL && g_keyboard == NULL) || 904 #endif 905 (g_mouseLL == NULL && g_mouse == NULL)) { 906 uninstall(); 907 return kHOOK_FAILED; 908 } 909 910 if (g_keyboardLL != NULL || g_mouseLL != NULL) { 911 g_hookThread = GetCurrentThreadId(); 912 return kHOOK_OKAY_LL; 913 } 914 915 return kHOOK_OKAY; 916 } 917 918 int 919 uninstall(void) 920 { 921 assert(g_hinstance != NULL); 922 923 // discard old dead keys 924 g_deadVirtKey = 0; 925 g_deadLParam = 0; 926 927 // detach from thread 928 detachThread(); 929 930 // uninstall hooks 931 if (g_keyboardLL != NULL) { 932 UnhookWindowsHookEx(g_keyboardLL); 933 g_keyboardLL = NULL; 934 } 935 if (g_mouseLL != NULL) { 936 UnhookWindowsHookEx(g_mouseLL); 937 g_mouseLL = NULL; 938 } 939 if (g_keyboard != NULL) { 940 UnhookWindowsHookEx(g_keyboard); 941 g_keyboard = NULL; 942 } 943 if (g_mouse != NULL) { 944 UnhookWindowsHookEx(g_mouse); 945 g_mouse = NULL; 946 } 947 if (g_getMessage != NULL && !g_screenSaver) { 948 UnhookWindowsHookEx(g_getMessage); 949 g_getMessage = NULL; 950 } 951 g_wheelSupport = kWheelNone; 952 953 return 1; 954 } 955 956 int 957 installScreenSaver(void) 958 { 959 assert(g_hinstance != NULL); 960 961 // must be initialized 962 if (g_threadID == 0) { 963 return 0; 964 } 965 966 // generate screen saver messages 967 g_screenSaver = true; 968 969 // install hook unless it's already installed 970 if (g_getMessage == NULL) { 971 g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, 972 &getMessageHook, 973 g_hinstance, 974 0); 975 } 976 977 return (g_getMessage != NULL) ? 1 : 0; 978 } 979 980 int 981 uninstallScreenSaver(void) 982 { 983 assert(g_hinstance != NULL); 984 985 // uninstall hook unless the mouse wheel hook is installed 986 if (g_getMessage != NULL && g_wheelSupport != kWheelOld) { 987 UnhookWindowsHookEx(g_getMessage); 988 g_getMessage = NULL; 989 } 990 991 // screen saver hook is no longer installed 992 g_screenSaver = false; 993 994 return 1; 995 } 996 997 void 998 setSides(UInt32 sides) 999 { 1000 g_zoneSides = sides; 1001 } 1002 1003 void 1004 setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize) 1005 { 1006 g_zoneSize = jumpZoneSize; 1007 g_xScreen = x; 1008 g_yScreen = y; 1009 g_wScreen = w; 1010 g_hScreen = h; 1011 } 1012 1013 void 1014 setMode(EHookMode mode) 1015 { 1016 if (mode == g_mode) { 1017 // no change 1018 return; 1019 } 1020 g_mode = mode; 1021 } 1022 1023 } 250 /** 251 * The DLL init/term function. 252 */ 253 ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG ulReason) 254 { 255 switch (ulReason) { 256 /* init */ 257 case 0: 258 g_hmod = hmod; 259 g_pid = getpid(); 260 break; 261 262 /* term */ 263 case 1: 264 g_pid = 0; 265 g_hmod = NULLHANDLE; 266 break; 267 268 default: 269 break; 270 } 271 return TRUE; 272 } 273 274 275 276 /** 277 * Initialize the hook dll (shared data mainly) in the synergy context. 278 * 279 * @returns success indicator (true/false) 280 * @param hmqSynergy 281 * @param tidSynergy 282 * @param pidSynergy 283 */ 284 CSYNERGYHOOK_API bool init(HMQ hmqSynergy, int tidSynergy, int pidSynergy) 285 { 286 /* 287 * Check that there isn't any synergy instance already running. 288 * If the verification fails, we will take the place dead synergy instance. 289 */ 290 if ( g_pidSynergy 291 && g_tidSynergy 292 && DosVerifyPidTid(g_pidSynergy, g_tidSynergy) == NO_ERROR) 293 return false; 294 295 /* 296 * Initialize the globals. 297 */ 298 g_hmqSynergy = hmqSynergy; 299 g_pidSynergy = pidSynergy; 300 g_tidSynergy = tidSynergy; 301 302 /* only do this if the hook is inactive. */ 303 if (g_enmMode == kHOOK_DISABLE) { 304 g_enmMode = kHOOK_DISABLE; 305 g_zoneSides = 0; 306 g_zoneSize = 0; 307 g_xScreen = 0; 308 g_yScreen = 0; 309 g_cxScreen = 0; 310 g_cyScreen = 0; 311 } 312 313 return true; 314 } 315 316 317 /** 318 * Cleanup before unloading the dll (synergy context). 319 * 320 * @returns success indicator (true/false) 321 * @param hab The anchor block. 322 */ 323 CSYNERGYHOOK_API bool cleanup(HAB hab) 324 { 325 assert(g_hmod != NULLHANDLE); 326 327 /* 328 * If we're the synergy process or if it's dead, shut down everything. 329 */ 330 if ( ( g_pidSynergy != getpid() 331 || g_tidSynergy != _gettid()) 332 && DosVerifyPidTid(g_pidSynergy, g_tidSynergy) == NO_ERROR) 333 return false; 334 335 /* parnaoia */ 336 uninstall(hab); 337 338 g_hmqSynergy = NULLHANDLE; 339 g_pidSynergy = 0; 340 g_tidSynergy = 0; 341 return true; 342 } 343 344 345 CSYNERGYHOOK_API EHookResult install(HAB hab) 346 { 347 // must be initialized 348 if (g_tidSynergy == 0) { 349 return kHOOK_FAILED; 350 } 351 assert(g_pidSynergy == getpid()); 352 assert(g_tidSynergy == _gettid()); 353 354 //// discard old dead keys 355 //g_deadVirtKey = 0; 356 //g_deadLParam = 0; 357 358 //// reset fake input flag 359 //g_fakeInput = false; 360 361 /* 362 * Install the hook. 363 */ 364 if ( !g_fInputHookInstalled 365 && WinSetHook(hab, NULLHANDLE, HK_INPUT, (PFN)InputHook, g_hmod)) 366 __atomic_xchg((unsigned volatile *)&g_fInputHookInstalled, true); 367 368 if (g_fInputHookInstalled) 369 return kHOOK_OKAY; 370 371 uninstall(hab); 372 return kHOOK_FAILED; 373 } 374 375 376 /** 377 * Uninstall the hooks. 378 * 379 * @returns 380 * @param hab 381 */ 382 CSYNERGYHOOK_API bool uninstall(HAB hab) 383 { 384 assert(g_pidSynergy == getpid()); 385 assert(g_tidSynergy == _gettid()); 386 387 //// discard old dead keys 388 //g_deadVirtKey = 0; 389 //g_deadLParam = 0; 390 391 /* 392 * Release the hooks. 393 */ 394 if ( g_fInputHookInstalled 395 && WinReleaseHook(hab, NULLHANDLE, HK_INPUT, (PFN)InputHook, g_hmod)) 396 __atomic_xchg((unsigned volatile *)&g_fInputHookInstalled, false); 397 398 return !g_fInputHookInstalled; 399 } 400 401 402 /** 403 * Sets the sides we should be watching out for jumps in. 404 * 405 * @param sides The new sides flags. 406 */ 407 CSYNERGYHOOK_API void setSides(UInt32 sides) 408 { 409 assert(g_pidSynergy == getpid()); 410 assert(g_tidSynergy == _gettid()); 411 __atomic_xchg((unsigned volatile *)&g_zoneSides, (unsigned)sides); 412 } 413 414 415 /** 416 * Set the jump zone size and screen size. 417 * 418 * @param x The screen x coordinate. 419 * @param y The screen y coordinate. 420 * @param cx The screen width. 421 * @param cy The screen heigth. 422 * @param jumpZoneSize The width of the jump zone (pixels). 423 */ 424 CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 cx, SInt32 cy, SInt32 jumpZoneSize) 425 { 426 assert(g_pidSynergy == getpid()); 427 assert(g_tidSynergy == _gettid()); 428 __atomic_xchg((unsigned volatile *)&g_zoneSize, (unsigned)jumpZoneSize); 429 __atomic_xchg((unsigned volatile *)&g_xScreen, (unsigned)x); 430 __atomic_xchg((unsigned volatile *)&g_yScreen, (unsigned)y); 431 __atomic_xchg((unsigned volatile *)&g_cxScreen, (unsigned)cx); 432 __atomic_xchg((unsigned volatile *)&g_cyScreen, (unsigned)cy); 433 } 434 435 436 /** 437 * Check the mode of operation. 438 * 439 * @param mode The new mode. 440 */ 441 CSYNERGYHOOK_API void setMode(EHookMode mode) 442 { 443 assert(g_pidSynergy == getpid()); 444 assert(g_tidSynergy == _gettid()); 445 if (mode != g_enmMode) { 446 switch (mode) { 447 case kHOOK_DISABLE: 448 case kHOOK_WATCH_JUMP_ZONE: 449 case kHOOK_RELAY_EVENTS: 450 __atomic_xchg((unsigned volatile *)&g_enmMode, (unsigned)mode); 451 break; 452 default: 453 __atomic_xchg((unsigned volatile *)&g_enmMode, kHOOK_DISABLE); 454 break; 455 } 456 } 457 } 458 -
trunk/synergy/lib/platform/CPMSynergyHook.h
r2752 r2755 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2002 Chris Schoeneman 4 * 4 * Copyright (C) 2006 Knut St. Osmundsen 5 * 5 6 * This package is free software; you can redistribute it and/or 6 7 * modify it under the terms of the GNU General Public License 7 8 * found in the file COPYING that should have accompanied this file. 8 * 9 * 9 10 * This package is distributed in the hope that it will be useful, 10 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 23 24 24 25 #if defined(SYNRGYHK_EXPORTS) 25 # define CSYNERGYHOOK_API __declspec(dllexport)26 # define CSYNERGYHOOK_API extern "C" __declspec(dllexport) 26 27 #else 27 # define CSYNERGYHOOK_API __declspec(dllimport)28 # define CSYNERGYHOOK_API extern "C" __declspec(dllimport) 28 29 #endif 29 30 30 #define SYNERGY_MSG_MARK WM_USER + 0x0011 // mark id; <unused> 31 #define SYNERGY_MSG_KEY WM_USER + 0x0012 // vk code; key data 32 #define SYNERGY_MSG_MOUSE_BUTTON WM_USER + 0x0013 // button msg; <unused> 33 #define SYNERGY_MSG_MOUSE_WHEEL WM_USER + 0x0014 // delta; <unused> 34 #define SYNERGY_MSG_MOUSE_MOVE WM_USER + 0x0015 // x; y 35 #define SYNERGY_MSG_POST_WARP WM_USER + 0x0016 // <unused>; <unused> 36 #define SYNERGY_MSG_PRE_WARP WM_USER + 0x0017 // x; y 37 #define SYNERGY_MSG_SCREEN_SAVER WM_USER + 0x0018 // activated; <unused> 38 #define SYNERGY_MSG_DEBUG WM_USER + 0x0019 // data, data 39 #define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY 40 #define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP 41 #define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_DEBUG 31 /** @name The messages posted from the input hook on the synergy message queue. 32 * @{ 33 */ 34 #define SYNERGY_PM_MSG_MARK WM_USER + 20 // mark id; <unused> 35 #define SYNERGY_PM_MSG_KEY WM_USER + 21 // vk code; key data 36 /** 37 * mp1.s1: msg 38 * mp1.s2: 0 reserved. 39 * mp2.s1: mouse x 40 * mp2.s2: mouse y 41 */ 42 #define SYNERGY_PM_MSG_MOUSE_BUTTON WM_USER + 22 43 /** WM_MOUSEMOVE mp1 and mp2. */ 44 #define SYNERGY_PM_MSG_MOUSE_MOVE WM_USER + 23 42 45 43 #define SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY VK_CANCEL 44 #define SYNERGY_HOOK_FAKE_INPUT_SCANCODE 0 46 #define SYNERGY_PM_MSG_POST_WARP WM_USER + 24 // <unused>; <unused> 47 #define SYNERGY_PM_MSG_PRE_WARP WM_USER + 25 // x; y 48 #define SYNERGY_PM_MSG_DEBUG WM_USER + 27 // data, data 45 49 46 extern "C" { 50 #define SYNERGY_PM_MSG_FIRST SYNERGY_PM_MSG_MARK /**< The first message. */ 51 #define SYNERGY_PM_MSG_LAST SYNERGY_PM_MSG_DEBUG /**< The last message. */ 52 #define SYNERGY_PM_MSG_INPUT_FIRST SYNERGY_PM_MSG_KEY /**< The first input message. */ 53 #define SYNERGY_PM_MSG_INPUT_LAST SYNERGY_PM_MSG_PRE_WARP /**< The last input message. */ 54 /** @} */ 55 56 #define SYNERGY_PM_HOOK_FAKE_INPUT_MP1_FIXED MPFROM2SHORT(KC_VIRTUALKEY | KC_SCANCODE, 0) 57 #define SYNERGY_PM_HOOK_FAKE_INPUT_MP2_SET MPFROM2SHORT(0x8f70, 0x708f) 58 #define SYNERGY_PM_HOOK_FAKE_INPUT_MP2_CLEAR MPFROM2SHORT(0x9f70, 0x708f) 47 59 48 60 enum EHookResult { 49 50 51 61 kHOOK_FAILED, 62 kHOOK_OKAY, 63 kHOOK_OKAY_LL 52 64 }; 53 65 54 66 enum EHookMode { 55 56 57 67 kHOOK_DISABLE, 68 kHOOK_WATCH_JUMP_ZONE, 69 kHOOK_RELAY_EVENTS 58 70 }; 59 71 60 typedef int (*InitFunc)(HMQ hmq, int tid, int pid); 61 typedef int (*CleanupFunc)(void); 62 typedef EHookResult (*InstallFunc)(void); 63 typedef int (*UninstallFunc)(void); 64 typedef int (*InstallScreenSaverFunc)(void); 65 typedef int (*UninstallScreenSaverFunc)(void); 66 typedef void (*SetSidesFunc)(UInt32); 67 typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32); 68 typedef void (*SetModeFunc)(int); 72 typedef bool (*InitFunc)(HMQ hmq, int tid, int pid); 73 typedef bool (*CleanupFunc)(HAB hab); 74 typedef EHookResult (*InstallFunc)(HAB hab); 75 typedef bool (*UninstallFunc)(HAB hab); 76 typedef void (*SetSidesFunc)(UInt32); 77 typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32); 78 typedef void (*SetModeFunc)(int); 69 79 70 CSYNERGYHOOK_API int init(HMQ hmq, int tid, int pid); 71 CSYNERGYHOOK_API int cleanup(void); 72 CSYNERGYHOOK_API EHookResult install(void); 73 CSYNERGYHOOK_API int uninstall(void); 74 CSYNERGYHOOK_API int installScreenSaver(void); 75 CSYNERGYHOOK_API int uninstallScreenSaver(void); 76 CSYNERGYHOOK_API void setSides(UInt32 sides); 77 CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 cx, SInt32 cy, SInt32 jumpZoneSize); 78 CSYNERGYHOOK_API void setMode(EHookMode mode); 79 80 } 80 CSYNERGYHOOK_API bool init(HMQ hmq, int tid, int pid); 81 CSYNERGYHOOK_API bool cleanup(HAB hab); 82 CSYNERGYHOOK_API EHookResult install(HAB hab); 83 CSYNERGYHOOK_API bool uninstall(HAB hab); 84 CSYNERGYHOOK_API void setSides(UInt32 sides); 85 CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 cx, SInt32 cy, SInt32 jumpZoneSize); 86 CSYNERGYHOOK_API void setMode(EHookMode mode); 81 87 82 88 #endif
Note:
See TracChangeset
for help on using the changeset viewer.