diff --git a/src/lib/platform/MSWindowsKeyState.cpp b/src/lib/platform/MSWindowsKeyState.cpp index 64900bb3..3bdb74eb 100644 --- a/src/lib/platform/MSWindowsKeyState.cpp +++ b/src/lib/platform/MSWindowsKeyState.cpp @@ -909,7 +909,10 @@ CMSWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const } for (KeyButton i = 1; i < 256; ++i) { if ((keyState[i] & 0x80) != 0) { - pressedKeys.insert(i); + KeyButton keyButton = virtualKeyToButton(i); + if (keyButton != 0) { + pressedKeys.insert(keyButton); + } } } } @@ -1344,6 +1347,12 @@ CMSWindowsKeyState::getKeyID(UINT virtualKey, KeyButton button) return s_virtualKey[virtualKey]; } +UINT +CMSWindowsKeyState::mapButtonToVirtualKey(KeyButton button) const +{ + return m_buttonToVK[button]; +} + KeyID CMSWindowsKeyState::getIDForKey(CKeyMap::KeyItem& item, KeyButton button, UINT virtualKey, diff --git a/src/lib/platform/MSWindowsKeyState.h b/src/lib/platform/MSWindowsKeyState.h index 27b992a2..abba89e9 100644 --- a/src/lib/platform/MSWindowsKeyState.h +++ b/src/lib/platform/MSWindowsKeyState.h @@ -124,6 +124,14 @@ public: */ static KeyID getKeyID(UINT virtualKey, KeyButton button); + //! Map button to virtual key + /*! + Returns the virtual key for button \p button + (button should include the extended key bit), or kKeyNone if there is + no such key. + */ + UINT mapButtonToVirtualKey(KeyButton button) const; + //@} // IKeyState overrides diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index 4ca81657..54ae63fb 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -46,6 +46,7 @@ #include #include #include +#include // // add backwards compatible multihead support (and suppress bogus warning). @@ -302,7 +303,10 @@ CMSWindowsScreen::enter() // all messages prior to now are invalid nextMark(); - } else { + + m_primaryKeyDownList.clear(); + } + else { // Entering a secondary screen. Ensure that no screensaver is active // and that the screen is not in powersave mode. CArchMiscWindows::wakeupDisplay(); @@ -351,6 +355,14 @@ CMSWindowsScreen::leave() m_keyState->saveModifiers(); m_hook.setMode(kHOOK_RELAY_EVENTS); + + m_primaryKeyDownList.clear(); + for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { + if (m_keyState->isKeyDown(i)) { + m_primaryKeyDownList.push_back(i); + LOG((CLOG_DEBUG1 "key button %d is down before leaving to another screen", i)); + } + } } // now off screen @@ -1137,6 +1149,18 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam) // record keyboard state m_keyState->onKey(button, down, oldState); + if (!down && m_isPrimary && !m_isOnScreen) { + PrimaryKeyDownList::iterator find = std::find(m_primaryKeyDownList.begin(), m_primaryKeyDownList.end(), button); + if (find != m_primaryKeyDownList.end()) { + LOG((CLOG_DEBUG1 "release key button %d on primary", *find)); + m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); + fakeLocalKey(*find, false); + m_primaryKeyDownList.erase(find); + m_hook.setMode(kHOOK_RELAY_EVENTS); + return true; + } + } + // windows doesn't tell us the modifier key state on mouse or key // events so we have to figure it out. most apps would use // GetKeyState() or even GetAsyncKeyState() for that but we can't @@ -1802,6 +1826,19 @@ CMSWindowsScreen::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return result; } +void +CMSWindowsScreen::fakeLocalKey(KeyButton button, bool press) const +{ + INPUT input; + input.type = INPUT_KEYBOARD; + input.ki.wVk = m_keyState->mapButtonToVirtualKey(button); + DWORD pressFlag = press ? KEYEVENTF_EXTENDEDKEY : KEYEVENTF_KEYUP; + input.ki.dwFlags = pressFlag; + input.ki.time = 0; + input.ki.dwExtraInfo = 0; + SendInput(1,&input,sizeof(input)); +} + // // CMSWindowsScreen::CHotKeyItem // diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h index 2a50503c..ab9db641 100644 --- a/src/lib/platform/MSWindowsScreen.h +++ b/src/lib/platform/MSWindowsScreen.h @@ -127,6 +127,9 @@ protected: virtual void updateButtons(); virtual IKeyState* getKeyState() const; + // simulate a local key to the system directly + void fakeLocalKey(KeyButton button, bool press) const; + private: // initialization and shutdown operations HCURSOR createBlankCursor() const; @@ -236,6 +239,7 @@ private: typedef std::map HotKeyMap; typedef std::vector HotKeyIDList; typedef std::map HotKeyToIDMap; + typedef std::vector PrimaryKeyDownList; static HINSTANCE s_windowInstance; @@ -335,4 +339,6 @@ private: const int m_dropWindowSize; CThread* m_sendDragThread; + + PrimaryKeyDownList m_primaryKeyDownList; }; diff --git a/src/lib/synergy/KeyState.cpp b/src/lib/synergy/KeyState.cpp index 9b4ac8ff..aad593be 100644 --- a/src/lib/synergy/KeyState.cpp +++ b/src/lib/synergy/KeyState.cpp @@ -903,7 +903,6 @@ CKeyState::updateModifierKeyState(KeyButton button, } } - // // CKeyState::CAddActiveModifierContext //