summaryrefslogtreecommitdiffstats
path: root/src/input/x11FakeKeyboardHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input/x11FakeKeyboardHandler.cpp')
-rw-r--r--src/input/x11FakeKeyboardHandler.cpp906
1 files changed, 906 insertions, 0 deletions
diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp
new file mode 100644
index 0000000..0c32b66
--- /dev/null
+++ b/src/input/x11FakeKeyboardHandler.cpp
@@ -0,0 +1,906 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # x11FakeKeyboardHandler.h:
+ # - Handle keyboard events on X11 - interface
+ # --------------------------------------------------------------------------
+ */
+
+#include <map>
+#include <set>
+#include <cassert>
+// Qt headers need to be included before X11 headers
+#include <QApplication>
+#include <QtCore>
+#include "x11FakeKeyboardHandler.h"
+// #include <multimap>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/keysymdef.h>
+#include <X11/extensions/XTest.h>
+#ifdef HAVE_XINPUT2_H
+# include <X11/extensions/XInput2.h>
+#else
+# include <X11/extensions/XInput.h>
+#endif
+#include <X11/XKBlib.h>
+#include <src/util/consoleLogger.h>
+#include "x11InputUtils.h"
+
+//////////////////////// INPUT EVENT TRANSLATION /////////////////////////////////
+
+typedef unsigned char xmodifier_type;
+
+char modifiernames[][8] = {
+ "SHIFT",
+ "LOCK",
+ "CONTROL",
+ "MOD1",
+ "MOD2",
+ "MOD3",
+ "MOD4",
+ "MOD5"
+};
+
+QString modifiers_to_string(xmodifier_type mods)
+{
+ QString s;
+ for(int i = 0; i < 8; i++)
+ {
+ if(mods & (1<<i))
+ {
+ s += modifiernames[i];
+ s += ", ";
+ }
+ }
+ s.chop(2);
+ return s;
+}
+
+
+typedef std::map<quint32, KeySym> 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() {
+ 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;
+ keysyms[Qt::Key_Insert] = XK_Insert;
+ keysyms[Qt::Key_Delete] = XK_Delete;
+ keysyms[Qt::Key_Pause] = XK_Pause;
+ keysyms[Qt::Key_Print] = XK_Print;
+ keysyms[Qt::Key_SysReq] = XK_Sys_Req;
+ keysyms[Qt::Key_Clear] = XK_Clear;
+ keysyms[Qt::Key_Home] = XK_Home;
+ keysyms[Qt::Key_End] = XK_End;
+ keysyms[Qt::Key_Left] = XK_Left;
+ keysyms[Qt::Key_Up] = XK_Up;
+ keysyms[Qt::Key_Right] = XK_Right;
+ keysyms[Qt::Key_Down] = XK_Down;
+ keysyms[Qt::Key_PageUp] = XK_Page_Up;
+ keysyms[Qt::Key_PageDown] = XK_Page_Down;
+ keysyms[Qt::Key_Shift] = XK_Shift_L;
+ keysyms[Qt::Key_Control] = XK_Control_L;
+ keysyms[Qt::Key_Meta] = XK_Meta_L;
+ keysyms[Qt::Key_Alt] = XK_Alt_L;
+ keysyms[Qt::Key_CapsLock] = XK_Caps_Lock;
+ keysyms[Qt::Key_NumLock] = XK_Num_Lock;
+ keysyms[Qt::Key_ScrollLock] = XK_Scroll_Lock;
+ keysyms[Qt::Key_F1] = XK_F1;
+ keysyms[Qt::Key_F2] = XK_F2;
+ keysyms[Qt::Key_F3] = XK_F3;
+ keysyms[Qt::Key_F4] = XK_F4;
+ keysyms[Qt::Key_F5] = XK_F5;
+ keysyms[Qt::Key_F6] = XK_F6;
+ keysyms[Qt::Key_F7] = XK_F7;
+ keysyms[Qt::Key_F8] = XK_F8;
+ keysyms[Qt::Key_F9] = XK_F9;
+ keysyms[Qt::Key_F10] = XK_F10;
+ keysyms[Qt::Key_F11] = XK_F11;
+ keysyms[Qt::Key_F12] = XK_F12;
+ keysyms[Qt::Key_F13] = XK_F13;
+ keysyms[Qt::Key_F14] = XK_F14;
+ keysyms[Qt::Key_F15] = XK_F15;
+ keysyms[Qt::Key_F16] = XK_F16;
+ keysyms[Qt::Key_F17] = XK_F17;
+ keysyms[Qt::Key_F18] = XK_F18;
+ keysyms[Qt::Key_F19] = XK_F19;
+ keysyms[Qt::Key_F20] = XK_F20;
+ keysyms[Qt::Key_F21] = XK_F21;
+ keysyms[Qt::Key_F22] = XK_F22;
+ keysyms[Qt::Key_F23] = XK_F23;
+ keysyms[Qt::Key_F24] = XK_F24;
+ keysyms[Qt::Key_F25] = XK_F25;
+ keysyms[Qt::Key_F26] = XK_F26;
+ keysyms[Qt::Key_F27] = XK_F27;
+ keysyms[Qt::Key_F28] = XK_F28;
+ keysyms[Qt::Key_F29] = XK_F29;
+ keysyms[Qt::Key_F30] = XK_F30;
+ keysyms[Qt::Key_F31] = XK_F31;
+ keysyms[Qt::Key_F32] = XK_F32;
+ keysyms[Qt::Key_F33] = XK_F33;
+ keysyms[Qt::Key_F34] = XK_F34;
+ keysyms[Qt::Key_F35] = XK_F35;
+ keysyms[Qt::Key_Super_L] = XK_Super_L;
+ keysyms[Qt::Key_Super_R] = XK_Super_R;
+ keysyms[Qt::Key_Menu] = XK_Menu;
+ 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;
+ 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;
+ keysyms[Qt::Key_AltGr] = XK_ISO_Level3_Shift;
+ keysyms[Qt::Key_Multi_key] = XK_Multi_key;
+ keysyms[Qt::Key_Codeinput] = XK_Codeinput;
+ keysyms[Qt::Key_SingleCandidate] = XK_SingleCandidate;
+ 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;
+ keysyms[Qt::Key_Katakana] = XK_Katakana;
+ keysyms[Qt::Key_Hiragana_Katakana] = XK_Hiragana_Katakana;
+ keysyms[Qt::Key_Zenkaku] = XK_Zenkaku;
+ keysyms[Qt::Key_Hankaku] = XK_Hankaku;
+ keysyms[Qt::Key_Zenkaku_Hankaku] = XK_Zenkaku_Hankaku;
+ keysyms[Qt::Key_Touroku] = XK_Touroku;
+ keysyms[Qt::Key_Massyo] = XK_Massyo;
+ keysyms[Qt::Key_Kana_Lock] = XK_Kana_Lock;
+ 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;
+ keysyms[Qt::Key_Hangul_Start] = XK_Hangul_Start;
+ keysyms[Qt::Key_Hangul_End] = XK_Hangul_End;
+ 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;
+ keysyms[Qt::Key_Dead_Tilde] = XK_dead_tilde;
+ keysyms[Qt::Key_Dead_Macron] = XK_dead_macron;
+ keysyms[Qt::Key_Dead_Breve] = XK_dead_breve;
+ keysyms[Qt::Key_Dead_Abovedot] = XK_dead_abovedot;
+ keysyms[Qt::Key_Dead_Diaeresis] = XK_dead_diaeresis;
+ keysyms[Qt::Key_Dead_Abovering] = XK_dead_abovering;
+ keysyms[Qt::Key_Dead_Doubleacute] = XK_dead_doubleacute;
+ keysyms[Qt::Key_Dead_Caron] = XK_dead_caron;
+ keysyms[Qt::Key_Dead_Cedilla] = XK_dead_cedilla;
+ keysyms[Qt::Key_Dead_Ogonek] = XK_dead_ogonek;
+ keysyms[Qt::Key_Dead_Iota] = XK_dead_iota;
+ keysyms[Qt::Key_Dead_Voiced_Sound] = XK_dead_voiced_sound;
+ keysyms[Qt::Key_Dead_Semivoiced_Sound] = XK_dead_semivoiced_sound;
+ 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];
+
+int xmodifier_from_qtmodifier(Qt::KeyboardModifier m) {
+ for(int i = 0; i < 8; i++) {
+ if(m == modifier_meaning[i])
+ return i;
+ }
+ return -1;
+}
+
+typedef std::map<Qt::KeyboardModifier, xmodifier_type> qt_to_xmodifier_type;
+typedef std::map<xmodifier_type, Qt::KeyboardModifier> x_to_qtmodifier_type;
+qt_to_xmodifier_type qt_to_xmodifier;
+x_to_qtmodifier_type x_to_qtmodifier;
+
+typedef std::multimap<xmodifier_type, int> modifier_to_keycode_map;
+modifier_to_keycode_map modifier_to_keycode;
+typedef std::map<int, xmodifier_type> keycode_to_modifier_map;
+keycode_to_modifier_map keycode_to_modifier;
+
+// 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
+# define XIAllDevices 1 /* does not matter */
+# define XIDeviceInfo XDeviceInfo
+# define XIQueryDevice(dpy, which, ninfos) XListInputDevices(dpy, ninfos)
+# define XIFreeDeviceInfo(infos) XFreeDeviceList(infos)
+# define XIMasterKeyboard IsXKeyboard
+# define XISlaveKeyboard IsXExtensionKeyboard
+ static inline Atom* getDeviceProperties(Display* dpy, XIDeviceInfo* devinfo, int* nprops)
+ {
+ if(devinfo->use == IsXKeyboard)
+ {
+ // According to XOpenDevice(3X11) you cannot open the Core Keyboard.
+ *nprops = 0;
+ return 0;
+ }
+
+ XDevice* dev = XOpenDevice(dpy, devinfo->id);
+ Atom* props = XListDeviceProperties(dpy, dev, nprops);
+ XCloseDevice(dpy, dev);
+ return props;
+ }
+#else
+ static inline Atom* getDeviceProperties(Display* dpy, XIDeviceInfo* devinfo, int* nprops)
+ {
+ return XIListProperties(dpy, devinfo->deviceid, nprops);
+ }
+#endif
+
+
+void initialize_basic_keycodes()
+{
+ for(int i = 0; i < 8; i++) {
+ modifier_keycodes[i] = -1;
+ }
+ for(int i = 0; i < 0x100; i++) {
+ basic_keycodes[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);
+ for(int i = 0; i < count; i++)
+ {
+ for(int j = 0; j < keysyms_per_code; j++)
+ {
+ const int idx = i * keysyms_per_code + j;
+ const KeySym ks = mapping[idx];
+ const int keycode = min_keycode + i;
+
+ 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)
+ continue; // already found
+
+ basic_keycodes[ks] = keycode;
+ basic_modifiers[ks] = j;
+ }
+ }
+ }
+ XFree(mapping);
+ }
+ else
+ {
+ // Try to find out what device XTest will send events on:
+ unsigned int xkbDeviceId = XkbUseCoreKbd;
+ Atom xtestDeviceProp = XInternAtom(dpy, "XTEST Device", false);
+ 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);
+
+ // 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++)
+ {
+ Atom prop = props[j];
+ if(prop == xtestDeviceProp)
+ {
+ // The device is the XTest Keyboard:
+ xkbDeviceId = devinfo->deviceid;
+ }
+ }
+ XFree(props);
+ }
+ }
+ XIFreeDeviceInfo(devinfos);
+#ifdef deviceid /* XInput1 */
+# undef deviceid
+#endif
+ }
+
+ // Okay, we know which device to query. Now get its keymap:
+ XkbDescPtr keybDesc = XkbGetKeyboard(dpy, XkbAllComponentsMask, xkbDeviceId);
+ if(!keybDesc)
+ {
+ 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++)
+ {
+ for(int j = 0; j <= 0xff; j++)
+ {
+ KeySym ks = 0;
+ unsigned int unconsumed;
+ if(keybDesc)
+ {
+ if(!XkbTranslateKeyCode(keybDesc, i, j, &unconsumed, &ks) || ks == NoSymbol)
+ continue;
+ }
+ else
+ {
+ if(!XkbLookupKeySym(dpy, i, j, &unconsumed, &ks) || ks == NoSymbol)
+ continue;
+ }
+
+ 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)
+ continue;
+
+ basic_keycodes[ks] = i;
+ basic_modifiers[ks] = unconsumed & j;
+ }
+ }
+ }
+
+ // Free the keyboard description:
+ if(keybDesc)
+ {
+ XkbFreeKeyboard(keybDesc, XkbAllComponentsMask, true);
+ }
+ }
+
+ // find out which keycodes cause the modifier state bits:
+ 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);
+
+ 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<<i), kc));
+ keycode_to_modifier[kc] = (1<<i);
+#define remember_modifier(qmod) do { \
+ qt_to_xmodifier[Qt::qmod##Modifier] = 1<<i; \
+ x_to_qtmodifier[1<<i] = Qt::qmod##Modifier; \
+} while(false)
+ if(kc == shift_kc) {
+ remember_modifier(Shift);
+ } else if(kc == control_kc) {
+ remember_modifier(Control);
+ } else if(kc == alt_kc) {
+ remember_modifier(Alt);
+ } else if(kc == meta_kc) {
+ remember_modifier(Meta);
+ } else if(kc == switch_kc) {
+ remember_modifier(GroupSwitch);
+ }
+#undef remember_modifier
+
+ if(modifier_keycodes[i] != -1) {
+ continue; // already found
+ }
+
+ // select one arbitrarily
+ modifier_keycodes[i] = kc;
+ }
+ }
+
+ XFreeModifiermap(modkm);
+}
+
+xmodifier_type translate_modifiers(quint32 mods)
+{
+ xmodifier_type ret = 0;
+
+ for(int j = 1; j < 8; j++) {
+ xmodifier_type i = 1<<j;
+
+ if(mods & x_to_qtmodifier[i])
+ {
+ ret |= i;
+ }
+ }
+
+ return ret;
+}
+
+typedef std::set<int> int_set_type;
+int_set_type pressed_modifier_keys;
+xmodifier_type current_modifiers;
+
+void trackModifiers(int keycode, bool down)
+{
+ // is this a modifier key?
+ const bool is_modifier = keycode_to_modifier.find(keycode) != keycode_to_modifier.end();
+
+ if(!is_modifier)
+ {
+ return;
+ }
+
+ if(down) {
+ pressed_modifier_keys.insert(keycode);
+ } else {
+ pressed_modifier_keys.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++)
+ {
+ keycode_to_modifier_map::iterator found_kc = keycode_to_modifier.find(*i);
+ if(found_kc != keycode_to_modifier.end())
+ {
+ modifs |= (*found_kc).second;
+ }
+ }
+ current_modifiers = modifs;
+
+ ConsoleLog writeLine(QString("[trackModifiers] current modifiers: %1").arg(modifiers_to_string(modifs)));
+}
+
+typedef std::pair<int, bool> modifier_tweak_type;
+typedef std::vector<modifier_tweak_type> tweak_sequence_type;
+
+void tweakModifiers(Display* dpy, xmodifier_type neededState, xmodifier_type actualState, tweak_sequence_type& tracker)
+{
+ ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiers_to_string(neededState)).arg(modifiers_to_string(actualState)));
+ for(int j = 0; j < 8; j++)
+ {
+ xmodifier_type i = 1<<j;
+
+ ConsoleLog writeLine(QString("Checking for %1...").arg(modifiers_to_string(i)));
+
+ if((i & neededState) && !(i & actualState))
+ {
+ ConsoleLog writeLine(QString("tweakModifiers: Modifier %1 needs to be pressed").arg(modifiernames[j]));
+
+ // needs to be pressed
+
+ //find the keycode:
+ int kc;
+ modifier_to_keycode_map::iterator iter = modifier_to_keycode.find(i);
+
+ if((iter == modifier_to_keycode.end()) || ((*iter).first != i))
+ {
+ continue; // we don't know a key that triggers this modifier
+ }
+
+ ConsoleLog writeLine(QString(" pressing key %1").arg((*iter).second));
+ XTestFakeKeyEvent(dpy, (*iter).second, 1, CurrentTime);
+
+ tracker.push_back(std::make_pair((*iter).second, true));
+ }
+ else if((!(i & neededState)) && (i & actualState))
+ {
+ ConsoleLog writeLine(QString("tweakModifiers: Modifier %1 needs to be released").arg(modifiernames[j]));
+
+ // needs to be released
+
+ int kc = -1;
+ // first, check whether any of the currently pressed keys has triggered this modifier:
+
+ int_set_type::iterator iter, end = pressed_modifier_keys.end();
+ for(iter = pressed_modifier_keys.begin(); iter != end; iter++)
+ {
+ keycode_to_modifier_map::iterator modmap_iter = keycode_to_modifier.find(*iter);
+ if(modmap_iter != keycode_to_modifier.end()) {
+ if(modmap_iter->second == i) {
+ 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));
+ }
+ }
+ }
+
+ if(kc == -1) {
+ // strange, but we need to release some other key:
+ // we don't know which one, so we abort this and hope for the best
+ continue;
+ }
+ }
+ }
+}
+
+void untweakModifiers(Display* dpy, tweak_sequence_type& tracker)
+{
+ tweak_sequence_type::iterator i, end = tracker.end();
+ for(i = tracker.begin(); i != end; i++) {
+ modifier_tweak_type& t = *i;
+ XTestFakeKeyEvent(dpy, t.first, !t.second, CurrentTime);
+ }
+}
+
+void X11FakeKeyboardHandler::initialize()
+{
+ initialize_keysyms();
+ initialize_basic_keycodes();
+ pressed_modifier_keys.clear();
+ current_modifiers = 0;
+}
+
+void X11FakeKeyboardHandler::handle(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());
+ 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())
+ {
+ case Qt::Key_Backtab:
+ handle(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));
+ }
+ } else {
+ KeySym ks = (*i).second;
+
+ // is it a "normal" key?
+ if(ks >= ' ' && ks < 0x100)
+ {
+ if(basic_keycodes[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)));
+
+ if(ks == XKeycodeToKeysym(dpy, basic_keycodes[ks], current_modifiers))
+ {
+ XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime);
+ }
+ else
+ {
+ // what modifier keys do we need to press?
+ xmodifier_type mods = translate_modifiers(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<<ShiftMapIndex) & ~(1<<LockMapIndex);
+ }
+ else
+ {
+ // Not an alpha character. We do need to respect Shift and Lock for those:
+ mods |= basic_modifiers[ks];
+ }
+
+ // now, tweak the modifiers
+ tweak_sequence_type tweaks;
+ tweakModifiers(dpy, mods, current_modifiers, tweaks);
+
+ // press the key:
+ XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime);
+
+ // and release the modifiers:
+ untweakModifiers(dpy, tweaks);
+ }
+ }
+ else
+ {
+ // just release the key.
+ XTestFakeKeyEvent(dpy, basic_keycodes[ks], 0, CurrentTime);
+ }
+ }
+ else
+ {
+ ConsoleLog writeLine(QString("No keycode is mapped to `%1'").arg(XKeysymToString(ks)));
+ }
+ }
+ 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)));
+ }
+ }
+ }
+
+ // Since there may not be a mainloop running, we need to manually flush the event queue
+ XFlush(dpy);
+}