Skip to content

Commit

Permalink
Respect modifiers in x0vncserver
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
CendioOssman committed Aug 21, 2017
1 parent d698a6c commit ac73038
Showing 1 changed file with 55 additions and 4 deletions.
59 changes: 55 additions & 4 deletions unix/x0vncserver/x0vncserver.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -253,12 +254,61 @@ class XDesktop : public SDesktop, public TXGlobalEventHandler
#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
}

Expand Down Expand Up @@ -301,6 +351,7 @@ class XDesktop : public SDesktop, public TXGlobalEventHandler
bool haveXtest;
bool haveDamage;
int maxButtons;
std::map<KeySym, KeyCode> pressedKeys;
bool running;
#ifdef HAVE_XDAMAGE
Damage damage;
Expand Down

0 comments on commit ac73038

Please sign in to comment.