summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSebastien Braun2010-10-10 17:08:49 +0200
committerSebastien Braun2010-10-11 00:56:09 +0200
commit2e072d898609ef8dfb5270a07e3212498648d048 (patch)
tree790a33e4ada52517a95d2da36857fb83f77b3ad9 /src
parentRemove leftover code that serves no purpose (diff)
downloadpvs-2e072d898609ef8dfb5270a07e3212498648d048.tar.gz
pvs-2e072d898609ef8dfb5270a07e3212498648d048.tar.xz
pvs-2e072d898609ef8dfb5270a07e3212498648d048.zip
Code cleanup and simplification for X11FakeKeyboardHandler
Diffstat (limited to 'src')
-rw-r--r--src/input/CMakeLists.txt32
-rw-r--r--src/input/x11FakeKeyboardHandler.cpp655
2 files changed, 358 insertions, 329 deletions
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<KeySym, KeySymInfo> 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<XModifiers, Qt::KeyboardModifier> XToQtModifierMap;
XToQtModifierMap XToQtModifier;
+typedef std::map<Qt::KeyboardModifier, XModifiers> QtToXModifierMap;
+QtToXModifierMap QtToXModifier;
+
// And how do the modifiers relate to Keycodes?
typedef std::multimap<XModifiers, int> ModifierToKeycodeMap;
@@ -395,6 +283,36 @@ ModifierToKeycodeMap ModifierToKeycode;
typedef std::map<int, XModifiers> 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<KeySym> 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<<i), kc));
+ KeycodeToModifier[kc] = (1<<i);
+ if(kc == shiftCode) {
+ XToQtModifier[1<<i] = Qt::ShiftModifier;
+ } else if(kc == controlCode) {
+ XToQtModifier[1<<i] = Qt::ControlModifier;
+ } else if(kc == altCode) {
+ XToQtModifier[1<<i] = Qt::AltModifier;
+ } else if(kc == metaCode) {
+ XToQtModifier[1<<i] = Qt::MetaModifier;
+ } else if(kc == switchCode) {
+ XToQtModifier[1<<i] = Qt::GroupSwitchModifier;
+ }
+
+ // and record the keycode we need to press/release
+ // to activate or deactivate a modifier:
+ if(modifierKeycodes[i] != -1) {
+ continue; // already found
+ }
+
+ // select one arbitrarily
+ modifierKeycodes[i] = kc;
+ }
+ }
+
+ XFreeModifiermap(modkm);
}
+#ifdef HAVE_XKBLIB_H
else
{
// XKB is present.
@@ -488,46 +471,59 @@ void initializeBasicKeycodes()
// 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)
+
+ // Is XInput present?
+#if defined(HAVE_XINPUT_H) || defined(HAVE_XINPUT2_H)
+ // We don't care about these:
+ int i1, i2, i3;
+ bool haveXInput = XQueryExtension(dpy, "XInputExtension", &i1, &i2, &i3);
+
+ if(haveXInput)
{
+ Atom xtestDeviceProp = XInternAtom(dpy, "XTEST Device", false);
+
+ // Find the list of input devices:
+ int ndevinfos;
+ XIDeviceInfo* devinfos = XIQueryDevice(dpy, XIAllDevices, &ndevinfos);
+ if(devinfos)
+ {
#ifndef HAVE_XINPUT2_H
# define deviceid id
#endif
- 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);
+ 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<<i), kc));
- KeycodeToModifier[kc] = (1<<i);
- if(kc == shiftCode) {
- XToQtModifier[1<<i] = Qt::ShiftModifier;
- } else if(kc == controlCode) {
- XToQtModifier[1<<i] = Qt::ControlModifier;
- } else if(kc == altCode) {
- XToQtModifier[1<<i] = Qt::ShiftModifier;
- } else if(kc == metaCode) {
- XToQtModifier[1<<i] = Qt::MetaModifier;
- } else if(kc == switchCode) {
- XToQtModifier[1<<i] = Qt::GroupSwitchModifier;
- }
-
- // and record the keycode we need to press/release
- // to activate or deactivate a modifier:
- if(modifierKeycodes[i] != -1) {
- continue; // already found
- }
-
- // select one arbitrarily
- modifierKeycodes[i] = kc;
- }
+ ConsoleLog writeLine("After initialization, XToQtModifier has the following entries:");
+ for(XToQtModifierMap::const_iterator i = XToQtModifier.begin();
+ i != XToQtModifier.end();
+ i++)
+ {
+ ConsoleLog writeLine(QString(" %1 %2").arg(i->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<<j;
if(mods & XToQtModifier[i])
@@ -643,7 +642,7 @@ XModifiers translateModifiers(quint32 mods)
// are currently active
typedef std::set<int> IntSet;
IntSet pressedModifierKeys;
-XModifiers currentModifiers;
+XModifiers currentModifiers = 0;
void trackModifiers(int keycode, bool down)
{
@@ -686,13 +685,15 @@ typedef std::vector<ModifierTweak> 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<<j;
- ConsoleLog writeLine(QString("Checking for %1...").arg(modifiersToString(i)));
-
// Do we need to activate the modifier?
if((i & neededState) && !(i & actualState))
{
@@ -707,7 +708,6 @@ void tweakModifiers(Display* dpy, XModifiers neededState, XModifiers actualState
continue;
}
- ConsoleLog writeLine(QString(" pressing key %1").arg((*iter).second));
XTestFakeKeyEvent(dpy, (*iter).second, 1, CurrentTime);
// record the tweak
@@ -730,7 +730,6 @@ void tweakModifiers(Display* dpy, XModifiers neededState, XModifiers actualState
kc = *iter;
// release this key:
- ConsoleLog writeLine(QString(" releasing key %1").arg(kc));
XTestFakeKeyEvent(dpy, kc, 0, CurrentTime);
tracker.push_back(std::make_pair(kc, false));
}
@@ -749,8 +748,8 @@ void tweakModifiers(Display* dpy, XModifiers neededState, XModifiers actualState
// Undo a recorded sequence of modifier tweaks
void untweakModifiers(Display* dpy, TweakSequence& tracker)
{
- TweakSequence::iterator i, end = tracker.end();
- for(i = tracker.begin(); i != end; i++) {
+ TweakSequence::reverse_iterator i, end = tracker.rend();
+ for(i = tracker.rbegin(); i != end; i++) {
ModifierTweak& t = *i;
XTestFakeKeyEvent(dpy, t.first, !t.second, CurrentTime);
}
@@ -771,95 +770,103 @@ void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext c
{
Display* dpy = X11InputUtils::display();
+ XTestGrabControl(dpy, 1);
+
// find out which keysym caused this event:
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.qtKeysym())
- {
- case Qt::Key_Backtab:
- doHandle(InputEvent(evt.type(), evt.code(), evt.qtModifiers() | Qt::ShiftModifier | Qt::Key_Tab));
- break;
- default:
- ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qtKeysym(), 8, 16));
- }
+ ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qtKeysym(), 8, 16));
} else {
KeySym ks = (*i).second;
- // is it a "normal" key?
- if(ks >= ' ' && 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<<ShiftMapIndex) & ~(1<<LockMapIndex);
- }
- else
- {
- // Not a letter. We do need to respect Shift and Lock for those:
- mods |= basicModifiers[ks];
- }
+ // Determine which modifiers actually need to be active
+ XModifiers neededMods;
+ neededMods = (mods
+ & (needed | ~mask)) // Cleer the needed-clear modifiers
+ | (needed & mask); // Set the needed-set modifiers
- // now, tweak the modifiers
- TweakSequence tweaks;
- tweakModifiers(dpy, mods, currentModifiers, tweaks);
+ // Modifiers need to be tracked BEFORE tweaking, as we may be
+ // pressing a modifier key, and we don't want to release it
+ // when untweaking.
+ trackModifiers(info.keycode, true);
- // press the key:
- XTestFakeKeyEvent(dpy, basicKeycodes[ks], 1, CurrentTime);
+ // now, tweak the modifiers
+ TweakSequence tweaks;
+ tweakModifiers(dpy, neededMods, currentModifiers, tweaks);
- // and release the modifiers:
- untweakModifiers(dpy, tweaks);
- }
- }
- else
- {
- // just release the key.
- XTestFakeKeyEvent(dpy, basicKeycodes[ks], 0, CurrentTime);
- }
+ // press the key:
+ XTestFakeKeyEvent(dpy, info.keycode, 1, CurrentTime);
+
+ // and release the modifiers:
+ untweakModifiers(dpy, tweaks);
}
else
{
- ConsoleLog writeLine(QString("No keycode is mapped to `%1'").arg(XKeysymToString(ks)));
+ // just release the key.
+ XTestFakeKeyEvent(dpy, info.keycode, 0, CurrentTime);
+ trackModifiers(info.keycode, false);
}
}
else
{
- // It is some kind of "special" key, so we just fake that, then:
- KeyCode kc = XKeysymToKeycode(dpy, ks);
- if(kc != 0)
- {
- ConsoleLog writeLine(QString("%1 special keycode %2, hopefully giving keysym %3").arg(evt.isPress() ? "Pressed" : "Released").arg(kc).arg(XKeysymToString(ks)));
- XTestFakeKeyEvent(dpy, kc, evt.isPress(), CurrentTime);
- // and track it if it is a modifier key:
- trackModifiers(kc, evt.isPress());
- }
- else
- {
- ConsoleLog writeLine(QString("No keycode is mapped to %1").arg(XKeysymToString(ks)));
- }
+ ConsoleLog writeLine(QString("No keycode is mapped to `%1'").arg(XKeysymToString(ks)));
}
}
+ XTestGrabControl(dpy, 0);
+
// Since there may not be a mainloop running, we need to manually flush the event queue
XFlush(dpy);
}