]> source.dussan.org Git - tigervnc.git/commitdiff
Respect modifiers in x0vncserver 496/head
authorPierre Ossman <ossman@cendio.se>
Wed, 16 Aug 2017 13:20:20 +0000 (15:20 +0200)
committerPierre Ossman <ossman@cendio.se>
Mon, 21 Aug 2017 10:04:33 +0000 (12:04 +0200)
Using XKeysymToKeycode() often gives the incorrect keycode as it
doesn't respect the current modifier state. Use XKB to find the
proper key instead.

This however also means that we need to track the mapping for all
pressed keys to make sure we know the correct keycode when it is
time to release the key.

unix/x0vncserver/x0vncserver.cxx

index 8f73ac2ce749557680da94841ccdfa321f007427..34713ea855523e4255c5f605b11c6fd5051c0856 100644 (file)
@@ -39,6 +39,7 @@
 #include <X11/X.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <X11/XKBlib.h>
 #ifdef HAVE_XTEST
 #include <X11/extensions/XTest.h>
 #endif
@@ -253,12 +254,61 @@ public:
 #endif
   }
 
+#ifdef HAVE_XTEST
+  KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
+    XkbDescPtr xkb;
+    XkbStateRec state;
+    unsigned keycode;
+
+    xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+    if (!xkb)
+      return 0;
+
+    XkbGetState(dpy, XkbUseCoreKbd, &state);
+
+    for (keycode = xkb->min_key_code;
+         keycode <= xkb->max_key_code;
+         keycode++) {
+      KeySym cursym;
+      unsigned int mods;
+      XkbTranslateKeyCode(xkb, keycode, state.compat_state, &mods, &cursym);
+      if (cursym == keysym)
+        break;
+    }
+
+    if (keycode > xkb->max_key_code)
+      keycode = 0;
+
+    XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
+
+    return keycode;
+  }
+#endif
+
   virtual void keyEvent(rdr::U32 key, bool down) {
 #ifdef HAVE_XTEST
-    if (!haveXtest) return;
-    int keycode = XKeysymToKeycode(dpy, key);
-    if (keycode)
-      XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
+    int keycode;
+
+    if (!haveXtest)
+      return;
+
+    if (down) {
+      if (pressedKeys.find(key) != pressedKeys.end())
+        keycode = pressedKeys[key];
+      else {
+        // XKeysymToKeycode() doesn't respect state, so we have to use
+        // something slightly more complex
+        keycode = XkbKeysymToKeycode(dpy, key);
+        if (!keycode)
+          return;
+        pressedKeys[key] = keycode;
+      }
+    } else {
+        keycode = pressedKeys[key];
+        pressedKeys.erase(key);
+    }
+
+    XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
 #endif
   }
 
@@ -301,6 +351,7 @@ protected:
   bool haveXtest;
   bool haveDamage;
   int maxButtons;
+  std::map<KeySym, KeyCode> pressedKeys;
   bool running;
 #ifdef HAVE_XDAMAGE
   Damage damage;