From e61097b8881bc7e72a5499816cb1199ea274a3ca Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Thu, 7 Oct 2010 22:54:10 +0200 Subject: Rework template meta-magic - No more implicit dependency on Boost.MPL - Better documentation for template magic - Move input handler policies to handler definitions where they belong - Separate out event descriptions from handlers --- src/input/x11FakeKeyboardHandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/input/x11FakeKeyboardHandler.cpp') diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index 0c32b66..eab4498 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -807,7 +807,7 @@ void X11FakeKeyboardHandler::initialize() current_modifiers = 0; } -void X11FakeKeyboardHandler::handle(InputEvent const& evt, InputEventContext const*) +void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext const*) { Display* dpy = X11InputUtils::display(); @@ -818,7 +818,7 @@ void X11FakeKeyboardHandler::handle(InputEvent const& evt, InputEventContext con switch(evt.qt_keysym()) { case Qt::Key_Backtab: - handle(InputEvent(evt.type(), evt.code(), evt.qt_modifiers() | Qt::ShiftModifier | Qt::Key_Tab)); + doHandle(InputEvent(evt.type(), evt.code(), evt.qt_modifiers() | Qt::ShiftModifier | Qt::Key_Tab)); break; default: ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qt_keysym(), 8, 16)); -- cgit v1.2.3-55-g7522 From 1233d9c40fdf20b2c5157eee89d995817b0c1c3b Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:33:59 +0200 Subject: Code cleanup for X11FakeKeyboardHandler.cpp - CamelCase names - Add more comments - Remove unused stuff --- src/input/x11FakeKeyboardHandler.cpp | 409 ++++++++++++++++------------------- 1 file changed, 184 insertions(+), 225 deletions(-) (limited to 'src/input/x11FakeKeyboardHandler.cpp') diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index eab4498..a136e45 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -9,7 +9,7 @@ # # General information about OpenSLX can be found at http://openslx.org/ # -------------------------------------------------------------------------- - # x11FakeKeyboardHandler.h: + # x11FakeKeyboardHandler.cpp: # - Handle keyboard events on X11 - interface # -------------------------------------------------------------------------- */ @@ -36,10 +36,10 @@ #include #include "x11InputUtils.h" -//////////////////////// INPUT EVENT TRANSLATION ///////////////////////////////// - -typedef unsigned char xmodifier_type; +// X11 supports 8 modifiers, so a bitmask of modifiers fits into a byte: +typedef unsigned char XModifiers; +// For debugging output, these are the names of modifier keys: char modifiernames[][8] = { "SHIFT", "LOCK", @@ -51,7 +51,7 @@ char modifiernames[][8] = { "MOD5" }; -QString modifiers_to_string(xmodifier_type mods) +QString modifiersToString(XModifiers mods) { QString s; for(int i = 0; i < 8; i++) @@ -66,15 +66,22 @@ QString modifiers_to_string(xmodifier_type mods) return s; } +///////////////////////////////////////////////////////////////////////// +// Input event translation code +///////////////////////////////////////////////////////////////////////// + +// We need to translate between Qt's keycodes and X11's keycodes. +// Unfortunately, there does not seem to be a direct correspondence +// between them, so we are stuck with storing a lookup table: +typedef std::map KeycodeLookupTable; +KeycodeLookupTable keysyms; -typedef std::map lookup_table_type; -typedef lookup_table_type::const_iterator lookup_table_const_iterator; -typedef lookup_table_type::iterator lookup_table_iterator; -lookup_table_type keysyms; -void initialize_keysyms() { +// The following code has been partially autogenerated by +// an insane sed(1) script and then hand-edited to make +// the errors go away. +void initializeKeycodeLookupTable() { keysyms[Qt::Key_Escape] = XK_Escape; keysyms[Qt::Key_Tab] = XK_Tab; -// keysyms[Qt::Key_Backtab] = XK_Backtab; keysyms[Qt::Key_Backspace] = XK_BackSpace; keysyms[Qt::Key_Return] = XK_Return; keysyms[Qt::Key_Enter] = XK_KP_Enter; @@ -140,8 +147,6 @@ void initialize_keysyms() { keysyms[Qt::Key_Hyper_L] = XK_Hyper_L; keysyms[Qt::Key_Hyper_R] = XK_Hyper_R; keysyms[Qt::Key_Help] = XK_Help; -// keysyms[Qt::Key_Direction_L] = XK_Direction_L; -// keysyms[Qt::Key_Direction_R] = XK_Direction_R; keysyms[Qt::Key_Space] = XK_space; keysyms[Qt::Key_Exclam] = XK_exclam; keysyms[Qt::Key_QuoteDbl] = XK_quotedbl; @@ -314,10 +319,8 @@ void initialize_keysyms() { keysyms[Qt::Key_MultipleCandidate] = XK_MultipleCandidate; keysyms[Qt::Key_PreviousCandidate] = XK_PreviousCandidate; keysyms[Qt::Key_Mode_switch] = XK_Mode_switch; -// keysyms[Qt::Key_script_switch] = XK_script_switch; keysyms[Qt::Key_Kanji] = XK_Kanji; keysyms[Qt::Key_Muhenkan] = XK_Muhenkan; -// keysyms[Qt::Key_Henkan_Mode] = XK_Henkan_Mode; keysyms[Qt::Key_Henkan] = XK_Henkan; keysyms[Qt::Key_Romaji] = XK_Romaji; keysyms[Qt::Key_Hiragana] = XK_Hiragana; @@ -332,9 +335,6 @@ void initialize_keysyms() { keysyms[Qt::Key_Kana_Shift] = XK_Kana_Shift; keysyms[Qt::Key_Eisu_Shift] = XK_Eisu_Shift; keysyms[Qt::Key_Eisu_toggle] = XK_Eisu_toggle; -// keysyms[Qt::Key_Kanji_Bangou] = XK_Kanji_Bangou; -// keysyms[Qt::Key_Zen_Koho] = XK_Zen_Koho; -// keysyms[Qt::Key_Mae_Koho] = XK_Mae_Koho; keysyms[Qt::Key_Hangul] = XK_Hangul; keysyms[Qt::Key_Hangul_Hanja] = XK_Hangul_Hanja; keysyms[Qt::Key_Hangul] = XK_Hangul; @@ -343,16 +343,11 @@ void initialize_keysyms() { keysyms[Qt::Key_Hangul_Hanja] = XK_Hangul_Hanja; keysyms[Qt::Key_Hangul_Jamo] = XK_Hangul_Jamo; keysyms[Qt::Key_Hangul_Romaja] = XK_Hangul_Romaja; -// keysyms[Qt::Key_Hangul_Codeinput] = XK_Hangul_Codeinput; keysyms[Qt::Key_Hangul_Jeonja] = XK_Hangul_Jeonja; keysyms[Qt::Key_Hangul_Banja] = XK_Hangul_Banja; keysyms[Qt::Key_Hangul_PreHanja] = XK_Hangul_PreHanja; keysyms[Qt::Key_Hangul_PostHanja] = XK_Hangul_PostHanja; -// keysyms[Qt::Key_Hangul_SingleCandidate] = XK_Hangul_SingleCandidate; -// keysyms[Qt::Key_Hangul_MultipleCandidate] = XK_Hangul_MultipleCandidate; -// keysyms[Qt::Key_Hangul_PreviousCandidate] = XK_Hangul_PreviousCandidate; keysyms[Qt::Key_Hangul_Special] = XK_Hangul_Special; -// keysyms[Qt::Key_Hangul_switch] = XK_Hangul_switch; keysyms[Qt::Key_Dead_Grave] = XK_dead_grave; keysyms[Qt::Key_Dead_Acute] = XK_dead_acute; keysyms[Qt::Key_Dead_Circumflex] = XK_dead_circumflex; @@ -372,94 +367,33 @@ void initialize_keysyms() { keysyms[Qt::Key_Dead_Belowdot] = XK_dead_belowdot; keysyms[Qt::Key_Dead_Hook] = XK_dead_hook; keysyms[Qt::Key_Dead_Horn] = XK_dead_horn; -// keysyms[Qt::Key_Back] = XK_Back; -// keysyms[Qt::Key_Forward] = XK_Forward; -// keysyms[Qt::Key_Stop] = XK_Stop; -// keysyms[Qt::Key_Refresh] = XK_Refresh; -// keysyms[Qt::Key_VolumeDown] = XK_VolumeDown; -// keysyms[Qt::Key_VolumeMute] = XK_VolumeMute; -// keysyms[Qt::Key_VolumeUp] = XK_VolumeUp; -// keysyms[Qt::Key_BassBoost] = XK_BassBoost; -// keysyms[Qt::Key_BassUp] = XK_BassUp; -// keysyms[Qt::Key_BassDown] = XK_BassDown; -// keysyms[Qt::Key_TrebleUp] = XK_TrebleUp; -// keysyms[Qt::Key_TrebleDown] = XK_TrebleDown; -// keysyms[Qt::Key_MediaPlay] = XK_MediaPlay; -// keysyms[Qt::Key_MediaStop] = XK_MediaStop; -// keysyms[Qt::Key_MediaPrevious] = XK_MediaPrevious; -// keysyms[Qt::Key_MediaNext] = XK_MediaNext; -// keysyms[Qt::Key_MediaRecord] = XK_MediaRecord; -// keysyms[Qt::Key_HomePage] = XK_HomePage; -// keysyms[Qt::Key_Favorites] = XK_Favorites; -// keysyms[Qt::Key_Search] = XK_Search; -// keysyms[Qt::Key_Standby] = XK_Standby; -// keysyms[Qt::Key_OpenUrl] = XK_OpenUrl; -// keysyms[Qt::Key_LaunchMail] = XK_LaunchMail; -// keysyms[Qt::Key_LaunchMedia] = XK_LaunchMedia; -// keysyms[Qt::Key_Launch0] = XK_Launch0; -// keysyms[Qt::Key_Launch1] = XK_Launch1; -// keysyms[Qt::Key_Launch2] = XK_Launch2; -// keysyms[Qt::Key_Launch3] = XK_Launch3; -// keysyms[Qt::Key_Launch4] = XK_Launch4; -// keysyms[Qt::Key_Launch5] = XK_Launch5; -// keysyms[Qt::Key_Launch6] = XK_Launch6; -// keysyms[Qt::Key_Launch7] = XK_Launch7; -// keysyms[Qt::Key_Launch8] = XK_Launch8; -// keysyms[Qt::Key_Launch9] = XK_Launch9; -// keysyms[Qt::Key_LaunchA] = XK_LaunchA; -// keysyms[Qt::Key_LaunchB] = XK_LaunchB; -// keysyms[Qt::Key_LaunchC] = XK_LaunchC; -// keysyms[Qt::Key_LaunchD] = XK_LaunchD; -// keysyms[Qt::Key_LaunchE] = XK_LaunchE; -// keysyms[Qt::Key_LaunchF] = XK_LaunchF; -// keysyms[Qt::Key_Display] = XK_Display; -// keysyms[Qt::Key_MediaLast] = XK_MediaLast; keysyms[Qt::Key_Select] = XK_Select; -// keysyms[Qt::Key_Yes] = XK_Yes; -// keysyms[Qt::Key_No] = XK_No; keysyms[Qt::Key_Cancel] = XK_Cancel; -// keysyms[Qt::Key_Printer] = XK_Printer; keysyms[Qt::Key_Execute] = XK_Execute; -// keysyms[Qt::Key_Sleep] = XK_Sleep; -// keysyms[Qt::Key_MediaPlay] = XK_MediaPlay; -// keysyms[Qt::Key_Zoom] = XK_Zoom; -// keysyms[Qt::Key_Jisho] = XK_Jisho; -// keysyms[Qt::Key_Oyayubi_Left] = XK_Oyayubi_Left; -// keysyms[Qt::Key_Oyayubi_Right] = XK_Oyayubi_Right; -// keysyms[Qt::Key_Context1] = XK_Context1; -// keysyms[Qt::Key_Context2] = XK_Context2; -// keysyms[Qt::Key_Context3] = XK_Context3; -// keysyms[Qt::Key_Context4] = XK_Context4; -// keysyms[Qt::Key_Call] = XK_Call; -// keysyms[Qt::Key_Hangup] = XK_Hangup; -// keysyms[Qt::Key_Flip] = XK_Flip; keysyms[Qt::Key_unknown] = XK_VoidSymbol; } -/* Store Keycodes for "normal" Latin1 keys: */ -int basic_keycodes[0x100]; -int basic_modifiers[0x100]; - -int modifier_keycodes[8]; -Qt::KeyboardModifier modifier_meaning[8]; +// every keysym with a value under 256 corresponds +// directly to an ISO-Latin1 Character. We need +// to store how to generate those characters: +int basicKeycodes[0x100]; // What key do we need to press? +int basicModifiers[0x100]; // What modifiers are required? -int xmodifier_from_qtmodifier(Qt::KeyboardModifier m) { - for(int i = 0; i < 8; i++) { - if(m == modifier_meaning[i]) - return i; - } - return -1; -} +// What keys do we need to press to generate the +// modifiers? +int modifierKeycodes[8]; +// How do the X11 modifiers relate to Qt's KeyboardModifiers? +Qt::KeyboardModifier modifierMeaning[8]; -typedef std::map qt_to_xmodifier_type; -typedef std::map x_to_qtmodifier_type; -qt_to_xmodifier_type qt_to_xmodifier; -x_to_qtmodifier_type x_to_qtmodifier; +// How do the X11 modifiers correspond to Qt's KeyboardModifiers? +typedef std::map XToQtModifierMap; +XToQtModifierMap XToQtModifier; -typedef std::multimap modifier_to_keycode_map; -modifier_to_keycode_map modifier_to_keycode; -typedef std::map keycode_to_modifier_map; -keycode_to_modifier_map keycode_to_modifier; +// And how do the modifiers relate to Keycodes? +typedef std::multimap ModifierToKeycodeMap; +ModifierToKeycodeMap ModifierToKeycode; +typedef std::map KeycodeToModifierMap; +KeycodeToModifierMap KeycodeToModifier; // We need to query the input devices, preferrable through XInput2, but // if that is not available we will contend ourselves with XInput1: @@ -491,56 +425,72 @@ keycode_to_modifier_map keycode_to_modifier; } #endif - -void initialize_basic_keycodes() +// Initialize the above data structures: +void initializeBasicKeycodes() { + // Mark everything as unknown initially for(int i = 0; i < 8; i++) { - modifier_keycodes[i] = -1; + modifierKeycodes[i] = -1; } for(int i = 0; i < 0x100; i++) { - basic_keycodes[i] = -1; + basicKeycodes[i] = -1; } Display* dpy = X11InputUtils::display(); - int min_keycode, max_keycode; - XDisplayKeycodes(dpy, &min_keycode, &max_keycode); - - int xkb_opcode, xkb_event, xkb_error, xkb_major, xkb_minor; - bool xkb_present = XkbQueryExtension(dpy, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor); - if(!xkb_present) { - int keysyms_per_code; - const int count = max_keycode - min_keycode + 1; - KeySym* mapping = XGetKeyboardMapping(dpy, min_keycode, count, &keysyms_per_code); + + // Find out the valid range of keycodes + int minKeycode, maxKeycode; + XDisplayKeycodes(dpy, &minKeycode, &maxKeycode); + + // Initialize the XKB client-side code, and find out whether + // the XKB extension is present in the server. + int xkbOpcode, xkbEvent, xkbError, xkbMajor, xkbMinor; + bool xkbPresent = XkbQueryExtension(dpy, &xkbOpcode, &xkbEvent, &xkbError, &xkbMajor, &xkbMinor); + + if(!xkbPresent) { + // No XKB. This is probably not a very recent + // system, but we will do the best we can. + // Retrieve the keyboard mapping + int keysymsPerCode; + const int count = maxKeycode - minKeycode + 1; + KeySym* mapping = XGetKeyboardMapping(dpy, minKeycode, count, &keysymsPerCode); + + // and traverse every entry for(int i = 0; i < count; i++) { - for(int j = 0; j < keysyms_per_code; j++) + for(int j = 0; j < keysymsPerCode; j++) { - const int idx = i * keysyms_per_code + j; + const int idx = i * keysymsPerCode + j; const KeySym ks = mapping[idx]; - const int keycode = min_keycode + i; + const int keycode = minKeycode + i; + // to find out if there is a Latin1 character there, if(ks >= ' ' && ks < 0x100) { - if(ks == XK_at) { - ConsoleLog writeLine(QString("Keycode %1 (%2) gives `@' with modifiers `%3', but it is really `%4'").arg(keycode).arg(XKeysymToString(XKeycodeToKeysym(dpy, keycode, 0))).arg(modifiers_to_string(j)).arg(XKeysymToString(XKeycodeToKeysym(dpy, keycode, j)))); - - } - - if(basic_keycodes[ks] != -1) + // that we have not yet found, + if(basicKeycodes[ks] != -1) continue; // already found - basic_keycodes[ks] = keycode; - basic_modifiers[ks] = j; + // and record its keycode and needed modifiers. + basicKeycodes[ks] = keycode; + basicModifiers[ks] = j; } } } + + // We are finished, free the mapping structure. XFree(mapping); } else { - // Try to find out what device XTest will send events on: + // XKB is present. + + // As different input devices can have different keymaps, + // we need to find out what device XTest will send events on: unsigned int xkbDeviceId = XkbUseCoreKbd; Atom xtestDeviceProp = XInternAtom(dpy, "XTEST Device", false); + + // Find the list of input devices: int ndevinfos; XIDeviceInfo* devinfos = XIQueryDevice(dpy, XIAllDevices, &ndevinfos); if(devinfos) @@ -578,6 +528,9 @@ void initialize_basic_keycodes() # undef deviceid #endif } + // at this point, xkbDeviceId contains the identifier + // of the XTEST Device, or xkbUseCoreKbd if none was + // found. // Okay, we know which device to query. Now get its keymap: XkbDescPtr keybDesc = XkbGetKeyboard(dpy, XkbAllComponentsMask, xkbDeviceId); @@ -586,7 +539,9 @@ void initialize_basic_keycodes() qWarning("Unable to retrieve keyboard description for device %d. Falling back to unreliable global mapping", xkbDeviceId); } - for(int i = min_keycode; i <= max_keycode; i++) + // This is basically the same loop as above, it just queries XKB + // instead of the old core Xlib routines. + for(int i = minKeycode; i <= maxKeycode; i++) { for(int j = 0; j <= 0xff; j++) { @@ -605,17 +560,11 @@ void initialize_basic_keycodes() if(ks && (ks < 0x100)) { -// ConsoleLog writeLine(QString("Keycode %1 (%2) seems to give `%3' with modifiers `%4', of which `%5' are unconsumed") -// .arg(i) -// .arg(XKeysymToString(XKeycodeToKeysym(dpy, i, 0))) -// .arg(XKeysymToString(ks)) -// .arg(modifiers_to_string(j)) -// .arg(modifiers_to_string(unconsumed))); - if(basic_keycodes[ks] != -1) + if(basicKeycodes[ks] != -1) continue; - basic_keycodes[ks] = i; - basic_modifiers[ks] = unconsumed & j; + basicKeycodes[ks] = i; + basicModifiers[ks] = unconsumed & j; } } } @@ -631,56 +580,57 @@ void initialize_basic_keycodes() XModifierKeymap* modkm; modkm = XGetModifierMapping(dpy); - const int shift_kc = XKeysymToKeycode(dpy, XK_Shift_L); - const int control_kc = XKeysymToKeycode(dpy, XK_Control_L); - const int alt_kc = XKeysymToKeycode(dpy, XK_Alt_L); - const int meta_kc = XKeysymToKeycode(dpy, XK_Meta_L); - const int switch_kc = XKeysymToKeycode(dpy, XK_Mode_switch); + const int shiftCode = XKeysymToKeycode(dpy, XK_Shift_L); + const int controlCode = XKeysymToKeycode(dpy, XK_Control_L); + const int altCode = XKeysymToKeycode(dpy, XK_Alt_L); + const int metaCode = XKeysymToKeycode(dpy, XK_Meta_L); + const int switchCode = XKeysymToKeycode(dpy, XK_Mode_switch); + // and use this information to find out which + // X11 modifiers correspond to Qt's modifiers: for(int i = 0; i < 8; i++) { for(int j = 0; j < modkm->max_keypermod; j++) { const int idx = i * modkm->max_keypermod + j; const int kc = modkm->modifiermap[idx]; - modifier_to_keycode.insert(std::make_pair((1< int_set_type; -int_set_type pressed_modifier_keys; -xmodifier_type current_modifiers; +// We need to keep track of which modifiers +// are currently active +typedef std::set IntSet; +IntSet pressedModifierKeys; +XModifiers currentModifiers; void trackModifiers(int keycode, bool down) { // is this a modifier key? - const bool is_modifier = keycode_to_modifier.find(keycode) != keycode_to_modifier.end(); + const bool isModifier = KeycodeToModifier.find(keycode) != KeycodeToModifier.end(); - if(!is_modifier) + if(!isModifier) { return; } if(down) { - pressed_modifier_keys.insert(keycode); + pressedModifierKeys.insert(keycode); } else { - pressed_modifier_keys.erase(keycode); + pressedModifierKeys.erase(keycode); } - int_set_type::iterator i, end = pressed_modifier_keys.end(); - xmodifier_type modifs = 0; - for(i = pressed_modifier_keys.begin(); i != end; i++) + IntSet::iterator i, end = pressedModifierKeys.end(); + XModifiers modifs = 0; + for(i = pressedModifierKeys.begin(); i != end; i++) { - keycode_to_modifier_map::iterator found_kc = keycode_to_modifier.find(*i); - if(found_kc != keycode_to_modifier.end()) + KeycodeToModifierMap::iterator foundCode = KeycodeToModifier.find(*i); + if(foundCode != KeycodeToModifier.end()) { - modifs |= (*found_kc).second; + modifs |= (*foundCode).second; } } - current_modifiers = modifs; + currentModifiers = modifs; - ConsoleLog writeLine(QString("[trackModifiers] current modifiers: %1").arg(modifiers_to_string(modifs))); + ConsoleLog writeLine(QString("[trackModifiers] current modifiers: %1").arg(modifiersToString(modifs))); } -typedef std::pair modifier_tweak_type; -typedef std::vector tweak_sequence_type; +// And, if we need to tweak the modifiers to generate +// a particular keysym, we need to keep track of which +// ones we pressed or released. +typedef std::pair ModifierTweak; +typedef std::vector TweakSequence; -void tweakModifiers(Display* dpy, xmodifier_type neededState, xmodifier_type actualState, tweak_sequence_type& tracker) +// Tweak the modifiers to reach the neededState, from actualState +// and record tweaks in the tracker. +void tweakModifiers(Display* dpy, XModifiers neededState, XModifiers actualState, TweakSequence& tracker) { - ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiers_to_string(neededState)).arg(modifiers_to_string(actualState))); + ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiersToString(neededState)).arg(modifiersToString(actualState))); for(int j = 0; j < 8; j++) { - xmodifier_type i = 1<second == i) { + KeycodeToModifierMap::iterator modmapIter = KeycodeToModifier.find(*iter); + if(modmapIter != KeycodeToModifier.end()) { + if(modmapIter->second == i) { kc = *iter; // release this key: @@ -790,29 +746,33 @@ void tweakModifiers(Display* dpy, xmodifier_type neededState, xmodifier_type act } } -void untweakModifiers(Display* dpy, tweak_sequence_type& tracker) +// Undo a recorded sequence of modifier tweaks +void untweakModifiers(Display* dpy, TweakSequence& tracker) { - tweak_sequence_type::iterator i, end = tracker.end(); + TweakSequence::iterator i, end = tracker.end(); for(i = tracker.begin(); i != end; i++) { - modifier_tweak_type& t = *i; + ModifierTweak& t = *i; XTestFakeKeyEvent(dpy, t.first, !t.second, CurrentTime); } } +// initialize the handler void X11FakeKeyboardHandler::initialize() { - initialize_keysyms(); - initialize_basic_keycodes(); - pressed_modifier_keys.clear(); - current_modifiers = 0; + initializeKeycodeLookupTable(); + initializeBasicKeycodes(); + pressedModifierKeys.clear(); + currentModifiers = 0; } +// actually try our best to generate the correct input sequence +// for the event void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext const*) { Display* dpy = X11InputUtils::display(); // find out which keysym caused this event: - lookup_table_const_iterator i = keysyms.find(evt.qt_keysym()); + KeycodeLookupTable::const_iterator i = keysyms.find(evt.qt_keysym()); if(i == keysyms.end()) { // Special cases. We don't know how to directly translate those, so we will try to emulate them. switch(evt.qt_keysym()) @@ -829,44 +789,43 @@ void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext c // is it a "normal" key? if(ks >= ' ' && ks < 0x100) { - if(basic_keycodes[ks] != -1) + if(basicKeycodes[ks] != -1) { if(evt.isPress()) { // Try the simple way first: // Does the keycode with current modifiers yield the requested symbol? - KeySym unmod_ks = XKeycodeToKeysym(dpy, basic_keycodes[ks], current_modifiers); - ConsoleLog writeLine(QString("Pressing the key for %1 would yield %2 right now.").arg(XKeysymToString(ks)).arg(XKeysymToString(unmod_ks))); + KeySym unmodSym = XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers); + ConsoleLog writeLine(QString("Pressing the key for %1 would yield %2 right now.").arg(XKeysymToString(ks)).arg(XKeysymToString(unmodSym))); - if(ks == XKeycodeToKeysym(dpy, basic_keycodes[ks], current_modifiers)) + if(ks == XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers)) { - XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime); + XTestFakeKeyEvent(dpy, basicKeycodes[ks], 1, CurrentTime); } else { // what modifier keys do we need to press? - xmodifier_type mods = translate_modifiers(evt.qt_modifiers()); + XModifiers mods = translateModifiers(evt.qt_modifiers()); // we may need to press additional modifiers to generate this keysym: if(QChar(ks, 0).isLetter()) { - // but, since we do not differentiate upper and lower case, - // and instead let the sender handle those modifiers, - // we need to AND ShiftModifier and LockModifier out. - mods |= basic_modifiers[ks] & ~(1<>(QDataStream& istrm, InputEvent& evt) { - istrm >> evt.type_ >> evt.code_ >> evt.value_; + istrm >> evt._type >> evt._code >> evt._value; return istrm; } diff --git a/src/input/inputEvent.h b/src/input/inputEvent.h index 82b059c..73b7129 100644 --- a/src/input/inputEvent.h +++ b/src/input/inputEvent.h @@ -39,19 +39,19 @@ private: friend void eventToString(InputEvent const& evt, QString& str); friend bool eventFromString(QString const& str, InputEvent& evt); - uint16_t type_; - uint16_t code_; - uint32_t value_; + quint16 _type; + quint16 _code; + quint32 _value; // InputEvents are immutable. Prohibit assignment: InputEvent& operator=(InputEvent const&); // There intentionally is no implementation. public: - InputEvent(uint16_t type, uint16_t code, uint32_t value = 0) : type_(type), code_(code), value_(value) + InputEvent(quint16 type, quint16 code, quint32 value = 0) : _type(type), _code(code), _value(value) { } - InputEvent(InputEvent const& other) : type_(other.type_), code_(other.code_), value_(other.value_) + InputEvent(InputEvent const& other) : _type(other._type), _code(other._code), _value(other._value) { } @@ -59,110 +59,110 @@ public: { } - static InputEvent mouseMotion(uint16_t x, uint16_t y) + static InputEvent mouseMotion(quint16 x, quint16 y) { - return InputEvent(ET_POINTER, 0, ((uint32_t)x << 16) | y); + return InputEvent(ET_POINTER, 0, ((quint32)x << 16) | y); } - static uint16_t mouseButtonsFromQt(int b); + static quint16 mouseButtonsFromQt(int b); static InputEvent mousePressRelease(int button, int buttons); static InputEvent keyboardPress(int key, int mods); static InputEvent keyboardRelease(int key, int mods); - static const uint16_t ET_KEY = 0; - static const uint16_t ET_BUTTON = 1; - static const uint16_t ET_POINTER = 2; - static const uint16_t ET_SPECIAL = 3; + static const quint16 ET_KEY = 0; + static const quint16 ET_BUTTON = 1; + static const quint16 ET_POINTER = 2; + static const quint16 ET_SPECIAL = 3; - static const uint16_t EC_PRESS = 0; - static const uint16_t EC_RELEASE = 1; - static const uint16_t EC_REBOOT = 2; - static const uint16_t EC_SYSRQ = 3; - static const uint16_t EC_KILL_X = 4; - static const uint16_t EC_SAY_HELLO = 5; //< for debugging purposes + static const quint16 EC_PRESS = 0; + static const quint16 EC_RELEASE = 1; + static const quint16 EC_REBOOT = 2; + static const quint16 EC_SYSRQ = 3; + static const quint16 EC_KILL_X = 4; + static const quint16 EC_SAY_HELLO = 5; //< for debugging purposes - typedef uint32_t event_key; + typedef quint32 event_key; - typedef uint32_t event_key_modifiers; + typedef quint32 event_key_modifiers; - static const uint16_t EB_LEFT = 1; - static const uint16_t EB_MIDDLE = 2; - static const uint16_t EB_RIGHT = 4; + static const quint16 EB_LEFT = 1; + static const quint16 EB_MIDDLE = 2; + static const quint16 EB_RIGHT = 4; - static const uint32_t MODIFIER_MASK = + static const quint32 MODIFIER_MASK = 0x7e000000; - uint16_t type() const + quint16 type() const { - return type_; + return _type; } - uint16_t code() const + quint16 code() const { - return code_; + return _code; } - uint32_t value() const + quint32 value() const { - return value_; + return _value; } bool isKeyboard() const { - return type_ == ET_KEY; + return _type == ET_KEY; } bool isButton() const { - return type_ == ET_BUTTON; + return _type == ET_BUTTON; } bool isPointer() const { - return type_ == ET_POINTER; + return _type == ET_POINTER; } bool isSpecial() const { - return type_ == ET_SPECIAL; + return _type == ET_SPECIAL; } bool isPress() const { - return code_ == EC_PRESS; + return _code == EC_PRESS; } bool isRelease() const { - return code_ == EC_RELEASE; + return _code == EC_RELEASE; } - uint16_t pressedButton() const + quint16 pressedButton() const { - assert(type_ == ET_BUTTON); - return (value_ >> 16); + assert(_type == ET_BUTTON); + return (_value >> 16); } - uint16_t heldButtons() const + quint16 heldButtons() const { - assert(type_ == ET_BUTTON); - return (value_ & 0xffff); + assert(_type == ET_BUTTON); + return (_value & 0xffff); } - uint16_t xCoord() const + quint16 xCoord() const { - assert(type_ == ET_POINTER); - return (value_ >> 16); + assert(_type == ET_POINTER); + return (_value >> 16); } - uint16_t yCoord() const + quint16 yCoord() const { - assert(type_ == ET_POINTER); - return (value_ & 0xffff); + assert(_type == ET_POINTER); + return (_value & 0xffff); } - static QString typeToString(uint16_t type) + static QString typeToString(quint16 type) { switch(type) { @@ -179,7 +179,7 @@ public: } } - static QString codeToString(uint16_t code) + static QString codeToString(quint16 code) { switch(code) { @@ -200,17 +200,17 @@ public: QString toString() const { - return QString("%1:%2:%3").arg(typeToString(type_)).arg(codeToString(code_)).arg(value_, 16); + return QString("%1:%2:%3").arg(typeToString(_type)).arg(codeToString(_code)).arg(_value, 16); } - uint32_t qt_keysym() const + quint32 qtKeysym() const { - return value_ & ~MODIFIER_MASK; + return _value & ~MODIFIER_MASK; } - uint32_t qt_modifiers() const + quint32 qtModifiers() const { - return value_ & MODIFIER_MASK; + return _value & MODIFIER_MASK; } // We want to enable InputEvent as a translation context, so we fake the tr method: @@ -222,14 +222,14 @@ public: struct SpecialInputEventDescription { - SpecialInputEventDescription(uint16_t type, uint16_t code, uint32_t value, QString const& description_) + SpecialInputEventDescription(quint16 type, quint16 code, quint32 value, QString const& description_) : type(type), code(code), value(value), description(description_) { } - uint16_t type; - uint16_t code; - uint32_t value; + quint16 type; + quint16 code; + quint32 value; QString description; InputEvent toEvent() const diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 5b03a90..71a530b 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -176,7 +176,7 @@ struct InputEventHandlerPolicyBase // The actual handler class need to provide doHandle and can override // allow and isApplicable. ///////////////////////////////////////////////////////////////////////// -/* interface */ class InputEventHandlerBase +class InputEventHandlerBase { public: enum HandlerStatus @@ -246,9 +246,15 @@ private: // Unfortunately, we cannot specialize member functions of a template. // So, we need to make this a class with a static non-template member. ///////////////////////////////////////////////////////////////////////// - template + template struct ConditionallyAppend { + ///////////////////////////////////////////////////////////////////////// + // This method will never be instantiated for handlers that are + // not Compatible, thus generating no reference to HandlerType + // and permitting compilation to proceed without + // tedious nested preprocessor conditionals. + ///////////////////////////////////////////////////////////////////////// static void doIt(InputEventHandlerChain* chain) { chain->handlers.append(new HandlerType); diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index a136e45..4e3449a 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -772,16 +772,16 @@ void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext c Display* dpy = X11InputUtils::display(); // find out which keysym caused this event: - KeycodeLookupTable::const_iterator i = keysyms.find(evt.qt_keysym()); + KeycodeLookupTable::const_iterator i = keysyms.find(evt.qtKeysym()); if(i == keysyms.end()) { // Special cases. We don't know how to directly translate those, so we will try to emulate them. - switch(evt.qt_keysym()) + switch(evt.qtKeysym()) { case Qt::Key_Backtab: - doHandle(InputEvent(evt.type(), evt.code(), evt.qt_modifiers() | Qt::ShiftModifier | Qt::Key_Tab)); + doHandle(InputEvent(evt.type(), evt.code(), evt.qtModifiers() | Qt::ShiftModifier | Qt::Key_Tab)); break; default: - ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qt_keysym(), 8, 16)); + ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qtKeysym(), 8, 16)); } } else { KeySym ks = (*i).second; @@ -805,7 +805,7 @@ void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext c else { // what modifier keys do we need to press? - XModifiers mods = translateModifiers(evt.qt_modifiers()); + XModifiers mods = translateModifiers(evt.qtModifiers()); // we may need to press additional modifiers to generate this keysym: if(QChar(ks, 0).isLetter()) -- cgit v1.2.3-55-g7522 From 2e072d898609ef8dfb5270a07e3212498648d048 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 17:08:49 +0200 Subject: Code cleanup and simplification for X11FakeKeyboardHandler --- src/input/CMakeLists.txt | 32 +- src/input/x11FakeKeyboardHandler.cpp | 655 ++++++++++++++++++----------------- 2 files changed, 358 insertions(+), 329 deletions(-) (limited to 'src/input/x11FakeKeyboardHandler.cpp') diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index b7a6511..d950c67 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -5,16 +5,28 @@ set(pvsinput_SRCS unprivilegedInputHandlerChain.cpp inputEventHandler.cpp ) + +set(feature_DEFS) if(UNIX) find_file(XINPUT2_HDR X11/extensions/XInput2.h) if(XINPUT2_HDR) - set_property(SOURCE x11FakeKeyboardHandler.cpp - APPEND - PROPERTY COMPILE_DEFINITIONS HAVE_XINPUT2_H - ) + list(APPEND feature_DEFS + HAVE_XINPUT2_H) endif() - + + find_file(XINPUT_HDR X11/extensions/XInput.h) + if(XINPUT_HDR) + list(APPEND feature_DEFS + HAVE_XINPUT_H) + endif() + + find_file(XKBLIB_HDR X11/XKBlib.h) + if(XKBLIB_HDR) + list(APPEND feature_DEFS + HAVE_XKBLIB_H) + endif() + set(pvsprivinputd_SRCS pvsprivinputd.cpp pvsPrivInputHandler.cpp @@ -114,6 +126,11 @@ if(UNIX) DESTINATION sbin) endif() +set_property(SOURCE ${pvsinput_SRCS} ${pvsprivinputd_SRCS} + APPEND + PROPERTY COMPILE_DEFINITIONS ${feature_DEFS} +) + set(pvsinput_TSS i18n/pvsinput_de_DE.ts i18n/pvsinput_fr_FR.ts @@ -146,3 +163,8 @@ add_library( ${pvsinput_SRCS} ${pvsinput_RCS} ) + +add_library( + pvsinputtests + STATIC + templateMagicTests.cpp) diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index 4e3449a..fed087e 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -51,6 +51,44 @@ char modifiernames[][8] = { "MOD5" }; +// We generally want to find a key sequence with as few modifiers as +// possible. These are all modifier combinations sorted by number of +// bits set: +char modifierpriority[256] = { + 0, 1, 2, 4, 8, 16, 32, 64, 128, + 3, 5, 6, 9, 10, 12, 17, 18, + 20, 24, 33, 34, 36, 40, 48, 65, + 66, 68, 72, 80, 96, 129, 130, 132, + 136, 144, 160, 192, 7, 11, 13, 14, + 19, 21, 22, 25, 26, 28, 35, 37, + 38, 41, 42, 44, 49, 50, 52, 56, + 67, 69, 70, 73, 74, 76, 81, 82, + 84, 88, 97, 98, 100, 104, 112, 131, + 133, 134, 137, 138, 140, 145, 146, 148, + 152, 161, 162, 164, 168, 176, 193, 194, + 196, 200, 208, 224, 15, 23, 27, 29, + 30, 39, 43, 45, 46, 51, 53, 54, + 57, 58, 60, 71, 75, 77, 78, 83, + 85, 86, 89, 90, 92, 99, 101, 102, + 105, 106, 108, 113, 114, 116, 120, 135, + 139, 141, 142, 147, 149, 150, 153, 154, + 156, 163, 165, 166, 169, 170, 172, 177, + 178, 180, 184, 195, 197, 198, 201, 202, + 204, 209, 210, 212, 216, 225, 226, 228, + 232, 240, 31, 47, 55, 59, 61, 62, + 79, 87, 91, 93, 94, 103, 107, 109, + 110, 115, 117, 118, 121, 122, 124, 143, + 151, 155, 157, 158, 167, 171, 173, 174, + 179, 181, 182, 185, 186, 188, 199, 203, + 205, 206, 211, 213, 214, 217, 218, 220, + 227, 229, 230, 233, 234, 236, 241, 242, + 244, 248, 63, 95, 111, 119, 123, 125, + 126, 159, 175, 183, 187, 189, 190, 207, + 215, 219, 221, 222, 231, 235, 237, 238, + 243, 245, 246, 249, 250, 252, 127, 191, + 223, 239, 247, 251, 253, 254, 255 +}; + QString modifiersToString(XModifiers mods) { QString s; @@ -82,6 +120,7 @@ KeycodeLookupTable keysyms; void initializeKeycodeLookupTable() { keysyms[Qt::Key_Escape] = XK_Escape; keysyms[Qt::Key_Tab] = XK_Tab; + keysyms[Qt::Key_Backtab] = XK_ISO_Left_Tab; keysyms[Qt::Key_Backspace] = XK_BackSpace; keysyms[Qt::Key_Return] = XK_Return; keysyms[Qt::Key_Enter] = XK_KP_Enter; @@ -147,171 +186,13 @@ void initializeKeycodeLookupTable() { keysyms[Qt::Key_Hyper_L] = XK_Hyper_L; keysyms[Qt::Key_Hyper_R] = XK_Hyper_R; keysyms[Qt::Key_Help] = XK_Help; - keysyms[Qt::Key_Space] = XK_space; - keysyms[Qt::Key_Exclam] = XK_exclam; - keysyms[Qt::Key_QuoteDbl] = XK_quotedbl; - keysyms[Qt::Key_NumberSign] = XK_numbersign; - keysyms[Qt::Key_Dollar] = XK_dollar; - keysyms[Qt::Key_Percent] = XK_percent; - keysyms[Qt::Key_Ampersand] = XK_ampersand; - keysyms[Qt::Key_Apostrophe] = XK_apostrophe; - keysyms[Qt::Key_ParenLeft] = XK_parenleft; - keysyms[Qt::Key_ParenRight] = XK_parenright; - keysyms[Qt::Key_Asterisk] = XK_asterisk; - keysyms[Qt::Key_Plus] = XK_plus; - keysyms[Qt::Key_Comma] = XK_comma; - keysyms[Qt::Key_Minus] = XK_minus; - keysyms[Qt::Key_Period] = XK_period; - keysyms[Qt::Key_Slash] = XK_slash; - keysyms[Qt::Key_0] = XK_0; - keysyms[Qt::Key_1] = XK_1; - keysyms[Qt::Key_2] = XK_2; - keysyms[Qt::Key_3] = XK_3; - keysyms[Qt::Key_4] = XK_4; - keysyms[Qt::Key_5] = XK_5; - keysyms[Qt::Key_6] = XK_6; - keysyms[Qt::Key_7] = XK_7; - keysyms[Qt::Key_8] = XK_8; - keysyms[Qt::Key_9] = XK_9; - keysyms[Qt::Key_Colon] = XK_colon; - keysyms[Qt::Key_Semicolon] = XK_semicolon; - keysyms[Qt::Key_Less] = XK_less; - keysyms[Qt::Key_Equal] = XK_equal; - keysyms[Qt::Key_Greater] = XK_greater; - keysyms[Qt::Key_Question] = XK_question; - keysyms[Qt::Key_At] = XK_at; - keysyms[Qt::Key_A] = XK_A; - keysyms[Qt::Key_B] = XK_B; - keysyms[Qt::Key_C] = XK_C; - keysyms[Qt::Key_D] = XK_D; - keysyms[Qt::Key_E] = XK_E; - keysyms[Qt::Key_F] = XK_F; - keysyms[Qt::Key_G] = XK_G; - keysyms[Qt::Key_H] = XK_H; - keysyms[Qt::Key_I] = XK_I; - keysyms[Qt::Key_J] = XK_J; - keysyms[Qt::Key_K] = XK_K; - keysyms[Qt::Key_L] = XK_L; - keysyms[Qt::Key_M] = XK_M; - keysyms[Qt::Key_N] = XK_N; - keysyms[Qt::Key_O] = XK_O; - keysyms[Qt::Key_P] = XK_P; - keysyms[Qt::Key_Q] = XK_Q; - keysyms[Qt::Key_R] = XK_R; - keysyms[Qt::Key_S] = XK_S; - keysyms[Qt::Key_T] = XK_T; - keysyms[Qt::Key_U] = XK_U; - keysyms[Qt::Key_V] = XK_V; - keysyms[Qt::Key_W] = XK_W; - keysyms[Qt::Key_X] = XK_X; - keysyms[Qt::Key_Y] = XK_Y; - keysyms[Qt::Key_Z] = XK_Z; - keysyms[Qt::Key_BracketLeft] = XK_bracketleft; - keysyms[Qt::Key_Backslash] = XK_backslash; - keysyms[Qt::Key_BracketRight] = XK_bracketright; - keysyms[Qt::Key_AsciiCircum] = XK_asciicircum; - keysyms[Qt::Key_Underscore] = XK_underscore; - keysyms[Qt::Key_QuoteLeft] = XK_quoteleft; - keysyms[Qt::Key_BraceLeft] = XK_braceleft; - keysyms[Qt::Key_Bar] = XK_bar; - keysyms[Qt::Key_BraceRight] = XK_braceright; - keysyms[Qt::Key_AsciiTilde] = XK_asciitilde; - keysyms[Qt::Key_nobreakspace] = XK_nobreakspace; - keysyms[Qt::Key_exclamdown] = XK_exclamdown; - keysyms[Qt::Key_cent] = XK_cent; - keysyms[Qt::Key_sterling] = XK_sterling; - keysyms[Qt::Key_currency] = XK_currency; - keysyms[Qt::Key_yen] = XK_yen; - keysyms[Qt::Key_brokenbar] = XK_brokenbar; - keysyms[Qt::Key_section] = XK_section; - keysyms[Qt::Key_diaeresis] = XK_diaeresis; - keysyms[Qt::Key_copyright] = XK_copyright; - keysyms[Qt::Key_ordfeminine] = XK_ordfeminine; - keysyms[Qt::Key_guillemotleft] = XK_guillemotleft; - keysyms[Qt::Key_notsign] = XK_notsign; - keysyms[Qt::Key_hyphen] = XK_hyphen; - keysyms[Qt::Key_registered] = XK_registered; - keysyms[Qt::Key_macron] = XK_macron; - keysyms[Qt::Key_degree] = XK_degree; - keysyms[Qt::Key_plusminus] = XK_plusminus; - keysyms[Qt::Key_twosuperior] = XK_twosuperior; - keysyms[Qt::Key_threesuperior] = XK_threesuperior; - keysyms[Qt::Key_acute] = XK_acute; - keysyms[Qt::Key_mu] = XK_mu; - keysyms[Qt::Key_paragraph] = XK_paragraph; - keysyms[Qt::Key_periodcentered] = XK_periodcentered; - keysyms[Qt::Key_cedilla] = XK_cedilla; - keysyms[Qt::Key_onesuperior] = XK_onesuperior; - keysyms[Qt::Key_masculine] = XK_masculine; - keysyms[Qt::Key_guillemotright] = XK_guillemotright; - keysyms[Qt::Key_onequarter] = XK_onequarter; - keysyms[Qt::Key_onehalf] = XK_onehalf; - keysyms[Qt::Key_threequarters] = XK_threequarters; - keysyms[Qt::Key_questiondown] = XK_questiondown; - keysyms[Qt::Key_Agrave] = XK_Agrave; - keysyms[Qt::Key_Aacute] = XK_Aacute; - keysyms[Qt::Key_Acircumflex] = XK_Acircumflex; - keysyms[Qt::Key_Atilde] = XK_Atilde; - keysyms[Qt::Key_Adiaeresis] = XK_Adiaeresis; - keysyms[Qt::Key_Aring] = XK_Aring; - keysyms[Qt::Key_AE] = XK_AE; - keysyms[Qt::Key_Ccedilla] = XK_Ccedilla; - keysyms[Qt::Key_Egrave] = XK_Egrave; - keysyms[Qt::Key_Eacute] = XK_Eacute; - keysyms[Qt::Key_Ecircumflex] = XK_Ecircumflex; - keysyms[Qt::Key_Ediaeresis] = XK_Ediaeresis; - keysyms[Qt::Key_Igrave] = XK_Igrave; - keysyms[Qt::Key_Iacute] = XK_Iacute; - keysyms[Qt::Key_Icircumflex] = XK_Icircumflex; - keysyms[Qt::Key_Idiaeresis] = XK_Idiaeresis; - keysyms[Qt::Key_ETH] = XK_ETH; - keysyms[Qt::Key_Ntilde] = XK_Ntilde; - keysyms[Qt::Key_Ograve] = XK_Ograve; - keysyms[Qt::Key_Oacute] = XK_Oacute; - keysyms[Qt::Key_Ocircumflex] = XK_Ocircumflex; - keysyms[Qt::Key_Otilde] = XK_Otilde; - keysyms[Qt::Key_Odiaeresis] = XK_Odiaeresis; - keysyms[Qt::Key_multiply] = XK_multiply; - keysyms[Qt::Key_Ooblique] = XK_Ooblique; - keysyms[Qt::Key_Ugrave] = XK_Ugrave; - keysyms[Qt::Key_Uacute] = XK_Uacute; - keysyms[Qt::Key_Ucircumflex] = XK_Ucircumflex; - keysyms[Qt::Key_Udiaeresis] = XK_Udiaeresis; - keysyms[Qt::Key_Yacute] = XK_Yacute; - keysyms[Qt::Key_THORN] = XK_THORN; - keysyms[Qt::Key_ssharp] = XK_ssharp; - keysyms[Qt::Key_Agrave] = XK_Agrave; - keysyms[Qt::Key_Aacute] = XK_Aacute; - keysyms[Qt::Key_Acircumflex] = XK_Acircumflex; - keysyms[Qt::Key_Atilde] = XK_Atilde; - keysyms[Qt::Key_Adiaeresis] = XK_Adiaeresis; - keysyms[Qt::Key_Aring] = XK_Aring; - keysyms[Qt::Key_AE] = XK_AE; - keysyms[Qt::Key_Ccedilla] = XK_Ccedilla; - keysyms[Qt::Key_Egrave] = XK_Egrave; - keysyms[Qt::Key_Eacute] = XK_Eacute; - keysyms[Qt::Key_Ecircumflex] = XK_Ecircumflex; - keysyms[Qt::Key_Ediaeresis] = XK_Ediaeresis; - keysyms[Qt::Key_Igrave] = XK_Igrave; - keysyms[Qt::Key_Iacute] = XK_Iacute; - keysyms[Qt::Key_Icircumflex] = XK_Icircumflex; - keysyms[Qt::Key_Idiaeresis] = XK_Idiaeresis; - keysyms[Qt::Key_ETH] = XK_ETH; - keysyms[Qt::Key_Ntilde] = XK_Ntilde; - keysyms[Qt::Key_Ograve] = XK_Ograve; - keysyms[Qt::Key_Oacute] = XK_Oacute; - keysyms[Qt::Key_Ocircumflex] = XK_Ocircumflex; - keysyms[Qt::Key_Otilde] = XK_Otilde; - keysyms[Qt::Key_Odiaeresis] = XK_Odiaeresis; - keysyms[Qt::Key_division] = XK_division; - keysyms[Qt::Key_Ooblique] = XK_Ooblique; - keysyms[Qt::Key_Ugrave] = XK_Ugrave; - keysyms[Qt::Key_Uacute] = XK_Uacute; - keysyms[Qt::Key_Ucircumflex] = XK_Ucircumflex; - keysyms[Qt::Key_Udiaeresis] = XK_Udiaeresis; - keysyms[Qt::Key_Yacute] = XK_Yacute; - keysyms[Qt::Key_THORN] = XK_THORN; - keysyms[Qt::Key_ydiaeresis] = XK_ydiaeresis; + // Latin1 symbols do directly map to + // Keycodes both in Qt and in X11: + for(int i = 0x20; i < 0x100; i++) + { + keysyms[i] = i; + } + keysyms[Qt::Key_AltGr] = XK_ISO_Level3_Shift; keysyms[Qt::Key_Multi_key] = XK_Multi_key; keysyms[Qt::Key_Codeinput] = XK_Codeinput; @@ -373,11 +254,15 @@ void initializeKeycodeLookupTable() { keysyms[Qt::Key_unknown] = XK_VoidSymbol; } -// every keysym with a value under 256 corresponds -// directly to an ISO-Latin1 Character. We need -// to store how to generate those characters: -int basicKeycodes[0x100]; // What key do we need to press? -int basicModifiers[0x100]; // What modifiers are required? +// We need to store how to generate KeySyms: +struct KeySymInfo +{ + KeyCode keycode; + XModifiers neededModifiers; + XModifiers modifierMask; +}; +typedef std::map KeySymToInfoMap; +KeySymToInfoMap keysymInfos; // What keys do we need to press to generate the // modifiers? @@ -388,6 +273,9 @@ Qt::KeyboardModifier modifierMeaning[8]; // How do the X11 modifiers correspond to Qt's KeyboardModifiers? typedef std::map XToQtModifierMap; XToQtModifierMap XToQtModifier; +typedef std::map QtToXModifierMap; +QtToXModifierMap QtToXModifier; + // And how do the modifiers relate to Keycodes? typedef std::multimap ModifierToKeycodeMap; @@ -395,6 +283,36 @@ ModifierToKeycodeMap ModifierToKeycode; typedef std::map KeycodeToModifierMap; KeycodeToModifierMap KeycodeToModifier; +#ifdef HAVE_XKBLIB_H +void recordModifierMapping(XkbDescPtr keybDesc, int keycode, Qt::KeyboardModifier qtMod) +{ + XModifiers rmod = 0; + if(QtToXModifier.find(qtMod) == QtToXModifier.end()) + { + for(int i = 1; i < 0x100; i <<= 1) + { + if(keybDesc->map->modmap[keycode] == i) + { + rmod = i; + XToQtModifier[rmod] = qtMod; + QtToXModifier[qtMod] = rmod; + } + } + } + else + { + rmod = QtToXModifier[qtMod]; + } + + if(rmod) + { + ModifierToKeycode.insert(std::make_pair(rmod, keycode)); + KeycodeToModifier[keycode] = rmod; + ConsoleLog writeLine(QString("%1 %2 %3 ... generates modifier %4").arg(keycode, 3).arg("", 40).arg("", 40).arg(rmod, 2, 16)); + } +} +#endif + // We need to query the input devices, preferrable through XInput2, but // if that is not available we will contend ourselves with XInput1: #ifndef HAVE_XINPUT2_H @@ -428,13 +346,22 @@ KeycodeToModifierMap KeycodeToModifier; // Initialize the above data structures: void initializeBasicKeycodes() { + // We temporarily need a list of all known KeySyms: + typedef std::set KeySymSet; + KeySymSet knownKeySyms; + + for(KeycodeLookupTable::const_iterator kcIter = keysyms.begin(); + kcIter != keysyms.end(); + kcIter++) + { + knownKeySyms.insert((*kcIter).second); + } + // Mark everything as unknown initially for(int i = 0; i < 8; i++) { modifierKeycodes[i] = -1; } - for(int i = 0; i < 0x100; i++) { - basicKeycodes[i] = -1; - } + keysymInfos.clear(); Display* dpy = X11InputUtils::display(); @@ -445,7 +372,11 @@ void initializeBasicKeycodes() // Initialize the XKB client-side code, and find out whether // the XKB extension is present in the server. int xkbOpcode, xkbEvent, xkbError, xkbMajor, xkbMinor; +#ifdef HAVE_XKBLIB_H bool xkbPresent = XkbQueryExtension(dpy, &xkbOpcode, &xkbEvent, &xkbError, &xkbMajor, &xkbMinor); +#else + bool xkbPresent = false; +#endif if(!xkbPresent) { // No XKB. This is probably not a very recent @@ -458,29 +389,81 @@ void initializeBasicKeycodes() // and traverse every entry for(int i = 0; i < count; i++) { - for(int j = 0; j < keysymsPerCode; j++) + for(int j = 0; j < 0x100; j++) { - const int idx = i * keysymsPerCode + j; + const XModifiers mods = modifierpriority[j]; + if(mods >= keysymsPerCode) + continue; + + const int idx = i * keysymsPerCode + mods; const KeySym ks = mapping[idx]; const int keycode = minKeycode + i; - // to find out if there is a Latin1 character there, - if(ks >= ' ' && ks < 0x100) + // to find out if there is a KeySym there that we know about + if(knownKeySyms.find(ks) != knownKeySyms.end()) { // that we have not yet found, - if(basicKeycodes[ks] != -1) + if(keysymInfos.find(ks) != keysymInfos.end()) continue; // already found // and record its keycode and needed modifiers. - basicKeycodes[ks] = keycode; - basicModifiers[ks] = j; + KeySymInfo info; + info.keycode = keycode; + info.neededModifiers = mods; + info.modifierMask = mods; + keysymInfos[ks] = info; } } } // We are finished, free the mapping structure. XFree(mapping); + + // find out which keycodes cause the modifier state bits: + XModifierKeymap* modkm; + modkm = XGetModifierMapping(dpy); + + const int shiftCode = XKeysymToKeycode(dpy, XK_Shift_L); + const int controlCode = XKeysymToKeycode(dpy, XK_Control_L); + const int altCode = XKeysymToKeycode(dpy, XK_Alt_L); + const int metaCode = XKeysymToKeycode(dpy, XK_Meta_L); + const int switchCode = XKeysymToKeycode(dpy, XK_Mode_switch); + + // and use this information to find out which + // X11 modifiers correspond to Qt's modifiers: + for(int i = 0; i < 8; i++) { + for(int j = 0; j < modkm->max_keypermod; j++) { + const int idx = i * modkm->max_keypermod + j; + const int kc = modkm->modifiermap[idx]; + + ModifierToKeycode.insert(std::make_pair((1<deviceid, devinfo->use, devinfo->name); + for(int i = 0; i < ndevinfos && xkbDeviceId == XkbUseCoreKbd; i++) + { + XIDeviceInfo* devinfo = devinfos + i; + qDebug("Found device %lu of type %d with name %s", (unsigned long)devinfo->deviceid, devinfo->use, devinfo->name); - // We want it to be a keyboard. - if(devinfo->use != XIMasterKeyboard && devinfo->use != XISlaveKeyboard) - continue; + // We want it to be a keyboard. + if(devinfo->use != XIMasterKeyboard && devinfo->use != XISlaveKeyboard) + continue; - int nprops; - Atom* props = getDeviceProperties(dpy, devinfo, &nprops); - if(props) - { - for(int j = 0; j < nprops && xkbDeviceId == XkbUseCoreKbd; j++) + int nprops; + Atom* props = getDeviceProperties(dpy, devinfo, &nprops); + if(props) { - Atom prop = props[j]; - if(prop == xtestDeviceProp) + for(int j = 0; j < nprops && xkbDeviceId == XkbUseCoreKbd; j++) { - // The device is the XTest Keyboard: - xkbDeviceId = devinfo->deviceid; + Atom prop = props[j]; + if(prop == xtestDeviceProp) + { + // The device is the XTest Keyboard: + xkbDeviceId = devinfo->deviceid; + } } + XFree(props); } - XFree(props); } - } - XIFreeDeviceInfo(devinfos); + XIFreeDeviceInfo(devinfos); #ifdef deviceid /* XInput1 */ # undef deviceid #endif + } } +#endif /* HAVE_XINPUT_H || HAVE_XINPUT2_H */ + // at this point, xkbDeviceId contains the identifier // of the XTEST Device, or xkbUseCoreKbd if none was // found. @@ -545,26 +541,64 @@ void initializeBasicKeycodes() { for(int j = 0; j <= 0xff; j++) { + XModifiers mods = modifierpriority[j]; KeySym ks = 0; unsigned int unconsumed; if(keybDesc) { - if(!XkbTranslateKeyCode(keybDesc, i, j, &unconsumed, &ks) || ks == NoSymbol) + if(!XkbTranslateKeyCode(keybDesc, i, mods, &unconsumed, &ks) || ks == NoSymbol) continue; } else { - if(!XkbLookupKeySym(dpy, i, j, &unconsumed, &ks) || ks == NoSymbol) + if(!XkbLookupKeySym(dpy, i, mods, &unconsumed, &ks) || ks == NoSymbol) continue; } - if(ks && (ks < 0x100)) + if(knownKeySyms.find(ks) != knownKeySyms.end()) { - if(basicKeycodes[ks] != -1) + if(j & ~unconsumed) + { + // we would be recording extraneous modifiers + continue; + } + + if(keysymInfos.find(ks) != keysymInfos.end()) continue; - basicKeycodes[ks] = i; - basicModifiers[ks] = unconsumed & j; + KeySymInfo info; + info.keycode = i; + info.neededModifiers = mods & unconsumed; + info.modifierMask = unconsumed; + keysymInfos[ks] = info; + + ConsoleLog writeLine(QString("%1 %2 %3 %4").arg(i, 3).arg(modifiersToString(info.neededModifiers), 40).arg(modifiersToString(info.modifierMask), 40).arg(XKeysymToString(ks))); + } + + if(j == 0) + { + switch(ks) + { + case XK_Shift_L: + case XK_Shift_R: + recordModifierMapping(keybDesc, i, Qt::ShiftModifier); + break; + case XK_Control_L: + case XK_Control_R: + recordModifierMapping(keybDesc, i, Qt::ControlModifier); + break; + case XK_Meta_L: + case XK_Meta_R: + recordModifierMapping(keybDesc, i, Qt::MetaModifier); + break; + case XK_Alt_L: + case XK_Alt_R: + recordModifierMapping(keybDesc, i, Qt::AltModifier); + break; + case XK_ISO_Level3_Shift: + recordModifierMapping(keybDesc, i, Qt::GroupSwitchModifier); + break; + } } } } @@ -575,50 +609,15 @@ void initializeBasicKeycodes() XkbFreeKeyboard(keybDesc, XkbAllComponentsMask, true); } } +#endif /* HAVE_XKBLIB_H */ - // find out which keycodes cause the modifier state bits: - XModifierKeymap* modkm; - modkm = XGetModifierMapping(dpy); - - const int shiftCode = XKeysymToKeycode(dpy, XK_Shift_L); - const int controlCode = XKeysymToKeycode(dpy, XK_Control_L); - const int altCode = XKeysymToKeycode(dpy, XK_Alt_L); - const int metaCode = XKeysymToKeycode(dpy, XK_Meta_L); - const int switchCode = XKeysymToKeycode(dpy, XK_Mode_switch); - - // and use this information to find out which - // X11 modifiers correspond to Qt's modifiers: - for(int i = 0; i < 8; i++) { - for(int j = 0; j < modkm->max_keypermod; j++) { - const int idx = i * modkm->max_keypermod + j; - const int kc = modkm->modifiermap[idx]; - - ModifierToKeycode.insert(std::make_pair((1<first, 2, 16).arg(i->second, 8, 16)); } - - XFreeModifiermap(modkm); } // Translate a Qt KeyboardModifiers flag to @@ -627,7 +626,7 @@ XModifiers translateModifiers(quint32 mods) { XModifiers ret = 0; - for(int j = 1; j < 8; j++) { + for(int j = 0; j < 8; j++) { XModifiers i = 1< IntSet; IntSet pressedModifierKeys; -XModifiers currentModifiers; +XModifiers currentModifiers = 0; void trackModifiers(int keycode, bool down) { @@ -686,13 +685,15 @@ typedef std::vector TweakSequence; // and record tweaks in the tracker. void tweakModifiers(Display* dpy, XModifiers neededState, XModifiers actualState, TweakSequence& tracker) { + if(neededState == actualState) + // nothing to do. + return; + ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiersToString(neededState)).arg(modifiersToString(actualState))); for(int j = 0; j < 8; j++) { XModifiers i = 1<= ' ' && ks < 0x100) + KeySymToInfoMap::const_iterator infoIter = keysymInfos.find(ks); + if(infoIter != keysymInfos.end()) { - if(basicKeycodes[ks] != -1) + KeySymInfo info = infoIter->second; + + if(evt.isPress()) { - if(evt.isPress()) + QString format = "Trying to press the key for %1 with modifiers %2 (X: %3, Qt: %4), while current modifiers are %5 and needed are %6 with mask %7"; + if(ks >= ' ' && ks < 0x100) + { + ConsoleLog writeLine(format + .arg((char)ks) + .arg(modifiersToString(translateModifiers(evt.qtModifiers()))) + .arg(translateModifiers(evt.qtModifiers()), 2, 16) + .arg(evt.qtModifiers(), 8, 16) + .arg(modifiersToString(currentModifiers)) + .arg(modifiersToString(info.neededModifiers)) + .arg(modifiersToString(info.modifierMask))); + } + else { - // Try the simple way first: - // Does the keycode with current modifiers yield the requested symbol? - KeySym unmodSym = XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers); - ConsoleLog writeLine(QString("Pressing the key for %1 would yield %2 right now.").arg(XKeysymToString(ks)).arg(XKeysymToString(unmodSym))); + ConsoleLog writeLine(format + .arg(XKeysymToString(ks)) + .arg(modifiersToString(translateModifiers(evt.qtModifiers()))) + .arg(translateModifiers(evt.qtModifiers()), 2, 16) + .arg(evt.qtModifiers(), 8, 16) + .arg(modifiersToString(currentModifiers)) + .arg(modifiersToString(info.neededModifiers)) + .arg(modifiersToString(info.modifierMask))); + } - if(ks == XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers)) - { - XTestFakeKeyEvent(dpy, basicKeycodes[ks], 1, CurrentTime); - } - else - { - // what modifier keys do we need to press? - XModifiers mods = translateModifiers(evt.qtModifiers()); + // what modifier keys do we need to press? + XModifiers mods = translateModifiers(evt.qtModifiers()); + XModifiers needed = info.neededModifiers; + XModifiers mask = info.modifierMask; + + // This is quite ad-hoc, but we do NOT want to + // mask Alt. + // On some configurations, the F-Keys consume Alt, + // and when we AND it out, we disable Alt+Fn + // combinations. That's just wrong. + // FIXME: Are there situations + // where we actually need to keep Alt masked? + // Hint: I found none. + // If so, how do we determine that? + QtToXModifierMap::const_iterator altIter = QtToXModifier.find(Qt::AltModifier); + if(altIter != QtToXModifier.end()) + { + mask &= ~(altIter->second); + } - // we may need to press additional modifiers to generate this keysym: - if(QChar(ks, 0).isLetter()) - { - // but, since Qt does not differentiate upper and lower case, - // we need to preserve Shift and Lock in their current state. - mods |= basicModifiers[ks] & ~(1<