diff --git a/client/CMSWindowsSecondaryScreen.cpp b/client/CMSWindowsSecondaryScreen.cpp index c040479b..7bd1dee5 100644 --- a/client/CMSWindowsSecondaryScreen.cpp +++ b/client/CMSWindowsSecondaryScreen.cpp @@ -111,6 +111,9 @@ CMSWindowsSecondaryScreen::close() { assert(m_client != NULL); + // release keys that are logically pressed + releaseKeys(); + // restore the screen saver settings getScreenSaver()->enable(); @@ -1698,6 +1701,57 @@ CMSWindowsSecondaryScreen::doKeystrokes(const Keystrokes& keys, SInt32 count) } } +void +CMSWindowsSecondaryScreen::releaseKeys() +{ + CLock lock(&m_mutex); + + syncDesktop(); + + // release left/right modifier keys first. if the platform doesn't + // support them then they won't be set and the non-side-distinuishing + // key will retain its state. if the platform does support them then + // the non-side-distinguishing will be reset. + if ((m_keys[VK_LSHIFT] & 0x80) != 0) { + sendKeyEvent(VK_LSHIFT, false); + m_keys[VK_SHIFT] = 0; + m_keys[VK_LSHIFT] = 0; + } + if ((m_keys[VK_RSHIFT] & 0x80) != 0) { + sendKeyEvent(VK_RSHIFT, false); + m_keys[VK_SHIFT] = 0; + m_keys[VK_RSHIFT] = 0; + } + if ((m_keys[VK_LCONTROL] & 0x80) != 0) { + sendKeyEvent(VK_LCONTROL, false); + m_keys[VK_CONTROL] = 0; + m_keys[VK_LCONTROL] = 0; + } + if ((m_keys[VK_RCONTROL] & 0x80) != 0) { + sendKeyEvent(VK_RCONTROL, false); + m_keys[VK_CONTROL] = 0; + m_keys[VK_RCONTROL] = 0; + } + if ((m_keys[VK_LMENU] & 0x80) != 0) { + sendKeyEvent(VK_LMENU, false); + m_keys[VK_MENU] = 0; + m_keys[VK_LMENU] = 0; + } + if ((m_keys[VK_RMENU] & 0x80) != 0) { + sendKeyEvent(VK_RMENU, false); + m_keys[VK_MENU] = 0; + m_keys[VK_RMENU] = 0; + } + + // now check all the other keys + for (UInt32 i = 0; i < sizeof(m_keys) / sizeof(m_keys[0]); ++i) { + if ((m_keys[i] & 0x80) != 0) { + sendKeyEvent(i, false); + m_keys[i] = 0; + } + } +} + void CMSWindowsSecondaryScreen::updateKeys() { diff --git a/client/CMSWindowsSecondaryScreen.h b/client/CMSWindowsSecondaryScreen.h index e5a6452d..6db408f2 100644 --- a/client/CMSWindowsSecondaryScreen.h +++ b/client/CMSWindowsSecondaryScreen.h @@ -85,6 +85,7 @@ private: KeyModifierMask, EKeyAction) const; void doKeystrokes(const Keystrokes&, SInt32 count); + void releaseKeys(); void updateKeys(); void updateModifiers(); void toggleKey(UINT virtualKey, KeyModifierMask mask); diff --git a/client/CXWindowsSecondaryScreen.cpp b/client/CXWindowsSecondaryScreen.cpp index 4ae2c723..32eb1419 100644 --- a/client/CXWindowsSecondaryScreen.cpp +++ b/client/CXWindowsSecondaryScreen.cpp @@ -130,6 +130,9 @@ CXWindowsSecondaryScreen::close() { assert(m_client != NULL); + // release keys that are logically pressed + releaseKeys(); + // restore the screen saver settings getScreenSaver()->enable(); @@ -847,6 +850,24 @@ CXWindowsSecondaryScreen::maskToX(KeyModifierMask inMask) const return outMask; } +void +CXWindowsSecondaryScreen::releaseKeys() +{ + CDisplayLock display(this); + + // key up for each key that's down + for (UInt32 i = 0; i < 256; ++i) { + if (m_keys[i]) { + XTestFakeKeyEvent(display, i, False, CurrentTime); + m_keys[i] = false; + } + } + + // update + XSync(display, False); + +} + void CXWindowsSecondaryScreen::updateKeys(Display* display) { @@ -855,7 +876,7 @@ CXWindowsSecondaryScreen::updateKeys(Display* display) XQueryKeymap(display, keys); // transfer to our state - for (unsigned int i = 0, j = 0; i < 32; j += 8, ++i) { + for (UInt32 i = 0, j = 0; i < 32; j += 8, ++i) { m_keys[j + 0] = ((keys[i] & 0x01) != 0); m_keys[j + 1] = ((keys[i] & 0x02) != 0); m_keys[j + 2] = ((keys[i] & 0x04) != 0); diff --git a/client/CXWindowsSecondaryScreen.h b/client/CXWindowsSecondaryScreen.h index 0e07c4ea..44343d23 100644 --- a/client/CXWindowsSecondaryScreen.h +++ b/client/CXWindowsSecondaryScreen.h @@ -72,6 +72,7 @@ private: void doKeystrokes(const Keystrokes&, SInt32 count); unsigned int maskToX(KeyModifierMask) const; + void releaseKeys(); void updateKeys(Display* display); void updateKeycodeMap(Display* display); void updateModifiers(Display* display); diff --git a/synergy/ISecondaryScreen.h b/synergy/ISecondaryScreen.h index a31bc563..66fed53d 100644 --- a/synergy/ISecondaryScreen.h +++ b/synergy/ISecondaryScreen.h @@ -27,7 +27,10 @@ public: // stolen and screen size changed). virtual void open(CClient*) = 0; - // close the screen. should restore the screen saver. + // close the screen. should restore the screen saver. it should + // also simulate key up events for any keys that have simulate key + // down events without a matching key up. without this the client + // will leave its keyboard in the wrong logical state. virtual void close() = 0; // called when the user navigates to the secondary screen. warp