| 1 | // LAF OS Library |
|---|---|
| 2 | // Copyright (C) 2016-2018 David Capello |
| 3 | // |
| 4 | // This file is released under the terms of the MIT license. |
| 5 | // Read LICENSE.txt for more information. |
| 6 | |
| 7 | #ifdef HAVE_CONFIG_H |
| 8 | #include "config.h" |
| 9 | #endif |
| 10 | |
| 11 | #include "base/ints.h" |
| 12 | #include "os/x11/keys.h" |
| 13 | #include "os/x11/x11.h" |
| 14 | |
| 15 | #include <X11/Xlib.h> |
| 16 | #include <X11/keysym.h> |
| 17 | |
| 18 | namespace os { |
| 19 | |
| 20 | bool g_spaceBarIsPressed = false; |
| 21 | |
| 22 | KeyScancode x11_keysym_to_scancode(const KeySym keysym) |
| 23 | { |
| 24 | switch (keysym) { |
| 25 | case XK_BackSpace: return kKeyBackspace; |
| 26 | case XK_Tab: return kKeyTab; |
| 27 | case XK_Linefeed: return kKeyEnter; |
| 28 | case XK_Clear: return kKeyDel; |
| 29 | case XK_Return: return kKeyEnter; |
| 30 | case XK_Pause: |
| 31 | case XK_Break: return kKeyPause; |
| 32 | case XK_Scroll_Lock: return kKeyScrLock; |
| 33 | case XK_Escape: return kKeyEsc; |
| 34 | case XK_Delete: return kKeyDel; |
| 35 | case XK_Home: return kKeyHome; |
| 36 | case XK_Left: return kKeyLeft; |
| 37 | case XK_Up: return kKeyUp; |
| 38 | case XK_Right: return kKeyRight; |
| 39 | case XK_Down: return kKeyDown; |
| 40 | case XK_Page_Up: return kKeyPageUp; |
| 41 | case XK_Page_Down: return kKeyPageDown; |
| 42 | case XK_End: return kKeyEnd; |
| 43 | case XK_Sys_Req: |
| 44 | case XK_Print: return kKeyPrtscr; |
| 45 | case XK_Insert: return kKeyInsert; |
| 46 | case XK_Menu: return kKeyMenu; |
| 47 | case XK_Num_Lock: return kKeyNumLock; |
| 48 | case XK_KP_Space: return kKeySpace; |
| 49 | case XK_KP_Tab: return kKeyTab; |
| 50 | case XK_KP_Enter: return kKeyEnterPad; |
| 51 | case XK_KP_0: case XK_KP_Insert: return kKey0Pad; |
| 52 | case XK_KP_1: case XK_KP_End: return kKey1Pad; |
| 53 | case XK_KP_2: case XK_KP_Down: return kKey2Pad; |
| 54 | case XK_KP_3: case XK_KP_Page_Down: return kKey3Pad; |
| 55 | case XK_KP_4: case XK_KP_Left: return kKey4Pad; |
| 56 | case XK_KP_5: case XK_KP_Begin: return kKey5Pad; |
| 57 | case XK_KP_6: case XK_KP_Right: return kKey6Pad; |
| 58 | case XK_KP_7: case XK_KP_Home: return kKey7Pad; |
| 59 | case XK_KP_8: case XK_KP_Up: return kKey8Pad; |
| 60 | case XK_KP_9: case XK_KP_Page_Up: return kKey9Pad; |
| 61 | case XK_KP_Decimal: |
| 62 | case XK_KP_Delete: return kKeyDelPad; |
| 63 | case XK_KP_Equal: return kKeyEqualsPad; |
| 64 | case XK_KP_Multiply: return kKeyAsterisk; |
| 65 | case XK_KP_Add: return kKeyPlusPad; |
| 66 | case XK_KP_Subtract: return kKeyMinusPad; |
| 67 | case XK_KP_Divide: return kKeySlashPad; |
| 68 | case XK_F1: return kKeyF1; |
| 69 | case XK_F2: return kKeyF2; |
| 70 | case XK_F3: return kKeyF3; |
| 71 | case XK_F4: return kKeyF4; |
| 72 | case XK_F5: return kKeyF5; |
| 73 | case XK_F6: return kKeyF6; |
| 74 | case XK_F7: return kKeyF7; |
| 75 | case XK_F8: return kKeyF8; |
| 76 | case XK_F9: return kKeyF9; |
| 77 | case XK_F10: return kKeyF10; |
| 78 | case XK_F11: return kKeyF11; |
| 79 | case XK_F12: return kKeyF12; |
| 80 | case XK_Shift_L: return kKeyLShift; |
| 81 | case XK_Shift_R: return kKeyRShift; |
| 82 | case XK_Control_L: return kKeyLControl; |
| 83 | case XK_Control_R: return kKeyRControl; |
| 84 | case XK_Caps_Lock: return kKeyCapsLock; |
| 85 | case XK_Alt_L: return kKeyAlt; |
| 86 | case XK_Alt_R: return kKeyAltGr; |
| 87 | case XK_Meta_L: |
| 88 | case XK_Super_L: return kKeyLWin; |
| 89 | case XK_Meta_R: |
| 90 | case XK_Super_R: return kKeyRWin; |
| 91 | case XK_space: return kKeySpace; |
| 92 | case XK_apostrophe: return kKeyQuote; |
| 93 | case XK_comma: return kKeyComma; |
| 94 | case XK_minus: return kKeyMinus; |
| 95 | case XK_period: return kKeyStop; |
| 96 | case XK_slash: return kKeySlash; |
| 97 | case XK_0: return kKey0; |
| 98 | case XK_1: return kKey1; |
| 99 | case XK_2: return kKey2; |
| 100 | case XK_3: return kKey3; |
| 101 | case XK_4: return kKey4; |
| 102 | case XK_5: return kKey5; |
| 103 | case XK_6: return kKey6; |
| 104 | case XK_7: return kKey7; |
| 105 | case XK_8: return kKey8; |
| 106 | case XK_9: return kKey9; |
| 107 | case XK_semicolon: return kKeyColon; |
| 108 | case XK_less: return kKeyBackslash2; |
| 109 | case XK_A: return kKeyA; |
| 110 | case XK_B: return kKeyB; |
| 111 | case XK_C: return kKeyC; |
| 112 | case XK_D: return kKeyD; |
| 113 | case XK_E: return kKeyE; |
| 114 | case XK_F: return kKeyF; |
| 115 | case XK_G: return kKeyG; |
| 116 | case XK_H: return kKeyH; |
| 117 | case XK_I: return kKeyI; |
| 118 | case XK_J: return kKeyJ; |
| 119 | case XK_K: return kKeyK; |
| 120 | case XK_L: return kKeyL; |
| 121 | case XK_M: return kKeyM; |
| 122 | case XK_N: return kKeyN; |
| 123 | case XK_O: return kKeyO; |
| 124 | case XK_P: return kKeyP; |
| 125 | case XK_Q: return kKeyQ; |
| 126 | case XK_R: return kKeyR; |
| 127 | case XK_S: return kKeyS; |
| 128 | case XK_T: return kKeyT; |
| 129 | case XK_U: return kKeyU; |
| 130 | case XK_V: return kKeyV; |
| 131 | case XK_W: return kKeyW; |
| 132 | case XK_X: return kKeyX; |
| 133 | case XK_Y: return kKeyY; |
| 134 | case XK_Z: return kKeyZ; |
| 135 | case XK_bracketleft: return kKeyOpenbrace; |
| 136 | case XK_backslash: return kKeyBackslash; |
| 137 | case XK_bracketright: return kKeyClosebrace; |
| 138 | case XK_grave: return kKeyTilde; |
| 139 | case XK_a: return kKeyA; |
| 140 | case XK_b: return kKeyB; |
| 141 | case XK_c: return kKeyC; |
| 142 | case XK_d: return kKeyD; |
| 143 | case XK_e: return kKeyE; |
| 144 | case XK_f: return kKeyF; |
| 145 | case XK_g: return kKeyG; |
| 146 | case XK_h: return kKeyH; |
| 147 | case XK_i: return kKeyI; |
| 148 | case XK_j: return kKeyJ; |
| 149 | case XK_k: return kKeyK; |
| 150 | case XK_l: return kKeyL; |
| 151 | case XK_m: return kKeyM; |
| 152 | case XK_n: return kKeyN; |
| 153 | case XK_o: return kKeyO; |
| 154 | case XK_p: return kKeyP; |
| 155 | case XK_q: return kKeyQ; |
| 156 | case XK_r: return kKeyR; |
| 157 | case XK_s: return kKeyS; |
| 158 | case XK_t: return kKeyT; |
| 159 | case XK_u: return kKeyU; |
| 160 | case XK_v: return kKeyV; |
| 161 | case XK_w: return kKeyW; |
| 162 | case XK_x: return kKeyX; |
| 163 | case XK_y: return kKeyY; |
| 164 | case XK_z: return kKeyZ; |
| 165 | } |
| 166 | return kKeyNil; |
| 167 | } |
| 168 | |
| 169 | KeySym x11_keysym_to_scancode(const KeyScancode scancode) |
| 170 | { |
| 171 | switch (scancode) { |
| 172 | case kKeyBackspace: return XK_BackSpace; |
| 173 | case kKeyTab: return XK_Tab; |
| 174 | case kKeyEnter: return XK_Return; |
| 175 | case kKeyPause: return XK_Pause; |
| 176 | case kKeyScrLock: return XK_Scroll_Lock; |
| 177 | case kKeyEsc: return XK_Escape; |
| 178 | case kKeyDel: return XK_Delete; |
| 179 | case kKeyHome: return XK_Home; |
| 180 | case kKeyLeft: return XK_Left; |
| 181 | case kKeyUp: return XK_Up; |
| 182 | case kKeyRight: return XK_Right; |
| 183 | case kKeyDown: return XK_Down; |
| 184 | case kKeyPageUp: return XK_Page_Up; |
| 185 | case kKeyPageDown: return XK_Page_Down; |
| 186 | case kKeyEnd: return XK_End; |
| 187 | case kKeyPrtscr: return XK_Print; |
| 188 | case kKeyInsert: return XK_Insert; |
| 189 | case kKeyMenu: return XK_Menu; |
| 190 | case kKeyNumLock: return XK_Num_Lock; |
| 191 | case kKeyEnterPad: return XK_KP_Enter; |
| 192 | case kKey0Pad: return XK_KP_0; |
| 193 | case kKey1Pad: return XK_KP_1; |
| 194 | case kKey2Pad: return XK_KP_2; |
| 195 | case kKey3Pad: return XK_KP_3; |
| 196 | case kKey4Pad: return XK_KP_4; |
| 197 | case kKey5Pad: return XK_KP_5; |
| 198 | case kKey6Pad: return XK_KP_6; |
| 199 | case kKey7Pad: return XK_KP_7; |
| 200 | case kKey8Pad: return XK_KP_8; |
| 201 | case kKey9Pad: return XK_KP_9; |
| 202 | case kKeyDelPad: return XK_KP_Delete; |
| 203 | case kKeyEqualsPad: return XK_KP_Equal; |
| 204 | case kKeyAsterisk: return XK_KP_Multiply; |
| 205 | case kKeyPlusPad: return XK_KP_Add; |
| 206 | case kKeyMinusPad: return XK_KP_Subtract; |
| 207 | case kKeySlashPad: return XK_KP_Divide; |
| 208 | case kKeyF1: return XK_F1; |
| 209 | case kKeyF2: return XK_F2; |
| 210 | case kKeyF3: return XK_F3; |
| 211 | case kKeyF4: return XK_F4; |
| 212 | case kKeyF5: return XK_F5; |
| 213 | case kKeyF6: return XK_F6; |
| 214 | case kKeyF7: return XK_F7; |
| 215 | case kKeyF8: return XK_F8; |
| 216 | case kKeyF9: return XK_F9; |
| 217 | case kKeyF10: return XK_F10; |
| 218 | case kKeyF11: return XK_F11; |
| 219 | case kKeyF12: return XK_F12; |
| 220 | case kKeyLShift: return XK_Shift_L; |
| 221 | case kKeyRShift: return XK_Shift_R; |
| 222 | case kKeyLControl: return XK_Control_L; |
| 223 | case kKeyRControl: return XK_Control_R; |
| 224 | case kKeyCapsLock: return XK_Caps_Lock; |
| 225 | case kKeyAlt: return XK_Alt_L; |
| 226 | case kKeyAltGr: return XK_Alt_R; |
| 227 | case kKeyLWin: return XK_Super_L; |
| 228 | case kKeyRWin: return XK_Super_R; |
| 229 | case kKeySpace: return XK_space; |
| 230 | case kKeyQuote: return XK_apostrophe; |
| 231 | case kKeyComma: return XK_comma; |
| 232 | case kKeyMinus: return XK_minus; |
| 233 | case kKeyStop: return XK_period; |
| 234 | case kKeySlash: return XK_slash; |
| 235 | case kKey0: return XK_0; |
| 236 | case kKey1: return XK_1; |
| 237 | case kKey2: return XK_2; |
| 238 | case kKey3: return XK_3; |
| 239 | case kKey4: return XK_4; |
| 240 | case kKey5: return XK_5; |
| 241 | case kKey6: return XK_6; |
| 242 | case kKey7: return XK_7; |
| 243 | case kKey8: return XK_8; |
| 244 | case kKey9: return XK_9; |
| 245 | case kKeyColon: return XK_semicolon; |
| 246 | case kKeyBackslash2: return XK_less; |
| 247 | case kKeyOpenbrace: return XK_bracketleft; |
| 248 | case kKeyBackslash: return XK_backslash; |
| 249 | case kKeyClosebrace: return XK_bracketright; |
| 250 | case kKeyTilde: return XK_grave; |
| 251 | case kKeyA: return XK_a; |
| 252 | case kKeyB: return XK_b; |
| 253 | case kKeyC: return XK_c; |
| 254 | case kKeyD: return XK_d; |
| 255 | case kKeyE: return XK_e; |
| 256 | case kKeyF: return XK_f; |
| 257 | case kKeyG: return XK_g; |
| 258 | case kKeyH: return XK_h; |
| 259 | case kKeyI: return XK_i; |
| 260 | case kKeyJ: return XK_j; |
| 261 | case kKeyK: return XK_k; |
| 262 | case kKeyL: return XK_l; |
| 263 | case kKeyM: return XK_m; |
| 264 | case kKeyN: return XK_n; |
| 265 | case kKeyO: return XK_o; |
| 266 | case kKeyP: return XK_p; |
| 267 | case kKeyQ: return XK_q; |
| 268 | case kKeyR: return XK_r; |
| 269 | case kKeyS: return XK_s; |
| 270 | case kKeyT: return XK_t; |
| 271 | case kKeyU: return XK_u; |
| 272 | case kKeyV: return XK_v; |
| 273 | case kKeyW: return XK_w; |
| 274 | case kKeyX: return XK_x; |
| 275 | case kKeyY: return XK_y; |
| 276 | case kKeyZ: return XK_z; |
| 277 | } |
| 278 | return 0; |
| 279 | } |
| 280 | |
| 281 | bool x11_is_key_pressed(const KeyScancode scancode) |
| 282 | { |
| 283 | ::Display* display = X11::instance()->display(); |
| 284 | const KeySym keysym = x11_keysym_to_scancode(scancode); |
| 285 | const KeyCode keycode = XKeysymToKeycode(display, keysym); |
| 286 | if (!keycode) |
| 287 | return false; |
| 288 | |
| 289 | // TODO several platforms have this kind of API to get the whole |
| 290 | // keyboard state, it would be a lot better if we expose this |
| 291 | // API to the user (so we don't have to call XQueryKeymap for |
| 292 | // each key). |
| 293 | char keys[32]; |
| 294 | XQueryKeymap(display, keys); |
| 295 | |
| 296 | return (keys[keycode/8] & (1 << (keycode%8)) ? true: false); |
| 297 | } |
| 298 | |
| 299 | // TODO I guess that this code should be common to all platforms, but |
| 300 | // osx/win_get_unicode_from_scancode() work in a different way: |
| 301 | // the Unicode is returned only if the scancode key is pressed |
| 302 | // (and that's the case anyway in the only part we are using |
| 303 | // System::getUnicodeFromScancode(), a System::isKeyPressed() is |
| 304 | // tested before). |
| 305 | int x11_get_unicode_from_scancode(const KeyScancode scancode) |
| 306 | { |
| 307 | switch (scancode) { |
| 308 | case kKeyEqualsPad: return '='; |
| 309 | case kKeyAsterisk: return '*'; |
| 310 | case kKeyPlusPad: return '+'; |
| 311 | case kKeyMinusPad: return '-'; |
| 312 | case kKeySlashPad: return '/'; |
| 313 | case kKeySpace: return ' '; |
| 314 | case kKeyQuote: return '\''; |
| 315 | case kKeyComma: return ','; |
| 316 | case kKeyMinus: return '-'; |
| 317 | case kKeyStop: return '.'; |
| 318 | case kKeySlash: return '/'; |
| 319 | case kKey0: case kKey0Pad: return '0'; |
| 320 | case kKey1: case kKey1Pad: return '1'; |
| 321 | case kKey2: case kKey2Pad: return '2'; |
| 322 | case kKey3: case kKey3Pad: return '3'; |
| 323 | case kKey4: case kKey4Pad: return '4'; |
| 324 | case kKey5: case kKey5Pad: return '5'; |
| 325 | case kKey6: case kKey6Pad: return '6'; |
| 326 | case kKey7: case kKey7Pad: return '7'; |
| 327 | case kKey8: case kKey8Pad: return '8'; |
| 328 | case kKey9: case kKey9Pad: return '9'; |
| 329 | case kKeyColon: return ':'; |
| 330 | case kKeyBackslash: case kKeyBackslash2: return '\\'; |
| 331 | case kKeyOpenbrace: return '['; |
| 332 | case kKeyClosebrace: return ']'; |
| 333 | case kKeyTilde: return '~'; |
| 334 | case kKeyA: return 'a'; |
| 335 | case kKeyB: return 'b'; |
| 336 | case kKeyC: return 'c'; |
| 337 | case kKeyD: return 'd'; |
| 338 | case kKeyE: return 'e'; |
| 339 | case kKeyF: return 'f'; |
| 340 | case kKeyG: return 'g'; |
| 341 | case kKeyH: return 'h'; |
| 342 | case kKeyI: return 'i'; |
| 343 | case kKeyJ: return 'j'; |
| 344 | case kKeyK: return 'k'; |
| 345 | case kKeyL: return 'l'; |
| 346 | case kKeyM: return 'm'; |
| 347 | case kKeyN: return 'n'; |
| 348 | case kKeyO: return 'o'; |
| 349 | case kKeyP: return 'p'; |
| 350 | case kKeyQ: return 'q'; |
| 351 | case kKeyR: return 'r'; |
| 352 | case kKeyS: return 's'; |
| 353 | case kKeyT: return 't'; |
| 354 | case kKeyU: return 'u'; |
| 355 | case kKeyV: return 'v'; |
| 356 | case kKeyW: return 'w'; |
| 357 | case kKeyX: return 'x'; |
| 358 | case kKeyY: return 'y'; |
| 359 | case kKeyZ: return 'z'; |
| 360 | } |
| 361 | return 0; |
| 362 | } |
| 363 | |
| 364 | KeyModifiers get_modifiers_from_x(const int state) |
| 365 | { |
| 366 | int modifiers = kKeyNoneModifier; |
| 367 | if (state & ShiftMask) modifiers |= kKeyShiftModifier; |
| 368 | if (state & ControlMask) modifiers |= kKeyCtrlModifier; |
| 369 | // Mod1Mask is Alt, and Mod5Mask is AltGr |
| 370 | if (state & (Mod1Mask | Mod5Mask)) modifiers |= kKeyAltModifier; |
| 371 | // Mod4Mask is Windows key |
| 372 | if (state & Mod4Mask) modifiers |= kKeyWinModifier; |
| 373 | if (g_spaceBarIsPressed) modifiers |= kKeySpaceModifier; |
| 374 | return (KeyModifiers)modifiers; |
| 375 | } |
| 376 | |
| 377 | } // namespace os |
| 378 |