Respect modifiers in x0vncserver
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.
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index 8f73ac2..34713ea 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -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 @@
#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 @@
bool haveXtest;
bool haveDamage;
int maxButtons;
+ std::map<KeySym, KeyCode> pressedKeys;
bool running;
#ifdef HAVE_XDAMAGE
Damage damage;