SDL  2.0
SDL_x11keyboard.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_X11
24 
25 #include "SDL_x11video.h"
26 
27 #include "../../events/SDL_keyboard_c.h"
28 #include "../../events/scancodes_darwin.h"
29 #include "../../events/scancodes_xfree86.h"
30 
31 #include <X11/keysym.h>
32 #include <X11/XKBlib.h>
33 
34 #include "imKStoUCS.h"
35 
36 /* *INDENT-OFF* */
37 static const struct {
38  KeySym keysym;
39  SDL_Scancode scancode;
40 } KeySymToSDLScancode[] = {
41  { XK_Return, SDL_SCANCODE_RETURN },
42  { XK_Escape, SDL_SCANCODE_ESCAPE },
43  { XK_BackSpace, SDL_SCANCODE_BACKSPACE },
44  { XK_Tab, SDL_SCANCODE_TAB },
45  { XK_Caps_Lock, SDL_SCANCODE_CAPSLOCK },
46  { XK_F1, SDL_SCANCODE_F1 },
47  { XK_F2, SDL_SCANCODE_F2 },
48  { XK_F3, SDL_SCANCODE_F3 },
49  { XK_F4, SDL_SCANCODE_F4 },
50  { XK_F5, SDL_SCANCODE_F5 },
51  { XK_F6, SDL_SCANCODE_F6 },
52  { XK_F7, SDL_SCANCODE_F7 },
53  { XK_F8, SDL_SCANCODE_F8 },
54  { XK_F9, SDL_SCANCODE_F9 },
55  { XK_F10, SDL_SCANCODE_F10 },
56  { XK_F11, SDL_SCANCODE_F11 },
57  { XK_F12, SDL_SCANCODE_F12 },
58  { XK_Print, SDL_SCANCODE_PRINTSCREEN },
59  { XK_Scroll_Lock, SDL_SCANCODE_SCROLLLOCK },
60  { XK_Pause, SDL_SCANCODE_PAUSE },
61  { XK_Insert, SDL_SCANCODE_INSERT },
62  { XK_Home, SDL_SCANCODE_HOME },
63  { XK_Prior, SDL_SCANCODE_PAGEUP },
64  { XK_Delete, SDL_SCANCODE_DELETE },
65  { XK_End, SDL_SCANCODE_END },
66  { XK_Next, SDL_SCANCODE_PAGEDOWN },
67  { XK_Right, SDL_SCANCODE_RIGHT },
68  { XK_Left, SDL_SCANCODE_LEFT },
69  { XK_Down, SDL_SCANCODE_DOWN },
70  { XK_Up, SDL_SCANCODE_UP },
71  { XK_Num_Lock, SDL_SCANCODE_NUMLOCKCLEAR },
72  { XK_KP_Divide, SDL_SCANCODE_KP_DIVIDE },
73  { XK_KP_Multiply, SDL_SCANCODE_KP_MULTIPLY },
74  { XK_KP_Subtract, SDL_SCANCODE_KP_MINUS },
75  { XK_KP_Add, SDL_SCANCODE_KP_PLUS },
76  { XK_KP_Enter, SDL_SCANCODE_KP_ENTER },
77  { XK_KP_Delete, SDL_SCANCODE_KP_PERIOD },
78  { XK_KP_End, SDL_SCANCODE_KP_1 },
79  { XK_KP_Down, SDL_SCANCODE_KP_2 },
80  { XK_KP_Next, SDL_SCANCODE_KP_3 },
81  { XK_KP_Left, SDL_SCANCODE_KP_4 },
82  { XK_KP_Begin, SDL_SCANCODE_KP_5 },
83  { XK_KP_Right, SDL_SCANCODE_KP_6 },
84  { XK_KP_Home, SDL_SCANCODE_KP_7 },
85  { XK_KP_Up, SDL_SCANCODE_KP_8 },
86  { XK_KP_Prior, SDL_SCANCODE_KP_9 },
87  { XK_KP_Insert, SDL_SCANCODE_KP_0 },
88  { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
89  { XK_KP_1, SDL_SCANCODE_KP_1 },
90  { XK_KP_2, SDL_SCANCODE_KP_2 },
91  { XK_KP_3, SDL_SCANCODE_KP_3 },
92  { XK_KP_4, SDL_SCANCODE_KP_4 },
93  { XK_KP_5, SDL_SCANCODE_KP_5 },
94  { XK_KP_6, SDL_SCANCODE_KP_6 },
95  { XK_KP_7, SDL_SCANCODE_KP_7 },
96  { XK_KP_8, SDL_SCANCODE_KP_8 },
97  { XK_KP_9, SDL_SCANCODE_KP_9 },
98  { XK_KP_0, SDL_SCANCODE_KP_0 },
99  { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
100  { XK_Hyper_R, SDL_SCANCODE_APPLICATION },
101  { XK_KP_Equal, SDL_SCANCODE_KP_EQUALS },
102  { XK_F13, SDL_SCANCODE_F13 },
103  { XK_F14, SDL_SCANCODE_F14 },
104  { XK_F15, SDL_SCANCODE_F15 },
105  { XK_F16, SDL_SCANCODE_F16 },
106  { XK_F17, SDL_SCANCODE_F17 },
107  { XK_F18, SDL_SCANCODE_F18 },
108  { XK_F19, SDL_SCANCODE_F19 },
109  { XK_F20, SDL_SCANCODE_F20 },
110  { XK_F21, SDL_SCANCODE_F21 },
111  { XK_F22, SDL_SCANCODE_F22 },
112  { XK_F23, SDL_SCANCODE_F23 },
113  { XK_F24, SDL_SCANCODE_F24 },
114  { XK_Execute, SDL_SCANCODE_EXECUTE },
115  { XK_Help, SDL_SCANCODE_HELP },
116  { XK_Menu, SDL_SCANCODE_MENU },
117  { XK_Select, SDL_SCANCODE_SELECT },
118  { XK_Cancel, SDL_SCANCODE_STOP },
119  { XK_Redo, SDL_SCANCODE_AGAIN },
120  { XK_Undo, SDL_SCANCODE_UNDO },
121  { XK_Find, SDL_SCANCODE_FIND },
122  { XK_KP_Separator, SDL_SCANCODE_KP_COMMA },
123  { XK_Sys_Req, SDL_SCANCODE_SYSREQ },
124  { XK_Control_L, SDL_SCANCODE_LCTRL },
125  { XK_Shift_L, SDL_SCANCODE_LSHIFT },
126  { XK_Alt_L, SDL_SCANCODE_LALT },
127  { XK_Meta_L, SDL_SCANCODE_LGUI },
128  { XK_Super_L, SDL_SCANCODE_LGUI },
129  { XK_Control_R, SDL_SCANCODE_RCTRL },
130  { XK_Shift_R, SDL_SCANCODE_RSHIFT },
131  { XK_Alt_R, SDL_SCANCODE_RALT },
132  { XK_ISO_Level3_Shift, SDL_SCANCODE_RALT },
133  { XK_Meta_R, SDL_SCANCODE_RGUI },
134  { XK_Super_R, SDL_SCANCODE_RGUI },
135  { XK_Mode_switch, SDL_SCANCODE_MODE },
136  { XK_period, SDL_SCANCODE_PERIOD },
137  { XK_comma, SDL_SCANCODE_COMMA },
138  { XK_slash, SDL_SCANCODE_SLASH },
139  { XK_backslash, SDL_SCANCODE_BACKSLASH },
140  { XK_minus, SDL_SCANCODE_MINUS },
141  { XK_equal, SDL_SCANCODE_EQUALS },
142  { XK_space, SDL_SCANCODE_SPACE },
143  { XK_grave, SDL_SCANCODE_GRAVE },
144  { XK_apostrophe, SDL_SCANCODE_APOSTROPHE },
145  { XK_bracketleft, SDL_SCANCODE_LEFTBRACKET },
146  { XK_bracketright, SDL_SCANCODE_RIGHTBRACKET },
147 };
148 
149 static const struct
150 {
151  SDL_Scancode const *table;
152  int table_size;
153 } scancode_set[] = {
158 };
159 /* *INDENT-OFF* */
160 
161 /* This function only works for keyboards in US QWERTY layout */
162 static SDL_Scancode
163 X11_KeyCodeToSDLScancode(_THIS, KeyCode keycode)
164 {
165  KeySym keysym;
166  int i;
167 
168  keysym = X11_KeyCodeToSym(_this, keycode, 0);
169  if (keysym == NoSymbol) {
170  return SDL_SCANCODE_UNKNOWN;
171  }
172 
173  if (keysym >= XK_a && keysym <= XK_z) {
174  return SDL_SCANCODE_A + (keysym - XK_a);
175  }
176  if (keysym >= XK_A && keysym <= XK_Z) {
177  return SDL_SCANCODE_A + (keysym - XK_A);
178  }
179 
180  if (keysym == XK_0) {
181  return SDL_SCANCODE_0;
182  }
183  if (keysym >= XK_1 && keysym <= XK_9) {
184  return SDL_SCANCODE_1 + (keysym - XK_1);
185  }
186 
187  for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) {
188  if (keysym == KeySymToSDLScancode[i].keysym) {
189  return KeySymToSDLScancode[i].scancode;
190  }
191  }
192  return SDL_SCANCODE_UNKNOWN;
193 }
194 
195 static Uint32
196 X11_KeyCodeToUcs4(_THIS, KeyCode keycode, unsigned char group)
197 {
198  KeySym keysym = X11_KeyCodeToSym(_this, keycode, group);
199 
200  if (keysym == NoSymbol) {
201  return 0;
202  }
203 
204  return X11_KeySymToUcs4(keysym);
205 }
206 
207 KeySym
208 X11_KeyCodeToSym(_THIS, KeyCode keycode, unsigned char group)
209 {
211  KeySym keysym;
212 
214  if (data->xkb) {
215  int num_groups = XkbKeyNumGroups(data->xkb, keycode);
216  unsigned char info = XkbKeyGroupInfo(data->xkb, keycode);
217 
218  if (num_groups && group >= num_groups) {
219 
220  int action = XkbOutOfRangeGroupAction(info);
221 
222  if (action == XkbRedirectIntoRange) {
223  if ((group = XkbOutOfRangeGroupNumber(info)) >= num_groups) {
224  group = 0;
225  }
226  } else if (action == XkbClampIntoRange) {
227  group = num_groups - 1;
228  } else {
229  group %= num_groups;
230  }
231  }
232  keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0);
233  } else {
234  keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
235  }
236 #else
237  keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
238 #endif
239 
240  return keysym;
241 }
242 
243 int
245 {
247  int i = 0;
248  int j = 0;
249  int min_keycode, max_keycode;
250  struct {
251  SDL_Scancode scancode;
252  KeySym keysym;
253  int value;
254  } fingerprint[] = {
255  { SDL_SCANCODE_HOME, XK_Home, 0 },
256  { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
257  { SDL_SCANCODE_UP, XK_Up, 0 },
258  { SDL_SCANCODE_LEFT, XK_Left, 0 },
259  { SDL_SCANCODE_DELETE, XK_Delete, 0 },
260  { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
261  };
262  int best_distance;
263  int best_index;
264  int distance;
265 
266  X11_XAutoRepeatOn(data->display);
267 
268 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
269  {
270  int xkb_major = XkbMajorVersion;
271  int xkb_minor = XkbMinorVersion;
272  if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
273  data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
274  }
275  }
276 #endif
277 
278  /* Try to determine which scancodes are being used based on fingerprint */
279  best_distance = SDL_arraysize(fingerprint) + 1;
280  best_index = -1;
281  X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
282  for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
283  fingerprint[i].value =
284  X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) -
285  min_keycode;
286  }
287  for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
288  /* Make sure the scancode set isn't too big */
289  if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
290  continue;
291  }
292  distance = 0;
293  for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
294  if (fingerprint[j].value < 0
295  || fingerprint[j].value >= scancode_set[i].table_size) {
296  distance += 1;
297  } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) {
298  distance += 1;
299  }
300  }
301  if (distance < best_distance) {
302  best_distance = distance;
303  best_index = i;
304  }
305  }
306  if (best_index >= 0 && best_distance <= 2) {
307 #ifdef DEBUG_KEYBOARD
308  printf("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", best_index, min_keycode, max_keycode, scancode_set[best_index].table_size);
309 #endif
310  SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table,
311  sizeof(SDL_Scancode) * scancode_set[best_index].table_size);
312  } else {
314 
315  printf
316  ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
317 
318  /* Determine key_layout - only works on US QWERTY layout */
319  SDL_GetDefaultKeymap(keymap);
320  for (i = min_keycode; i <= max_keycode; ++i) {
321  KeySym sym;
322  sym = X11_KeyCodeToSym(_this, (KeyCode) i, 0);
323  if (sym != NoSymbol) {
324  SDL_Scancode scancode;
325  printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
326  (unsigned int) sym, X11_XKeysymToString(sym));
327  scancode = X11_KeyCodeToSDLScancode(_this, i);
328  data->key_layout[i] = scancode;
329  if (scancode == SDL_SCANCODE_UNKNOWN) {
330  printf("scancode not found\n");
331  } else {
332  printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
333  }
334  }
335  }
336  }
337 
339 
341 
342 #ifdef SDL_USE_IME
343  SDL_IME_Init();
344 #endif
345 
346  return 0;
347 }
348 
349 void
351 {
353  int i;
354  SDL_Scancode scancode;
356  unsigned char group = 0;
357 
358  SDL_GetDefaultKeymap(keymap);
359 
360 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
361  if (data->xkb) {
362  XkbStateRec state;
363  X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb);
364 
365  if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) {
366  group = state.group;
367  }
368  }
369 #endif
370 
371 
372  for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
373  Uint32 key;
374 
375  /* Make sure this is a valid scancode */
376  scancode = data->key_layout[i];
377  if (scancode == SDL_SCANCODE_UNKNOWN) {
378  continue;
379  }
380 
381  /* See if there is a UCS keycode for this scancode */
382  key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group);
383  if (key) {
384  keymap[scancode] = key;
385  } else {
386  SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i);
387 
388  switch (keyScancode) {
389  case SDL_SCANCODE_RETURN:
390  keymap[scancode] = SDLK_RETURN;
391  break;
392  case SDL_SCANCODE_ESCAPE:
393  keymap[scancode] = SDLK_ESCAPE;
394  break;
396  keymap[scancode] = SDLK_BACKSPACE;
397  break;
398  case SDL_SCANCODE_TAB:
399  keymap[scancode] = SDLK_TAB;
400  break;
401  case SDL_SCANCODE_DELETE:
402  keymap[scancode] = SDLK_DELETE;
403  break;
404  default:
405  keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode);
406  break;
407  }
408  }
409  }
410  SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
411 }
412 
413 void
415 {
417 
419  if (data->xkb) {
420  X11_XkbFreeClientMap(data->xkb, 0, True);
421  data->xkb = NULL;
422  }
423 #endif
424 
425 #ifdef SDL_USE_IME
426  SDL_IME_Quit();
427 #endif
428 }
429 
430 static void
431 X11_ResetXIM(_THIS)
432 {
433 #ifdef X_HAVE_UTF8_STRING
434  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
435  int i;
436 
437  if (videodata && videodata->windowlist) {
438  for (i = 0; i < videodata->numwindows; ++i) {
439  SDL_WindowData *data = videodata->windowlist[i];
440  if (data && data->ic) {
441  /* Clear any partially entered dead keys */
442  char *contents = X11_Xutf8ResetIC(data->ic);
443  if (contents) {
444  X11_XFree(contents);
445  }
446  }
447  }
448  }
449 #endif
450 }
451 
452 void
454 {
455  X11_ResetXIM(_this);
456 }
457 
458 void
460 {
461  X11_ResetXIM(_this);
462 #ifdef SDL_USE_IME
463  SDL_IME_Reset();
464 #endif
465 }
466 
467 void
469 {
470  if (!rect) {
471  SDL_InvalidParamError("rect");
472  return;
473  }
474 
475 #ifdef SDL_USE_IME
477 #endif
478 }
479 
480 #endif /* SDL_VIDEO_DRIVER_X11 */
481 
482 /* vi: set ts=4 sw=4 expandtab: */
void SDL_GetDefaultKeymap(SDL_Keycode *keymap)
Definition: SDL_keyboard.c:580
GLboolean GLuint group
GLenum GLsizei GLenum GLenum const void * table
void X11_QuitKeyboard(_THIS)
void X11_SetTextInputRect(_THIS, SDL_Rect *rect)
static const SDL_Scancode xfree86_scancode_table[]
void SDL_IME_Quit(void)
Definition: SDL_ime.c:97
SDL_Rect rect
Definition: testrelative.c:27
struct wl_display * display
struct xkb_state * state
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
void SDL_IME_UpdateTextRect(SDL_Rect *rect)
Definition: SDL_ime.c:127
SDL_WindowData ** windowlist
Definition: SDL_x11video.h:82
void X11_StartTextInput(_THIS)
static const SDL_Scancode xfree86_scancode_table2[]
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:159
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
Sint32 SDL_Keycode
The SDL virtual key representation.
Definition: SDL_keycode.h:42
GLsizei GLsizei GLfloat distance
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
void SDL_SetKeymap(int start, SDL_Keycode *keys, int length)
Definition: SDL_keyboard.c:586
static const SDL_Scancode darwin_scancode_table[]
#define SDL_memcpy
KeySym X11_KeyCodeToSym(_THIS, KeyCode, unsigned char group)
GLsizei const GLfloat * value
#define _THIS
unsigned int X11_KeySymToUcs4(KeySym keysym)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
#define SDL_SCANCODE_TO_KEYCODE(X)
Definition: SDL_keycode.h:45
void X11_UpdateKeymap(_THIS)
void SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
Definition: SDL_keyboard.c:598
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:143
void X11_StopTextInput(_THIS)
#define SDL_GetScancodeName
int X11_InitKeyboard(_THIS)
void SDL_IME_Reset(void)
Definition: SDL_ime.c:111
SDL_bool SDL_IME_Init(void)
Definition: SDL_ime.c:86
#define SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
Definition: SDL_config.h:314
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:90
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
static const SDL_Scancode xvnc_scancode_table[]