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_Meta_R, SDL_SCANCODE_RGUI },
133  { XK_Super_R, SDL_SCANCODE_RGUI },
134  { XK_Mode_switch, SDL_SCANCODE_MODE },
135 };
136 
137 static const struct
138 {
139  SDL_Scancode const *table;
140  int table_size;
141 } scancode_set[] = {
145 };
146 /* *INDENT-OFF* */
147 
148 /* This function only works for keyboards in US QWERTY layout */
149 static SDL_Scancode
150 X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode)
151 {
152  KeySym keysym;
153  int i;
154 
155 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
156  keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0);
157 #else
158  keysym = X11_XKeycodeToKeysym(display, keycode, 0);
159 #endif
160  if (keysym == NoSymbol) {
161  return SDL_SCANCODE_UNKNOWN;
162  }
163 
164  if (keysym >= XK_A && keysym <= XK_Z) {
165  return SDL_SCANCODE_A + (keysym - XK_A);
166  }
167 
168  if (keysym >= XK_0 && keysym <= XK_9) {
169  return SDL_SCANCODE_0 + (keysym - XK_0);
170  }
171 
172  for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) {
173  if (keysym == KeySymToSDLScancode[i].keysym) {
174  return KeySymToSDLScancode[i].scancode;
175  }
176  }
177  return SDL_SCANCODE_UNKNOWN;
178 }
179 
180 static Uint32
181 X11_KeyCodeToUcs4(Display *display, KeyCode keycode, unsigned char group)
182 {
183  KeySym keysym;
184 
185 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
186  keysym = X11_XkbKeycodeToKeysym(display, keycode, group, 0);
187 #else
188  keysym = X11_XKeycodeToKeysym(display, keycode, 0);
189 #endif
190  if (keysym == NoSymbol) {
191  return 0;
192  }
193 
194  return X11_KeySymToUcs4(keysym);
195 }
196 
197 int
199 {
201  int i = 0;
202  int j = 0;
203  int min_keycode, max_keycode;
204  struct {
205  SDL_Scancode scancode;
206  KeySym keysym;
207  int value;
208  } fingerprint[] = {
209  { SDL_SCANCODE_HOME, XK_Home, 0 },
210  { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
211  { SDL_SCANCODE_UP, XK_Up, 0 },
212  { SDL_SCANCODE_LEFT, XK_Left, 0 },
213  { SDL_SCANCODE_DELETE, XK_Delete, 0 },
214  { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
215  };
216  int best_distance;
217  int best_index;
218  int distance;
219 
220  X11_XAutoRepeatOn(data->display);
221 
222  /* Try to determine which scancodes are being used based on fingerprint */
223  best_distance = SDL_arraysize(fingerprint) + 1;
224  best_index = -1;
225  X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
226  for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
227  fingerprint[i].value =
228  X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) -
229  min_keycode;
230  }
231  for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
232  /* Make sure the scancode set isn't too big */
233  if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
234  continue;
235  }
236  distance = 0;
237  for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
238  if (fingerprint[j].value < 0
239  || fingerprint[j].value >= scancode_set[i].table_size) {
240  distance += 1;
241  } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) {
242  distance += 1;
243  }
244  }
245  if (distance < best_distance) {
246  best_distance = distance;
247  best_index = i;
248  }
249  }
250  if (best_index >= 0 && best_distance <= 2) {
251 #ifdef DEBUG_KEYBOARD
252  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);
253 #endif
254  SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table,
255  sizeof(SDL_Scancode) * scancode_set[best_index].table_size);
256  } else {
258 
259  printf
260  ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
261 
262  /* Determine key_layout - only works on US QWERTY layout */
263  SDL_GetDefaultKeymap(keymap);
264  for (i = min_keycode; i <= max_keycode; ++i) {
265  KeySym sym;
266 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
267  sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0);
268 #else
269  sym = X11_XKeycodeToKeysym(data->display, i, 0);
270 #endif
271  if (sym != NoSymbol) {
272  SDL_Scancode scancode;
273  printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
274  (unsigned int) sym, X11_XKeysymToString(sym));
275  scancode = X11_KeyCodeToSDLScancode(data->display, i);
276  data->key_layout[i] = scancode;
277  if (scancode == SDL_SCANCODE_UNKNOWN) {
278  printf("scancode not found\n");
279  } else {
280  printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
281  }
282  }
283  }
284  }
285 
287 
289 
290 #ifdef SDL_USE_IBUS
291  SDL_IBus_Init();
292 #endif
293 
294  return 0;
295 }
296 
297 void
299 {
301  int i;
302  SDL_Scancode scancode;
304  unsigned char group = 0;
305 
306  SDL_GetDefaultKeymap(keymap);
307 
308 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
309  {
310  XkbStateRec state;
311  if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) {
312  group = state.group;
313  }
314  }
315 #endif
316 
317 
318  for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
319  Uint32 key;
320 
321  /* Make sure this is a valid scancode */
322  scancode = data->key_layout[i];
323  if (scancode == SDL_SCANCODE_UNKNOWN) {
324  continue;
325  }
326 
327  /* See if there is a UCS keycode for this scancode */
328  key = X11_KeyCodeToUcs4(data->display, (KeyCode)i, group);
329  if (key) {
330  keymap[scancode] = key;
331  } else {
332  SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(data->display, (KeyCode)i);
333 
334  switch (keyScancode) {
335  case SDL_SCANCODE_RETURN:
336  keymap[scancode] = SDLK_RETURN;
337  break;
338  case SDL_SCANCODE_ESCAPE:
339  keymap[scancode] = SDLK_ESCAPE;
340  break;
342  keymap[scancode] = SDLK_BACKSPACE;
343  break;
344  case SDL_SCANCODE_TAB:
345  keymap[scancode] = SDLK_TAB;
346  break;
347  case SDL_SCANCODE_DELETE:
348  keymap[scancode] = SDLK_DELETE;
349  break;
350  default:
351  keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode);
352  break;
353  }
354  }
355  }
356  SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
357 }
358 
359 void
361 {
362 #ifdef SDL_USE_IBUS
363  SDL_IBus_Quit();
364 #endif
365 }
366 
367 void
369 {
370 
371 }
372 
373 void
375 {
376 #ifdef SDL_USE_IBUS
377  SDL_IBus_Reset();
378 #endif
379 }
380 
381 void
383 {
384  if (!rect) {
385  SDL_InvalidParamError("rect");
386  return;
387  }
388 
389 #ifdef SDL_USE_IBUS
390  SDL_IBus_UpdateTextRect(rect);
391 #endif
392 }
393 
394 #endif /* SDL_VIDEO_DRIVER_X11 */
395 
396 /* 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
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
void X11_QuitKeyboard(_THIS)
void X11_SetTextInputRect(_THIS, SDL_Rect *rect)
static const SDL_Scancode xfree86_scancode_table[]
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 X11_StartTextInput(_THIS)
static const SDL_Scancode xfree86_scancode_table2[]
#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:114
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
GLsizei const GLfloat * value
#define _THIS
unsigned int X11_KeySymToUcs4(KeySym keysym)
#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:42
void X11_StopTextInput(_THIS)
#define SDL_GetScancodeName
int X11_InitKeyboard(_THIS)
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
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
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:42