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
18namespace os {
19
20bool g_spaceBarIsPressed = false;
21
22KeyScancode 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
169KeySym 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
281bool 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).
305int 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
364KeyModifiers 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