diff options
Diffstat (limited to 'common/rfb')
-rw-r--r-- | common/rfb/CConnection.cxx | 87 | ||||
-rw-r--r-- | common/rfb/CConnection.h | 20 |
2 files changed, 107 insertions, 0 deletions
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index 2c347710..5e7530c8 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -40,6 +40,10 @@ #include <rfb/CConnection.h> #include <rfb/util.h> +#define XK_MISCELLANY +#define XK_XKB_KEYS +#include <rfb/keysymdef.h> + #include <rfb/LogWriter.h> #include <rdr/InStream.h> @@ -695,6 +699,89 @@ void CConnection::sendClipboardData(const char* data) } } +void CConnection::sendKeyPress(int systemKeyCode, + uint32_t keyCode, uint32_t keySym) +{ + // For the first few years, there wasn't a good consensus on what the + // Windows keys should be mapped to for X11. So we need to help out a + // bit and map all variants to the same key... + switch (keySym) { + case XK_Hyper_L: + keySym = XK_Super_L; + break; + case XK_Hyper_R: + keySym = XK_Super_R; + break; + // There has been several variants for Shift-Tab over the years. + // RFB states that we should always send a normal tab. + case XK_ISO_Left_Tab: + keySym = XK_Tab; + break; + } + +#ifdef __APPLE__ + // Alt on OS X behaves more like AltGr on other systems, and to get + // sane behaviour we should translate things in that manner for the + // remote VNC server. However that means we lose the ability to use + // Alt as a shortcut modifier. Do what RealVNC does and hijack the + // left command key as an Alt replacement. + switch (keySym) { + case XK_Super_L: + keySym = XK_Alt_L; + break; + case XK_Super_R: + keySym = XK_Super_L; + break; + case XK_Alt_L: + keySym = XK_Mode_switch; + break; + case XK_Alt_R: + keySym = XK_ISO_Level3_Shift; + break; + } +#endif + + // Because of the way keyboards work, we cannot expect to have the same + // symbol on release as when pressed. This breaks the VNC protocol however, + // so we need to keep track of what keysym a key _code_ generated on press + // and send the same on release. + downKeys[systemKeyCode].keyCode = keyCode; + downKeys[systemKeyCode].keySym = keySym; + + vlog.debug("Key pressed: %d => 0x%02x / XK_%s (0x%04x)", + systemKeyCode, keyCode, KeySymName(keySym), keySym); + + writer()->writeKeyEvent(keySym, keyCode, true); +} + +void CConnection::sendKeyRelease(int systemKeyCode) +{ + DownMap::iterator iter; + + iter = downKeys.find(systemKeyCode); + if (iter == downKeys.end()) { + // These occur somewhat frequently so let's not spam them unless + // logging is turned up. + vlog.debug("Unexpected release of key code %d", systemKeyCode); + return; + } + + vlog.debug("Key released: %d => 0x%02x / XK_%s (0x%04x)", + systemKeyCode, iter->second.keyCode, + KeySymName(iter->second.keySym), iter->second.keySym); + + writer()->writeKeyEvent(iter->second.keySym, + iter->second.keyCode, false); + + downKeys.erase(iter); +} + +void CConnection::releaseAllKeys() +{ + while (!downKeys.empty()) + sendKeyRelease(downKeys.begin()->first); +} + void CConnection::refreshFramebuffer() { forceNonincremental = true; diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h index 9101bf26..07e47e39 100644 --- a/common/rfb/CConnection.h +++ b/common/rfb/CConnection.h @@ -24,6 +24,7 @@ #ifndef __RFB_CCONNECTION_H__ #define __RFB_CCONNECTION_H__ +#include <map> #include <string> #include <rfb/CMsgHandler.h> @@ -196,6 +197,18 @@ namespace rfb { // clipboard via handleClipboardRequest(). virtual void sendClipboardData(const char* data); + // sendKeyPress()/sendKeyRelease() send keyboard events to the + // server + void sendKeyPress(int systemKeyCode, uint32_t keyCode, uint32_t keySym); + void sendKeyRelease(int systemKeyCode); + + // releaseAllKeys() sends keyboard release events to the server for + // all keys that are currently pressed down by this client, + // avoiding keys getting stuck. This can be useful if the client + // loses keyboard focus or otherwise no longer gets keyboard events + // from the system. + void releaseAllKeys(); + // refreshFramebuffer() forces a complete refresh of the entire // framebuffer void refreshFramebuffer(); @@ -313,6 +326,13 @@ namespace rfb { bool hasRemoteClipboard; bool hasLocalClipboard; bool unsolicitedClipboardAttempt; + + struct DownKey { + uint32_t keyCode; + uint32_t keySym; + }; + typedef std::map<int, DownKey> DownMap; + DownMap downKeys; }; } #endif |