| 1 | /**************************************************************************** | 
|---|
| 2 | ** | 
|---|
| 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | 
|---|
| 4 | ** All rights reserved. | 
|---|
| 5 | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
|---|
| 6 | ** | 
|---|
| 7 | ** This file is part of the tools module of the Qt Toolkit. | 
|---|
| 8 | ** | 
|---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$ | 
|---|
| 10 | ** Commercial Usage | 
|---|
| 11 | ** Licensees holding valid Qt Commercial licenses may use this file in | 
|---|
| 12 | ** accordance with the Qt Commercial License Agreement provided with the | 
|---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in | 
|---|
| 14 | ** a written agreement between you and Nokia. | 
|---|
| 15 | ** | 
|---|
| 16 | ** GNU Lesser General Public License Usage | 
|---|
| 17 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
|---|
| 18 | ** General Public License version 2.1 as published by the Free Software | 
|---|
| 19 | ** Foundation and appearing in the file LICENSE.LGPL included in the | 
|---|
| 20 | ** packaging of this file.  Please review the following information to | 
|---|
| 21 | ** ensure the GNU Lesser General Public License version 2.1 requirements | 
|---|
| 22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | 
|---|
| 23 | ** | 
|---|
| 24 | ** In addition, as a special exception, Nokia gives you certain additional | 
|---|
| 25 | ** rights.  These rights are described in the Nokia Qt LGPL Exception | 
|---|
| 26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | 
|---|
| 27 | ** | 
|---|
| 28 | ** GNU General Public License Usage | 
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU | 
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software | 
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the | 
|---|
| 32 | ** packaging of this file.  Please review the following information to | 
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be | 
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html. | 
|---|
| 35 | ** | 
|---|
| 36 | ** If you have questions regarding the use of this file, please contact | 
|---|
| 37 | ** Nokia at qt-info@nokia.com. | 
|---|
| 38 | ** $QT_END_LICENSE$ | 
|---|
| 39 | ** | 
|---|
| 40 | ****************************************************************************/ | 
|---|
| 41 |  | 
|---|
| 42 | #include "x11keyfaker.h" | 
|---|
| 43 | #include <QTimer> | 
|---|
| 44 | #include <QSocketNotifier> | 
|---|
| 45 | #include <QDebug> | 
|---|
| 46 | #include <X11/Xlib.h> | 
|---|
| 47 | #include <X11/cursorfont.h> | 
|---|
| 48 | #include <X11/extensions/XTest.h> | 
|---|
| 49 | #include <X11/keysym.h> | 
|---|
| 50 | #include <X11/XF86keysym.h> | 
|---|
| 51 | #include "qtopiakeysym.h" | 
|---|
| 52 | #include <unistd.h> | 
|---|
| 53 | #include <fcntl.h> | 
|---|
| 54 |  | 
|---|
| 55 | QT_BEGIN_NAMESPACE | 
|---|
| 56 |  | 
|---|
| 57 | X11KeyFaker::X11KeyFaker(const QString& displayName, QObject *parent) | 
|---|
| 58 | : QObject(parent) | 
|---|
| 59 | { | 
|---|
| 60 | this->displayName = displayName; | 
|---|
| 61 | this->dpy = 0; | 
|---|
| 62 | this->retryCount = 0; | 
|---|
| 63 | this->shiftKeycode = 0; | 
|---|
| 64 | this->modeSwitchKeycode = 0; | 
|---|
| 65 | this->modifiers = 0; | 
|---|
| 66 | connect(); | 
|---|
| 67 | } | 
|---|
| 68 |  | 
|---|
| 69 | X11KeyFaker::~X11KeyFaker() | 
|---|
| 70 | { | 
|---|
| 71 | if (dpy) | 
|---|
| 72 | XCloseDisplay(dpy); | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | void X11KeyFaker::sendKeyEvent(int qtCode, bool isPress) | 
|---|
| 76 | { | 
|---|
| 77 | if (!dpy) | 
|---|
| 78 | return; | 
|---|
| 79 |  | 
|---|
| 80 | // Convert the Qt key code into an X keysym. | 
|---|
| 81 | KeySym keysym = NoSymbol; | 
|---|
| 82 | switch (qtCode) { | 
|---|
| 83 | case Qt::Key_Escape: keysym = XK_Escape; break; | 
|---|
| 84 | case Qt::Key_Tab: keysym = XK_Tab; break; | 
|---|
| 85 | case Qt::Key_Backtab: keysym = XK_ISO_Left_Tab; break; | 
|---|
| 86 | case Qt::Key_Backspace: keysym = XK_BackSpace; break; | 
|---|
| 87 | case Qt::Key_Return: keysym = XK_Return; break; | 
|---|
| 88 | case Qt::Key_Enter: keysym = XK_KP_Enter; break; | 
|---|
| 89 | case Qt::Key_Insert: keysym = XK_KP_Insert; break; | 
|---|
| 90 | case Qt::Key_Delete: keysym = XK_KP_Delete; break; | 
|---|
| 91 | case Qt::Key_Pause: keysym = XK_Pause; break; | 
|---|
| 92 | case Qt::Key_Print: keysym = XK_Print; break; | 
|---|
| 93 | case Qt::Key_SysReq: keysym = 0x1005FF60; break; | 
|---|
| 94 | case Qt::Key_Clear: keysym = XK_KP_Begin; break; | 
|---|
| 95 | case Qt::Key_Home: keysym = XK_Home; break; | 
|---|
| 96 | case Qt::Key_End: keysym = XK_End; break; | 
|---|
| 97 | case Qt::Key_Left: keysym = XK_Left; break; | 
|---|
| 98 | case Qt::Key_Up: keysym = XK_Up; break; | 
|---|
| 99 | case Qt::Key_Right: keysym = XK_Right; break; | 
|---|
| 100 | case Qt::Key_Down: keysym = XK_Down; break; | 
|---|
| 101 | case Qt::Key_PageUp: keysym = XK_Prior; break; | 
|---|
| 102 | case Qt::Key_PageDown: keysym = XK_Next; break; | 
|---|
| 103 | case Qt::Key_Shift: keysym = XK_Shift_L; break; | 
|---|
| 104 | case Qt::Key_Control: keysym = XK_Control_L; break; | 
|---|
| 105 | case Qt::Key_Meta: keysym = XK_Meta_L; break; | 
|---|
| 106 | case Qt::Key_Alt: keysym = XK_Alt_L; break; | 
|---|
| 107 | case Qt::Key_CapsLock: keysym = XK_Caps_Lock; break; | 
|---|
| 108 | case Qt::Key_NumLock: keysym = XK_Num_Lock; break; | 
|---|
| 109 | case Qt::Key_ScrollLock: keysym = XK_Scroll_Lock; break; | 
|---|
| 110 | case Qt::Key_F1: keysym = XK_F1; break; | 
|---|
| 111 | case Qt::Key_F2: keysym = XK_F2; break; | 
|---|
| 112 | case Qt::Key_F3: keysym = XK_F3; break; | 
|---|
| 113 | case Qt::Key_F4: keysym = XK_F4; break; | 
|---|
| 114 | case Qt::Key_F5: keysym = XK_F5; break; | 
|---|
| 115 | case Qt::Key_F6: keysym = XK_F6; break; | 
|---|
| 116 | case Qt::Key_F7: keysym = XK_F7; break; | 
|---|
| 117 | case Qt::Key_F8: keysym = XK_F8; break; | 
|---|
| 118 | case Qt::Key_F9: keysym = XK_F9; break; | 
|---|
| 119 | case Qt::Key_F10: keysym = XK_F10; break; | 
|---|
| 120 | case Qt::Key_F11: keysym = XK_F11; break; | 
|---|
| 121 | case Qt::Key_F12: keysym = XK_F12; break; | 
|---|
| 122 | case Qt::Key_F13: keysym = XK_F13; break; | 
|---|
| 123 | case Qt::Key_F14: keysym = XK_F14; break; | 
|---|
| 124 | case Qt::Key_F15: keysym = XK_F15; break; | 
|---|
| 125 | case Qt::Key_F16: keysym = XK_F16; break; | 
|---|
| 126 | case Qt::Key_F17: keysym = XK_F17; break; | 
|---|
| 127 | case Qt::Key_F18: keysym = XK_F18; break; | 
|---|
| 128 | case Qt::Key_F19: keysym = XK_F19; break; | 
|---|
| 129 | case Qt::Key_F20: keysym = XK_F20; break; | 
|---|
| 130 | case Qt::Key_F21: keysym = XK_F21; break; | 
|---|
| 131 | case Qt::Key_F22: keysym = XK_F22; break; | 
|---|
| 132 | case Qt::Key_F23: keysym = XK_F23; break; | 
|---|
| 133 | case Qt::Key_F24: keysym = XK_F24; break; | 
|---|
| 134 | case Qt::Key_F25: keysym = XK_F25; break; | 
|---|
| 135 | case Qt::Key_F26: keysym = XK_F26; break; | 
|---|
| 136 | case Qt::Key_F27: keysym = XK_F27; break; | 
|---|
| 137 | case Qt::Key_F28: keysym = XK_F28; break; | 
|---|
| 138 | case Qt::Key_F29: keysym = XK_F29; break; | 
|---|
| 139 | case Qt::Key_F30: keysym = XK_F30; break; | 
|---|
| 140 | case Qt::Key_F31: keysym = XK_F31; break; | 
|---|
| 141 | case Qt::Key_F32: keysym = XK_F32; break; | 
|---|
| 142 | case Qt::Key_F33: keysym = XK_F33; break; | 
|---|
| 143 | case Qt::Key_F34: keysym = XK_F34; break; | 
|---|
| 144 | case Qt::Key_F35: keysym = XK_F35; break; | 
|---|
| 145 | case Qt::Key_Super_L: keysym = XK_Super_L; break; | 
|---|
| 146 | case Qt::Key_Super_R: keysym = XK_Super_R; break; | 
|---|
| 147 | case Qt::Key_Menu: keysym = XK_Menu; break; | 
|---|
| 148 | case Qt::Key_Hyper_L: keysym = XK_Hyper_L; break; | 
|---|
| 149 | case Qt::Key_Hyper_R: keysym = XK_Hyper_R; break; | 
|---|
| 150 | case Qt::Key_Help: keysym = XK_Help; break; | 
|---|
| 151 | case Qt::Key_Direction_L: keysym = NoSymbol; break; // ??? | 
|---|
| 152 | case Qt::Key_Direction_R: keysym = NoSymbol; break; // ??? | 
|---|
| 153 | case Qt::Key_Space: keysym = XK_space; break; | 
|---|
| 154 | case Qt::Key_Exclam: keysym = XK_exclam; break; | 
|---|
| 155 | case Qt::Key_QuoteDbl: keysym = XK_quotedbl; break; | 
|---|
| 156 | case Qt::Key_NumberSign: keysym = XK_numbersign; break; | 
|---|
| 157 | case Qt::Key_Dollar: keysym = XK_dollar; break; | 
|---|
| 158 | case Qt::Key_Percent: keysym = XK_percent; break; | 
|---|
| 159 | case Qt::Key_Ampersand: keysym = XK_ampersand; break; | 
|---|
| 160 | case Qt::Key_Apostrophe: keysym = XK_apostrophe; break; | 
|---|
| 161 | case Qt::Key_ParenLeft: keysym = XK_parenleft; break; | 
|---|
| 162 | case Qt::Key_ParenRight: keysym = XK_parenright; break; | 
|---|
| 163 | case Qt::Key_Asterisk: keysym = XK_asterisk; break; | 
|---|
| 164 | case Qt::Key_Plus: keysym = XK_plus; break; | 
|---|
| 165 | case Qt::Key_Comma: keysym = XK_comma; break; | 
|---|
| 166 | case Qt::Key_Minus: keysym = XK_minus; break; | 
|---|
| 167 | case Qt::Key_Period: keysym = XK_period; break; | 
|---|
| 168 | case Qt::Key_Slash: keysym = XK_slash; break; | 
|---|
| 169 | case Qt::Key_0: keysym = XK_0; break; | 
|---|
| 170 | case Qt::Key_1: keysym = XK_1; break; | 
|---|
| 171 | case Qt::Key_2: keysym = XK_2; break; | 
|---|
| 172 | case Qt::Key_3: keysym = XK_3; break; | 
|---|
| 173 | case Qt::Key_4: keysym = XK_4; break; | 
|---|
| 174 | case Qt::Key_5: keysym = XK_5; break; | 
|---|
| 175 | case Qt::Key_6: keysym = XK_6; break; | 
|---|
| 176 | case Qt::Key_7: keysym = XK_7; break; | 
|---|
| 177 | case Qt::Key_8: keysym = XK_8; break; | 
|---|
| 178 | case Qt::Key_9: keysym = XK_9; break; | 
|---|
| 179 | case Qt::Key_Colon: keysym = XK_colon; break; | 
|---|
| 180 | case Qt::Key_Semicolon: keysym = XK_semicolon; break; | 
|---|
| 181 | case Qt::Key_Less: keysym = XK_less; break; | 
|---|
| 182 | case Qt::Key_Equal: keysym = XK_equal; break; | 
|---|
| 183 | case Qt::Key_Greater: keysym = XK_greater; break; | 
|---|
| 184 | case Qt::Key_Question: keysym = XK_question; break; | 
|---|
| 185 | case Qt::Key_At: keysym = XK_at; break; | 
|---|
| 186 | case Qt::Key_A: keysym = XK_a; break; // Must be lower case keysyms | 
|---|
| 187 | case Qt::Key_B: keysym = XK_b; break; // for correct shift handling. | 
|---|
| 188 | case Qt::Key_C: keysym = XK_c; break; | 
|---|
| 189 | case Qt::Key_D: keysym = XK_d; break; | 
|---|
| 190 | case Qt::Key_E: keysym = XK_e; break; | 
|---|
| 191 | case Qt::Key_F: keysym = XK_f; break; | 
|---|
| 192 | case Qt::Key_G: keysym = XK_g; break; | 
|---|
| 193 | case Qt::Key_H: keysym = XK_h; break; | 
|---|
| 194 | case Qt::Key_I: keysym = XK_i; break; | 
|---|
| 195 | case Qt::Key_J: keysym = XK_j; break; | 
|---|
| 196 | case Qt::Key_K: keysym = XK_k; break; | 
|---|
| 197 | case Qt::Key_L: keysym = XK_l; break; | 
|---|
| 198 | case Qt::Key_M: keysym = XK_m; break; | 
|---|
| 199 | case Qt::Key_N: keysym = XK_n; break; | 
|---|
| 200 | case Qt::Key_O: keysym = XK_o; break; | 
|---|
| 201 | case Qt::Key_P: keysym = XK_p; break; | 
|---|
| 202 | case Qt::Key_Q: keysym = XK_q; break; | 
|---|
| 203 | case Qt::Key_R: keysym = XK_r; break; | 
|---|
| 204 | case Qt::Key_S: keysym = XK_s; break; | 
|---|
| 205 | case Qt::Key_T: keysym = XK_t; break; | 
|---|
| 206 | case Qt::Key_U: keysym = XK_u; break; | 
|---|
| 207 | case Qt::Key_V: keysym = XK_v; break; | 
|---|
| 208 | case Qt::Key_W: keysym = XK_w; break; | 
|---|
| 209 | case Qt::Key_X: keysym = XK_x; break; | 
|---|
| 210 | case Qt::Key_Y: keysym = XK_y; break; | 
|---|
| 211 | case Qt::Key_Z: keysym = XK_z; break; | 
|---|
| 212 | case Qt::Key_BracketLeft: keysym = XK_bracketleft; break; | 
|---|
| 213 | case Qt::Key_Backslash: keysym = XK_backslash; break; | 
|---|
| 214 | case Qt::Key_BracketRight: keysym = XK_bracketright; break; | 
|---|
| 215 | case Qt::Key_AsciiCircum: keysym = XK_asciicircum; break; | 
|---|
| 216 | case Qt::Key_Underscore: keysym = XK_underscore; break; | 
|---|
| 217 | case Qt::Key_QuoteLeft: keysym = XK_quoteleft; break; | 
|---|
| 218 | case Qt::Key_BraceLeft: keysym = XK_braceleft; break; | 
|---|
| 219 | case Qt::Key_Bar: keysym = XK_bar; break; | 
|---|
| 220 | case Qt::Key_BraceRight: keysym = XK_braceright; break; | 
|---|
| 221 | case Qt::Key_AsciiTilde: keysym = XK_asciitilde; break; | 
|---|
| 222 |  | 
|---|
| 223 | case Qt::Key_nobreakspace: keysym = XK_nobreakspace; break; | 
|---|
| 224 | case Qt::Key_exclamdown: keysym = XK_exclamdown; break; | 
|---|
| 225 | case Qt::Key_cent: keysym = XK_cent; break; | 
|---|
| 226 | case Qt::Key_sterling: keysym = XK_sterling; break; | 
|---|
| 227 | case Qt::Key_currency: keysym = XK_currency; break; | 
|---|
| 228 | case Qt::Key_yen: keysym = XK_yen; break; | 
|---|
| 229 | case Qt::Key_brokenbar: keysym = XK_brokenbar; break; | 
|---|
| 230 | case Qt::Key_section: keysym = XK_section; break; | 
|---|
| 231 | case Qt::Key_diaeresis: keysym = XK_diaeresis; break; | 
|---|
| 232 | case Qt::Key_copyright: keysym = XK_copyright; break; | 
|---|
| 233 | case Qt::Key_ordfeminine: keysym = XK_ordfeminine; break; | 
|---|
| 234 | case Qt::Key_guillemotleft: keysym = XK_guillemotleft; break; | 
|---|
| 235 | case Qt::Key_notsign: keysym = XK_notsign; break; | 
|---|
| 236 | case Qt::Key_hyphen: keysym = XK_hyphen; break; | 
|---|
| 237 | case Qt::Key_registered: keysym = XK_registered; break; | 
|---|
| 238 | case Qt::Key_macron: keysym = XK_macron; break; | 
|---|
| 239 | case Qt::Key_degree: keysym = XK_degree; break; | 
|---|
| 240 | case Qt::Key_plusminus: keysym = XK_plusminus; break; | 
|---|
| 241 | case Qt::Key_twosuperior: keysym = XK_twosuperior; break; | 
|---|
| 242 | case Qt::Key_threesuperior: keysym = XK_threesuperior; break; | 
|---|
| 243 | case Qt::Key_acute: keysym = XK_acute; break; | 
|---|
| 244 | case Qt::Key_mu: keysym = XK_mu; break; | 
|---|
| 245 | case Qt::Key_paragraph: keysym = XK_paragraph; break; | 
|---|
| 246 | case Qt::Key_periodcentered: keysym = XK_periodcentered; break; | 
|---|
| 247 | case Qt::Key_cedilla: keysym = XK_cedilla; break; | 
|---|
| 248 | case Qt::Key_onesuperior: keysym = XK_onesuperior; break; | 
|---|
| 249 | case Qt::Key_masculine: keysym = XK_masculine; break; | 
|---|
| 250 | case Qt::Key_guillemotright: keysym = XK_guillemotright; break; | 
|---|
| 251 | case Qt::Key_onequarter: keysym = XK_onequarter; break; | 
|---|
| 252 | case Qt::Key_onehalf: keysym = XK_onehalf; break; | 
|---|
| 253 | case Qt::Key_threequarters: keysym = XK_threequarters; break; | 
|---|
| 254 | case Qt::Key_questiondown: keysym = XK_questiondown; break; | 
|---|
| 255 | case Qt::Key_Agrave: keysym = XK_agrave; break; // Lower case keysyms | 
|---|
| 256 | case Qt::Key_Aacute: keysym = XK_aacute; break; // for shift handling. | 
|---|
| 257 | case Qt::Key_Acircumflex: keysym = XK_acircumflex; break; | 
|---|
| 258 | case Qt::Key_Atilde: keysym = XK_atilde; break; | 
|---|
| 259 | case Qt::Key_Adiaeresis: keysym = XK_adiaeresis; break; | 
|---|
| 260 | case Qt::Key_Aring: keysym = XK_aring; break; | 
|---|
| 261 | case Qt::Key_AE: keysym = XK_ae; break; | 
|---|
| 262 | case Qt::Key_Ccedilla: keysym = XK_ccedilla; break; | 
|---|
| 263 | case Qt::Key_Egrave: keysym = XK_egrave; break; | 
|---|
| 264 | case Qt::Key_Eacute: keysym = XK_eacute; break; | 
|---|
| 265 | case Qt::Key_Ecircumflex: keysym = XK_ecircumflex; break; | 
|---|
| 266 | case Qt::Key_Ediaeresis: keysym = XK_ediaeresis; break; | 
|---|
| 267 | case Qt::Key_Igrave: keysym = XK_igrave; break; | 
|---|
| 268 | case Qt::Key_Iacute: keysym = XK_iacute; break; | 
|---|
| 269 | case Qt::Key_Icircumflex: keysym = XK_icircumflex; break; | 
|---|
| 270 | case Qt::Key_Idiaeresis: keysym = XK_idiaeresis; break; | 
|---|
| 271 | case Qt::Key_ETH: keysym = XK_eth; break; | 
|---|
| 272 | case Qt::Key_Ntilde: keysym = XK_ntilde; break; | 
|---|
| 273 | case Qt::Key_Ograve: keysym = XK_ograve; break; | 
|---|
| 274 | case Qt::Key_Oacute: keysym = XK_oacute; break; | 
|---|
| 275 | case Qt::Key_Ocircumflex: keysym = XK_ocircumflex; break; | 
|---|
| 276 | case Qt::Key_Otilde: keysym = XK_otilde; break; | 
|---|
| 277 | case Qt::Key_Odiaeresis: keysym = XK_odiaeresis; break; | 
|---|
| 278 | case Qt::Key_multiply: keysym = XK_multiply; break; | 
|---|
| 279 | case Qt::Key_Ooblique: keysym = XK_ooblique; break; | 
|---|
| 280 | case Qt::Key_Ugrave: keysym = XK_ugrave; break; | 
|---|
| 281 | case Qt::Key_Uacute: keysym = XK_uacute; break; | 
|---|
| 282 | case Qt::Key_Ucircumflex: keysym = XK_ucircumflex; break; | 
|---|
| 283 | case Qt::Key_Udiaeresis: keysym = XK_udiaeresis; break; | 
|---|
| 284 | case Qt::Key_Yacute: keysym = XK_yacute; break; | 
|---|
| 285 | case Qt::Key_THORN: keysym = XK_thorn; break; | 
|---|
| 286 | case Qt::Key_ssharp: keysym = XK_ssharp; break; | 
|---|
| 287 | case Qt::Key_division: keysym = XK_division; break; | 
|---|
| 288 | case Qt::Key_ydiaeresis: keysym = XK_ydiaeresis; break; | 
|---|
| 289 |  | 
|---|
| 290 | case Qt::Key_AltGr: keysym = XK_ISO_Level3_Shift; break; | 
|---|
| 291 | case Qt::Key_Multi_key: keysym = XK_Multi_key; break; | 
|---|
| 292 | case Qt::Key_Codeinput: keysym = XK_Codeinput; break; | 
|---|
| 293 | case Qt::Key_SingleCandidate: keysym = XK_SingleCandidate; break; | 
|---|
| 294 | case Qt::Key_MultipleCandidate: keysym = XK_MultipleCandidate; break; | 
|---|
| 295 | case Qt::Key_PreviousCandidate: keysym = XK_PreviousCandidate; break; | 
|---|
| 296 |  | 
|---|
| 297 | case Qt::Key_Mode_switch: keysym = XK_Mode_switch; break; | 
|---|
| 298 |  | 
|---|
| 299 | case Qt::Key_Kanji: keysym = XK_Kanji; break; | 
|---|
| 300 | case Qt::Key_Muhenkan: keysym = XK_Muhenkan; break; | 
|---|
| 301 | case Qt::Key_Henkan: keysym = XK_Henkan; break; | 
|---|
| 302 | case Qt::Key_Romaji: keysym = XK_Romaji; break; | 
|---|
| 303 | case Qt::Key_Hiragana: keysym = XK_Hiragana; break; | 
|---|
| 304 | case Qt::Key_Katakana: keysym = XK_Katakana; break; | 
|---|
| 305 | case Qt::Key_Hiragana_Katakana: keysym = XK_Hiragana_Katakana; break; | 
|---|
| 306 | case Qt::Key_Zenkaku: keysym = XK_Zenkaku; break; | 
|---|
| 307 | case Qt::Key_Hankaku: keysym = XK_Hankaku; break; | 
|---|
| 308 | case Qt::Key_Zenkaku_Hankaku: keysym = XK_Zenkaku_Hankaku; break; | 
|---|
| 309 | case Qt::Key_Touroku: keysym = XK_Touroku; break; | 
|---|
| 310 | case Qt::Key_Massyo: keysym = XK_Massyo; break; | 
|---|
| 311 | case Qt::Key_Kana_Lock: keysym = XK_Kana_Lock; break; | 
|---|
| 312 | case Qt::Key_Kana_Shift: keysym = XK_Kana_Shift; break; | 
|---|
| 313 | case Qt::Key_Eisu_Shift: keysym = XK_Eisu_Shift; break; | 
|---|
| 314 | case Qt::Key_Eisu_toggle: keysym = XK_Eisu_toggle; break; | 
|---|
| 315 |  | 
|---|
| 316 | case Qt::Key_Hangul: keysym = XK_Hangul; break; | 
|---|
| 317 | case Qt::Key_Hangul_Start: keysym = XK_Hangul_Start; break; | 
|---|
| 318 | case Qt::Key_Hangul_End: keysym = XK_Hangul_End; break; | 
|---|
| 319 | case Qt::Key_Hangul_Hanja: keysym = XK_Hangul_Hanja; break; | 
|---|
| 320 | case Qt::Key_Hangul_Jamo: keysym = XK_Hangul_Jamo; break; | 
|---|
| 321 | case Qt::Key_Hangul_Romaja: keysym = XK_Hangul_Romaja; break; | 
|---|
| 322 | case Qt::Key_Hangul_Jeonja: keysym = XK_Hangul_Jeonja; break; | 
|---|
| 323 | case Qt::Key_Hangul_Banja: keysym = XK_Hangul_Banja; break; | 
|---|
| 324 | case Qt::Key_Hangul_PreHanja: keysym = XK_Hangul_PreHanja; break; | 
|---|
| 325 | case Qt::Key_Hangul_PostHanja: keysym = XK_Hangul_PostHanja; break; | 
|---|
| 326 | case Qt::Key_Hangul_Special: keysym = XK_Hangul_Special; break; | 
|---|
| 327 |  | 
|---|
| 328 | case Qt::Key_Dead_Grave: keysym = XK_dead_grave; break; | 
|---|
| 329 | case Qt::Key_Dead_Acute: keysym = XK_dead_acute; break; | 
|---|
| 330 | case Qt::Key_Dead_Circumflex: keysym = XK_dead_circumflex; break; | 
|---|
| 331 | case Qt::Key_Dead_Tilde: keysym = XK_dead_tilde; break; | 
|---|
| 332 | case Qt::Key_Dead_Macron: keysym = XK_dead_macron; break; | 
|---|
| 333 | case Qt::Key_Dead_Breve: keysym = XK_dead_breve; break; | 
|---|
| 334 | case Qt::Key_Dead_Abovedot: keysym = XK_dead_abovedot; break; | 
|---|
| 335 | case Qt::Key_Dead_Diaeresis: keysym = XK_dead_diaeresis; break; | 
|---|
| 336 | case Qt::Key_Dead_Abovering: keysym = XK_dead_abovering; break; | 
|---|
| 337 | case Qt::Key_Dead_Doubleacute: keysym = XK_dead_doubleacute; break; | 
|---|
| 338 | case Qt::Key_Dead_Caron: keysym = XK_dead_caron; break; | 
|---|
| 339 | case Qt::Key_Dead_Cedilla: keysym = XK_dead_cedilla; break; | 
|---|
| 340 | case Qt::Key_Dead_Ogonek: keysym = XK_dead_ogonek; break; | 
|---|
| 341 | case Qt::Key_Dead_Iota: keysym = XK_dead_iota; break; | 
|---|
| 342 | case Qt::Key_Dead_Voiced_Sound: keysym = XK_dead_voiced_sound; break; | 
|---|
| 343 | case Qt::Key_Dead_Semivoiced_Sound: keysym = XK_dead_semivoiced_sound; break; | 
|---|
| 344 | case Qt::Key_Dead_Belowdot: keysym = XK_dead_belowdot; break; | 
|---|
| 345 | case Qt::Key_Dead_Hook: keysym = XK_dead_hook; break; | 
|---|
| 346 | case Qt::Key_Dead_Horn: keysym = XK_dead_horn; break; | 
|---|
| 347 |  | 
|---|
| 348 | case Qt::Key_Back: keysym = XF86XK_Back; break; | 
|---|
| 349 | case Qt::Key_Forward: keysym = XF86XK_Forward; break; | 
|---|
| 350 | case Qt::Key_Stop: keysym = XF86XK_Stop; break; | 
|---|
| 351 | case Qt::Key_Refresh: keysym = XF86XK_Refresh; break; | 
|---|
| 352 |  | 
|---|
| 353 | case Qt::Key_VolumeDown: keysym = XF86XK_AudioLowerVolume; break; | 
|---|
| 354 | case Qt::Key_VolumeMute: keysym = XF86XK_AudioMute; break; | 
|---|
| 355 | case Qt::Key_VolumeUp: keysym = XF86XK_AudioRaiseVolume; break; | 
|---|
| 356 | case Qt::Key_BassBoost: keysym = NoSymbol; break;       // ??? | 
|---|
| 357 | case Qt::Key_BassUp: keysym = NoSymbol; break;          // ??? | 
|---|
| 358 | case Qt::Key_BassDown: keysym = NoSymbol; break;        // ??? | 
|---|
| 359 | case Qt::Key_TrebleUp: keysym = NoSymbol; break;        // ??? | 
|---|
| 360 | case Qt::Key_TrebleDown: keysym = NoSymbol; break;      // ??? | 
|---|
| 361 |  | 
|---|
| 362 | case Qt::Key_MediaPlay: keysym = XF86XK_AudioPlay; break; | 
|---|
| 363 | case Qt::Key_MediaStop: keysym = XF86XK_AudioStop; break; | 
|---|
| 364 | case Qt::Key_MediaPrevious: keysym = XF86XK_AudioPrev; break; | 
|---|
| 365 | case Qt::Key_MediaNext: keysym = XF86XK_AudioNext; break; | 
|---|
| 366 | case Qt::Key_MediaRecord: keysym = XF86XK_AudioRecord; break; | 
|---|
| 367 |  | 
|---|
| 368 | case Qt::Key_HomePage: keysym = XF86XK_HomePage; break; | 
|---|
| 369 | case Qt::Key_Favorites: keysym = XF86XK_Favorites; break; | 
|---|
| 370 | case Qt::Key_Search: keysym = XF86XK_Search; break; | 
|---|
| 371 | case Qt::Key_Standby: keysym = XF86XK_Standby; break; | 
|---|
| 372 | case Qt::Key_OpenUrl: keysym = XF86XK_OpenURL; break; | 
|---|
| 373 |  | 
|---|
| 374 | case Qt::Key_LaunchMail: keysym = XF86XK_Mail; break; | 
|---|
| 375 | case Qt::Key_LaunchMedia: keysym = XF86XK_AudioMedia; break; | 
|---|
| 376 | case Qt::Key_Launch0: keysym = XF86XK_Launch0; break; | 
|---|
| 377 | case Qt::Key_Launch1: keysym = XF86XK_Launch1; break; | 
|---|
| 378 | case Qt::Key_Launch2: keysym = XF86XK_Launch2; break; | 
|---|
| 379 | case Qt::Key_Launch3: keysym = XF86XK_Launch3; break; | 
|---|
| 380 | case Qt::Key_Launch4: keysym = XF86XK_Launch4; break; | 
|---|
| 381 | case Qt::Key_Launch5: keysym = XF86XK_Launch5; break; | 
|---|
| 382 | case Qt::Key_Launch6: keysym = XF86XK_Launch6; break; | 
|---|
| 383 | case Qt::Key_Launch7: keysym = XF86XK_Launch7; break; | 
|---|
| 384 | case Qt::Key_Launch8: keysym = XF86XK_Launch8; break; | 
|---|
| 385 | case Qt::Key_Launch9: keysym = XF86XK_Launch9; break; | 
|---|
| 386 | case Qt::Key_LaunchA: keysym = XF86XK_LaunchA; break; | 
|---|
| 387 | case Qt::Key_LaunchB: keysym = XF86XK_LaunchB; break; | 
|---|
| 388 | case Qt::Key_LaunchC: keysym = XF86XK_LaunchC; break; | 
|---|
| 389 | case Qt::Key_LaunchD: keysym = XF86XK_LaunchD; break; | 
|---|
| 390 | case Qt::Key_LaunchE: keysym = XF86XK_LaunchE; break; | 
|---|
| 391 | case Qt::Key_LaunchF: keysym = XF86XK_LaunchF; break; | 
|---|
| 392 |  | 
|---|
| 393 | case Qt::Key_MediaLast: keysym = NoSymbol; break;   // ??? | 
|---|
| 394 |  | 
|---|
| 395 | case Qt::Key_Select: keysym = QTOPIAXK_Select; break; | 
|---|
| 396 | case Qt::Key_Yes: keysym = QTOPIAXK_Yes; break; | 
|---|
| 397 | case Qt::Key_No: keysym = QTOPIAXK_No; break; | 
|---|
| 398 |  | 
|---|
| 399 | case Qt::Key_Cancel: keysym = QTOPIAXK_Cancel; break; | 
|---|
| 400 | case Qt::Key_Printer: keysym = QTOPIAXK_Printer; break; | 
|---|
| 401 | case Qt::Key_Execute: keysym = QTOPIAXK_Execute; break; | 
|---|
| 402 | case Qt::Key_Sleep: keysym = QTOPIAXK_Sleep; break; | 
|---|
| 403 | case Qt::Key_Play: keysym = QTOPIAXK_Play; break; | 
|---|
| 404 | case Qt::Key_Zoom: keysym = QTOPIAXK_Zoom; break; | 
|---|
| 405 |  | 
|---|
| 406 | case Qt::Key_Context1: keysym = QTOPIAXK_Context1; break; | 
|---|
| 407 | case Qt::Key_Context2: keysym = QTOPIAXK_Context2; break; | 
|---|
| 408 | case Qt::Key_Context3: keysym = QTOPIAXK_Context3; break; | 
|---|
| 409 | case Qt::Key_Context4: keysym = QTOPIAXK_Context4; break; | 
|---|
| 410 | case Qt::Key_Call: keysym = QTOPIAXK_Call; break; | 
|---|
| 411 | case Qt::Key_Hangup: keysym = QTOPIAXK_Hangup; break; | 
|---|
| 412 | case Qt::Key_Flip: keysym = QTOPIAXK_Flip; break; | 
|---|
| 413 |  | 
|---|
| 414 | case Qt::Key_unknown: keysym = NoSymbol; break; | 
|---|
| 415 | } | 
|---|
| 416 | if (keysym == NoSymbol) | 
|---|
| 417 | return; | 
|---|
| 418 |  | 
|---|
| 419 | // Convert the X keysym into an X keycode. | 
|---|
| 420 | KeyCode keycode = XKeysymToKeycode(dpy, keysym); | 
|---|
| 421 | if (keycode == NoSymbol) | 
|---|
| 422 | return; | 
|---|
| 423 |  | 
|---|
| 424 | // Determine if we need to fake shift keys as well. | 
|---|
| 425 | int index = 0; | 
|---|
| 426 | while (index < 4 && XKeycodeToKeysym(dpy, keycode, index) != keysym) | 
|---|
| 427 | ++index; | 
|---|
| 428 | int extraModifiers = 0; | 
|---|
| 429 | if ((index & 1) != 0) | 
|---|
| 430 | extraModifiers |= ShiftMask; | 
|---|
| 431 | if ((index & 2) != 0) | 
|---|
| 432 | extraModifiers |= Mod2Mask; | 
|---|
| 433 | if ((modifiers & LockMask) != 0) { | 
|---|
| 434 | // If Caps Lock is set, then flip the shift state for alphabetic keys. | 
|---|
| 435 | if (qtCode >= Qt::Key_A && qtCode <= Qt::Key_Z) | 
|---|
| 436 | extraModifiers ^= ShiftMask; | 
|---|
| 437 | if (qtCode >= Qt::Key_Agrave && qtCode <= Qt::Key_THORN && | 
|---|
| 438 | qtCode != Qt::Key_multiply) | 
|---|
| 439 | extraModifiers ^= ShiftMask; | 
|---|
| 440 | } | 
|---|
| 441 |  | 
|---|
| 442 | // Adjust modifier keys for the shift states.  This is needed for | 
|---|
| 443 | // things like the * and # phone keys, which need Shift to be pressed | 
|---|
| 444 | // when entering from a keyboard, but don't need Shift from a skin. | 
|---|
| 445 | unsigned long delay = 0; | 
|---|
| 446 | if (extraModifiers != 0) { | 
|---|
| 447 | if ((extraModifiers & ShiftMask) != 0) { | 
|---|
| 448 | if ((modifiers & ShiftMask) == 0) | 
|---|
| 449 | XTestFakeKeyEvent(dpy, shiftKeycode, true, delay++); | 
|---|
| 450 | } else { | 
|---|
| 451 | if ((modifiers & ShiftMask) != 0) | 
|---|
| 452 | XTestFakeKeyEvent(dpy, shiftKeycode, false, delay++); | 
|---|
| 453 | } | 
|---|
| 454 | if ((extraModifiers & Mod2Mask) != 0) { | 
|---|
| 455 | if ((modifiers & Mod2Mask) == 0) | 
|---|
| 456 | XTestFakeKeyEvent(dpy, modeSwitchKeycode, true, delay++); | 
|---|
| 457 | } else { | 
|---|
| 458 | if ((modifiers & Mod2Mask) != 0) | 
|---|
| 459 | XTestFakeKeyEvent(dpy, modeSwitchKeycode, false, delay++); | 
|---|
| 460 | } | 
|---|
| 461 | } | 
|---|
| 462 |  | 
|---|
| 463 | // Fake the actual key. | 
|---|
| 464 | XTestFakeKeyEvent(dpy, keycode, (Bool)isPress, delay++); | 
|---|
| 465 |  | 
|---|
| 466 | // Adjust the modifiers back. | 
|---|
| 467 | if (extraModifiers != 0) { | 
|---|
| 468 | if ((extraModifiers & ShiftMask) != 0) { | 
|---|
| 469 | if ((modifiers & ShiftMask) == 0) | 
|---|
| 470 | XTestFakeKeyEvent(dpy, shiftKeycode, false, delay++); | 
|---|
| 471 | } else { | 
|---|
| 472 | if ((modifiers & ShiftMask) != 0) | 
|---|
| 473 | XTestFakeKeyEvent(dpy, shiftKeycode, true, delay++); | 
|---|
| 474 | } | 
|---|
| 475 | if ((extraModifiers & Mod2Mask) != 0) { | 
|---|
| 476 | if ((modifiers & Mod2Mask) == 0) | 
|---|
| 477 | XTestFakeKeyEvent(dpy, modeSwitchKeycode, false, delay++); | 
|---|
| 478 | } else { | 
|---|
| 479 | if ((modifiers & Mod2Mask) != 0) | 
|---|
| 480 | XTestFakeKeyEvent(dpy, modeSwitchKeycode, true, delay++); | 
|---|
| 481 | } | 
|---|
| 482 | } | 
|---|
| 483 |  | 
|---|
| 484 | // Flush the key events. | 
|---|
| 485 | XFlush(dpy); | 
|---|
| 486 |  | 
|---|
| 487 | // Update the modifiers if this was a shift key. | 
|---|
| 488 | if (isPress) { | 
|---|
| 489 | if (qtCode == Qt::Key_Shift) | 
|---|
| 490 | modifiers |= ShiftMask; | 
|---|
| 491 | if (qtCode == Qt::Key_CapsLock) | 
|---|
| 492 | modifiers |= LockMask; | 
|---|
| 493 | if (qtCode == Qt::Key_Mode_switch) | 
|---|
| 494 | modifiers |= Mod2Mask; | 
|---|
| 495 | } else { | 
|---|
| 496 | if (qtCode == Qt::Key_Shift) | 
|---|
| 497 | modifiers &= ~ShiftMask; | 
|---|
| 498 | if (qtCode == Qt::Key_CapsLock) | 
|---|
| 499 | modifiers &= ~LockMask; | 
|---|
| 500 | if (qtCode == Qt::Key_Mode_switch) | 
|---|
| 501 | modifiers &= ~Mod2Mask; | 
|---|
| 502 | } | 
|---|
| 503 | } | 
|---|
| 504 |  | 
|---|
| 505 | // Determine if an X11 keycode is currently mapped to one or more keysyms. | 
|---|
| 506 | static bool keycodeInUse(Display *dpy, int keycode) | 
|---|
| 507 | { | 
|---|
| 508 | for (int index = 0; index < 8; ++index) { | 
|---|
| 509 | if (XKeycodeToKeysym(dpy, keycode, index) != NoSymbol) | 
|---|
| 510 | return true; | 
|---|
| 511 | } | 
|---|
| 512 | return false; | 
|---|
| 513 | } | 
|---|
| 514 |  | 
|---|
| 515 | // Allocate a keycode for a special keysym. | 
|---|
| 516 | static bool allocateSpecialKeysym | 
|---|
| 517 | (Display *dpy, int& min_keycode, int& max_keycode, KeySym key) | 
|---|
| 518 | { | 
|---|
| 519 | if (XKeysymToKeycode(dpy, key) != NoSymbol) | 
|---|
| 520 | return true; // There is already a mapping for this key.  Good! | 
|---|
| 521 | while (max_keycode >= min_keycode) { | 
|---|
| 522 | if (!keycodeInUse(dpy, max_keycode)) | 
|---|
| 523 | break; | 
|---|
| 524 | --max_keycode; | 
|---|
| 525 | } | 
|---|
| 526 | if (max_keycode < min_keycode) | 
|---|
| 527 | return false; | 
|---|
| 528 | XChangeKeyboardMapping(dpy, max_keycode, 1, &key, 1); | 
|---|
| 529 | --max_keycode; | 
|---|
| 530 | return true; | 
|---|
| 531 | } | 
|---|
| 532 |  | 
|---|
| 533 | void X11KeyFaker::connect() | 
|---|
| 534 | { | 
|---|
| 535 | // Open the display. | 
|---|
| 536 | dpy = XOpenDisplay(displayName.toLatin1().data()); | 
|---|
| 537 | if (!dpy) { | 
|---|
| 538 | // Try again in a few milliseconds.  Xnest may not be alive yet. | 
|---|
| 539 | // Give up after 10 seconds. | 
|---|
| 540 | if (++retryCount < 50) | 
|---|
| 541 | QTimer::singleShot(200, this, SLOT(connect())); | 
|---|
| 542 | else | 
|---|
| 543 | QTimer::singleShot(0, this, SIGNAL(couldNotConnect())); | 
|---|
| 544 | return; | 
|---|
| 545 | } | 
|---|
| 546 |  | 
|---|
| 547 | // Query the XTest extension, which we need to fake the key events. | 
|---|
| 548 | int event_base, error_base, major, minor; | 
|---|
| 549 | if (!XTestQueryExtension | 
|---|
| 550 | (dpy, &event_base, &error_base, &major, &minor)) { | 
|---|
| 551 | XCloseDisplay(dpy); | 
|---|
| 552 | dpy = 0; | 
|---|
| 553 | QTimer::singleShot(0, this, SIGNAL(couldNotConnect())); | 
|---|
| 554 | return; | 
|---|
| 555 | } | 
|---|
| 556 |  | 
|---|
| 557 | // Modify the Xnest's keyboard mappings to add Qtopia's special keysyms. | 
|---|
| 558 | int min_keycode = 1, max_keycode = 255; | 
|---|
| 559 | XDisplayKeycodes(dpy, &min_keycode, &max_keycode); | 
|---|
| 560 | bool ok = true; | 
|---|
| 561 | for (KeySym key = QTOPIAXK_Max; key >= QTOPIAXK_Min; --key) { | 
|---|
| 562 | // This is an extension keysym, not part of the standard X11 set. | 
|---|
| 563 | if (!allocateSpecialKeysym(dpy, min_keycode, max_keycode, key)) { | 
|---|
| 564 | ok = false; | 
|---|
| 565 | break; | 
|---|
| 566 | } | 
|---|
| 567 | } | 
|---|
| 568 | static const KeySym specials[] = { | 
|---|
| 569 | XF86XK_Back,                // Qt::Key_Back | 
|---|
| 570 | XF86XK_AudioLowerVolume,    // Qt::Key_VolumeUp | 
|---|
| 571 | XF86XK_AudioRaiseVolume,    // Qt::Key_VolumeDown | 
|---|
| 572 | XK_F28,                     // Qt::Key_F28 | 
|---|
| 573 | NoSymbol | 
|---|
| 574 | }; | 
|---|
| 575 | int index = 0; | 
|---|
| 576 | while (ok && specials[index] != NoSymbol) { | 
|---|
| 577 | // This is a standard X11/XFree86 keysym that Qtopia uses, | 
|---|
| 578 | // but it may not be on the user's physical keyboard. | 
|---|
| 579 | if (!allocateSpecialKeysym | 
|---|
| 580 | (dpy, min_keycode, max_keycode, specials[index])) | 
|---|
| 581 | ok = false; | 
|---|
| 582 | ++index; | 
|---|
| 583 | } | 
|---|
| 584 | if (!ok) | 
|---|
| 585 | qWarning() << "There are insufficient spare X11 keycodes to allocate the special Qtopia keys"; | 
|---|
| 586 |  | 
|---|
| 587 | // Change the root cursor to something more reasonable than "X". | 
|---|
| 588 | Cursor cursor = XCreateFontCursor(dpy, XC_left_ptr); | 
|---|
| 589 | XDefineCursor(dpy, RootWindow(dpy, DefaultScreen(dpy)), cursor); | 
|---|
| 590 |  | 
|---|
| 591 | // Look up the shift keys. | 
|---|
| 592 | shiftKeycode = XKeysymToKeycode(dpy, XK_Shift_L); | 
|---|
| 593 | if (shiftKeycode == NoSymbol) | 
|---|
| 594 | shiftKeycode = XKeysymToKeycode(dpy, XK_Shift_R); | 
|---|
| 595 | modeSwitchKeycode = XKeysymToKeycode(dpy, XK_Mode_switch); | 
|---|
| 596 |  | 
|---|
| 597 | // Make sure all of the above changes are flushed. | 
|---|
| 598 | XFlush(dpy); | 
|---|
| 599 |  | 
|---|
| 600 | // Set up event handling for the display. | 
|---|
| 601 | QSocketNotifier *notifier = new QSocketNotifier | 
|---|
| 602 | (ConnectionNumber(dpy), QSocketNotifier::Read, this); | 
|---|
| 603 | QObject::connect(notifier, SIGNAL(activated(int)), this, SLOT(readyRead())); | 
|---|
| 604 |  | 
|---|
| 605 | // Make sure the file descriptor is not inherited across exec's. | 
|---|
| 606 | fcntl(ConnectionNumber(dpy), F_SETFD, 1); | 
|---|
| 607 |  | 
|---|
| 608 | // Notify interested parties that we are now connected to the X display. | 
|---|
| 609 | QTimer::singleShot(0, this, SIGNAL(connected())); | 
|---|
| 610 | } | 
|---|
| 611 |  | 
|---|
| 612 | void X11KeyFaker::readyRead() | 
|---|
| 613 | { | 
|---|
| 614 | if (dpy) { | 
|---|
| 615 | // Read incoming events and discard them.  The only event | 
|---|
| 616 | // we care about is keyboard mapping changes.  Since we | 
|---|
| 617 | // don't have any active windows, there's nothing more to do. | 
|---|
| 618 | while (XEventsQueued(dpy, QueuedAfterFlush)) { | 
|---|
| 619 | XEvent event; | 
|---|
| 620 | XNextEvent(dpy, &event); | 
|---|
| 621 | if (event.xany.type == MappingNotify) | 
|---|
| 622 | XRefreshKeyboardMapping(&event.xmapping); | 
|---|
| 623 | } | 
|---|
| 624 | } | 
|---|
| 625 | } | 
|---|
| 626 |  | 
|---|
| 627 | QT_END_NAMESPACE | 
|---|