From e267d1dc1cb3d15dac350f566e034756ee51e2e7 Mon Sep 17 00:00:00 2001 From: crs Date: Mon, 1 Jul 2002 13:03:16 +0000 Subject: [PATCH] now synthesizing key release events for each pressed key when the client screen is closed. this fixes the bug where the client's keyboard was left with some keys logically pressed when the client died (e.g. using ctrl+c on the client program from the server's keyboard would leave the ctrl key logically pressed). --- client/CMSWindowsSecondaryScreen.cpp | 54 ++++++++++++++++++++++++++++ client/CMSWindowsSecondaryScreen.h | 1 + client/CXWindowsSecondaryScreen.cpp | 23 +++++++++++- client/CXWindowsSecondaryScreen.h | 1 + synergy/ISecondaryScreen.h | 5 ++- 5 files changed, 82 insertions(+), 2 deletions(-) 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