diff options
Diffstat (limited to 'vncviewer/KeyboardX11.cxx')
-rw-r--r-- | vncviewer/KeyboardX11.cxx | 113 |
1 files changed, 110 insertions, 3 deletions
diff --git a/vncviewer/KeyboardX11.cxx b/vncviewer/KeyboardX11.cxx index 8a91c2d0..587d9fc5 100644 --- a/vncviewer/KeyboardX11.cxx +++ b/vncviewer/KeyboardX11.cxx @@ -22,6 +22,7 @@ #include <assert.h> +#include <algorithm> #include <stdexcept> #include <X11/XKBlib.h> @@ -87,6 +88,32 @@ KeyboardX11::~KeyboardX11() { } +struct GrabInfo { + Window window; + bool found; +}; + +static Bool is_same_window(Display*, XEvent* event, XPointer arg) +{ + GrabInfo* info = (GrabInfo*)arg; + + assert(info); + + // Focus is returned to our window + if ((event->type == FocusIn) && + (event->xfocus.window == info->window)) { + info->found = true; + } + + // Focus got stolen yet again + if ((event->type == FocusOut) && + (event->xfocus.window == info->window)) { + info->found = false; + } + + return False; +} + bool KeyboardX11::isKeyboardReset(const void* event) { const XEvent* xevent = (const XEvent*)event; @@ -95,9 +122,22 @@ bool KeyboardX11::isKeyboardReset(const void* event) if (xevent->type == FocusOut) { if (xevent->xfocus.mode == NotifyGrab) { - // Something grabbed the keyboard, but we don't know who. Might be - // us, but might be the window manager. Be cautious and assume the - // latter and report that the keyboard state was reset. + GrabInfo info; + XEvent dummy; + + // Something grabbed the keyboard, but we don't know if it was to + // ourselves or someone else + + // Make sure we have all the queued events from the X server + XSync(fl_display, False); + + // Check if we'll get the focus back right away + info.window = xevent->xfocus.window; + info.found = false; + XCheckIfEvent(fl_display, &dummy, is_same_window, (XPointer)&info); + if (info.found) + return false; + return true; } } @@ -116,6 +156,10 @@ bool KeyboardX11::handleEvent(const void* event) char str; KeySym keysym; + // FLTK likes to use this instead of CurrentTime, so we need to keep + // it updated now that we steal this event + fl_event_time = xevent->xkey.time; + keycode = code_map_keycode_to_qnum[xevent->xkey.keycode]; XLookupString((XKeyEvent*)&xevent->xkey, &str, 1, &keysym, nullptr); @@ -127,6 +171,7 @@ bool KeyboardX11::handleEvent(const void* event) handler->handleKeyPress(xevent->xkey.keycode, keycode, keysym); return true; } else if (xevent->type == KeyRelease) { + fl_event_time = xevent->xkey.time; handler->handleKeyRelease(xevent->xkey.keycode); return true; } @@ -134,6 +179,31 @@ bool KeyboardX11::handleEvent(const void* event) return false; } +std::list<uint32_t> KeyboardX11::translateToKeySyms(int systemKeyCode) +{ + Status status; + XkbStateRec state; + std::list<uint32_t> keySyms; + unsigned char group; + + status = XkbGetState(fl_display, XkbUseCoreKbd, &state); + if (status != Success) + return keySyms; + + // Start with the currently used group + translateToKeySyms(systemKeyCode, state.group, &keySyms); + + // Then all other groups + for (group = 0; group < XkbNumKbdGroups; group++) { + if (group == state.group) + continue; + + translateToKeySyms(systemKeyCode, group, &keySyms); + } + + return keySyms; +} + unsigned KeyboardX11::getLEDState() { unsigned state; @@ -237,3 +307,40 @@ out: return mask; } + +void KeyboardX11::translateToKeySyms(int systemKeyCode, + unsigned char group, + std::list<uint32_t>* keySyms) +{ + unsigned int mods; + + // Start with no modifiers + translateToKeySyms(systemKeyCode, group, 0, keySyms); + + // Next just a single modifier at a time + for (mods = 1; mods < (Mod5Mask+1); mods <<= 1) + translateToKeySyms(systemKeyCode, group, mods, keySyms); + + // Finally everything + for (mods = 0; mods < (Mod5Mask<<1); mods++) + translateToKeySyms(systemKeyCode, group, mods, keySyms); +} + +void KeyboardX11::translateToKeySyms(int systemKeyCode, + unsigned char group, + unsigned char mods, + std::list<uint32_t>* keySyms) +{ + KeySym ks; + std::list<uint32_t>::const_iterator iter; + + ks = XkbKeycodeToKeysym(fl_display, systemKeyCode, group, mods); + if (ks == NoSymbol) + return; + + iter = std::find(keySyms->begin(), keySyms->end(), ks); + if (iter != keySyms->end()) + return; + + keySyms->push_back(ks); +} |