SDL  2.0
SDL_evdev_kbd.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 #include "SDL_evdev_kbd.h"
24 
25 #ifdef SDL_INPUT_LINUXKD
26 
27 /* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source */
28 
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <sys/ioctl.h>
32 #include <linux/kd.h>
33 #include <linux/keyboard.h>
34 #include <linux/vt.h>
35 #include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
36 
37 #include "../../events/SDL_events_c.h"
40 
41 /* These are not defined in older Linux kernel headers */
42 #ifndef K_UNICODE
43 #define K_UNICODE 0x03
44 #endif
45 #ifndef K_OFF
46 #define K_OFF 0x04
47 #endif
48 
49 /*
50  * Handler Tables.
51  */
52 
53 #define K_HANDLERS\
54  k_self, k_fn, k_spec, k_pad,\
55  k_dead, k_cons, k_cur, k_shift,\
56  k_meta, k_ascii, k_lock, k_lowercase,\
57  k_slock, k_dead2, k_brl, k_ignore
58 
59 typedef void (k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag);
60 static k_handler_fn K_HANDLERS;
61 static k_handler_fn *k_handler[16] = { K_HANDLERS };
62 
63 typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
64 static void fn_enter(SDL_EVDEV_keyboard_state *kbd);
65 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd);
66 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd);
67 static void fn_num(SDL_EVDEV_keyboard_state *kbd);
68 static void fn_compose(SDL_EVDEV_keyboard_state *kbd);
69 
70 static fn_handler_fn *fn_handler[] =
71 {
72  NULL, fn_enter, NULL, NULL,
73  NULL, NULL, NULL, fn_caps_toggle,
74  fn_num, NULL, NULL, NULL,
75  NULL, fn_caps_on, fn_compose, NULL,
76  NULL, NULL, NULL, fn_num
77 };
78 
79 
80 /*
81  * Keyboard State
82  */
83 
85 {
86  int console_fd;
87  int old_kbd_mode;
88  unsigned short **key_maps;
89  unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
90  SDL_bool dead_key_next;
91  int npadch; /* -1 or number assembled on pad */
92  struct kbdiacrs *accents;
93  unsigned int diacr;
94  SDL_bool rep; /* flag telling character repeat */
95  unsigned char lockstate;
96  unsigned char slockstate;
97  unsigned char ledflagstate;
98  char shift_state;
99  char text[128];
100  unsigned int text_len;
101 };
102 
103 #ifdef DUMP_ACCENTS
104 static void SDL_EVDEV_dump_accents(SDL_EVDEV_keyboard_state *kbd)
105 {
106  unsigned int i;
107 
108  printf("static struct kbdiacrs default_accents = {\n");
109  printf(" %d,\n", kbd->accents->kb_cnt);
110  printf(" {\n");
111  for (i = 0; i < kbd->accents->kb_cnt; ++i) {
112  struct kbdiacr *diacr = &kbd->accents->kbdiacr[i];
113  printf(" { 0x%.2x, 0x%.2x, 0x%.2x },\n",
114  diacr->diacr, diacr->base, diacr->result);
115  }
116  while (i < 256) {
117  printf(" { 0x00, 0x00, 0x00 },\n");
118  ++i;
119  }
120  printf(" }\n");
121  printf("};\n");
122 }
123 #endif /* DUMP_ACCENTS */
124 
125 #ifdef DUMP_KEYMAP
126 static void SDL_EVDEV_dump_keymap(SDL_EVDEV_keyboard_state *kbd)
127 {
128  int i, j;
129 
130  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
131  if (kbd->key_maps[i]) {
132  printf("static unsigned short default_key_map_%d[NR_KEYS] = {", i);
133  for (j = 0; j < NR_KEYS; ++j) {
134  if ((j%8) == 0) {
135  printf("\n ");
136  }
137  printf("0x%.4x, ", kbd->key_maps[i][j]);
138  }
139  printf("\n};\n");
140  }
141  }
142  printf("\n");
143  printf("static unsigned short *default_key_maps[MAX_NR_KEYMAPS] = {\n");
144  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
145  if (kbd->key_maps[i]) {
146  printf(" default_key_map_%d,\n", i);
147  } else {
148  printf(" NULL,\n");
149  }
150  }
151  printf("};\n");
152 }
153 #endif /* DUMP_KEYMAP */
154 
155 static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
156 {
157  int i, j;
158 
159  kbd->key_maps = (unsigned short **)SDL_calloc(MAX_NR_KEYMAPS, sizeof(unsigned short *));
160  if (!kbd->key_maps) {
161  return -1;
162  }
163 
164  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
165  struct kbentry kbe;
166 
167  kbe.kb_table = i;
168  kbe.kb_index = 0;
169  if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
170  return -1;
171  }
172 
173  if (kbe.kb_value == K_NOSUCHMAP) {
174  continue;
175  }
176 
177  kbd->key_maps[i] = (unsigned short *)SDL_malloc(NR_KEYS * sizeof(unsigned short));
178  if (!kbd->key_maps[i]) {
179  return -1;
180  }
181 
182  for (j = 0; j < NR_KEYS; ++j) {
183  kbe.kb_table = i;
184  kbe.kb_index = j;
185  if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
186  return -1;
187  }
188  kbd->key_maps[i][j] = (kbe.kb_value ^ 0xf000);
189  }
190  }
191  return 0;
192 }
193 
195 SDL_EVDEV_kbd_init(void)
196 {
198  int i;
199  char flag_state;
200  char shift_state[2] = {TIOCL_GETSHIFTSTATE, 0};
201 
202  kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
203  if (!kbd) {
204  return NULL;
205  }
206 
207  kbd->npadch = -1;
208 
209  /* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
210  kbd->console_fd = open("/dev/tty", O_RDONLY);
211 
212  if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
213  kbd->shift_state = *shift_state;
214  }
215 
216  if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
217  kbd->ledflagstate = flag_state;
218  }
219 
220  kbd->accents = &default_accents;
221  if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
222  /* No worries, we'll use the default accent table */
223  }
224 
225  kbd->key_maps = default_key_maps;
226  if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
227  /* Set the keyboard in UNICODE mode and load the keymaps */
228  ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
229 
230  if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
231  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
232  if (kbd->key_maps[i]) {
233  SDL_free(kbd->key_maps[i]);
234  }
235  }
236  SDL_free(kbd->key_maps);
237 
238  kbd->key_maps = default_key_maps;
239  }
240 
241  /* Mute the keyboard so keystrokes only generate evdev events
242  * and do not leak through to the console
243  */
244  ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
245  }
246 
247 #ifdef DUMP_ACCENTS
248  SDL_EVDEV_dump_accents(kbd);
249 #endif
250 #ifdef DUMP_KEYMAP
251  SDL_EVDEV_dump_keymap(kbd);
252 #endif
253  return kbd;
254 }
255 
256 void
258 {
259  if (!kbd) {
260  return;
261  }
262 
263  if (kbd->console_fd >= 0) {
264  /* Restore the original keyboard mode */
265  ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
266 
267  close(kbd->console_fd);
268  kbd->console_fd = -1;
269  }
270 
271  if (kbd->key_maps && kbd->key_maps != default_key_maps) {
272  int i;
273  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
274  if (kbd->key_maps[i]) {
275  SDL_free(kbd->key_maps[i]);
276  }
277  }
278  SDL_free(kbd->key_maps);
279  }
280 
281  SDL_free(kbd);
282 }
283 
284 /*
285  * Helper Functions.
286  */
287 static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
288 {
289  /* c is already part of a UTF-8 sequence and safe to add as a character */
290  if (kbd->text_len < (sizeof(kbd->text)-1)) {
291  kbd->text[kbd->text_len++] = (char)c;
292  }
293 }
294 
295 static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
296 {
297  if (c < 0x80)
298  /* 0******* */
299  put_queue(kbd, c);
300  else if (c < 0x800) {
301  /* 110***** 10****** */
302  put_queue(kbd, 0xc0 | (c >> 6));
303  put_queue(kbd, 0x80 | (c & 0x3f));
304  } else if (c < 0x10000) {
305  if (c >= 0xD800 && c < 0xE000)
306  return;
307  if (c == 0xFFFF)
308  return;
309  /* 1110**** 10****** 10****** */
310  put_queue(kbd, 0xe0 | (c >> 12));
311  put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
312  put_queue(kbd, 0x80 | (c & 0x3f));
313  } else if (c < 0x110000) {
314  /* 11110*** 10****** 10****** 10****** */
315  put_queue(kbd, 0xf0 | (c >> 18));
316  put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
317  put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
318  put_queue(kbd, 0x80 | (c & 0x3f));
319  }
320 }
321 
322 /*
323  * We have a combining character DIACR here, followed by the character CH.
324  * If the combination occurs in the table, return the corresponding value.
325  * Otherwise, if CH is a space or equals DIACR, return DIACR.
326  * Otherwise, conclude that DIACR was not combining after all,
327  * queue it and return CH.
328  */
329 static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
330 {
331  unsigned int d = kbd->diacr;
332  unsigned int i;
333 
334  kbd->diacr = 0;
335 
336  for (i = 0; i < kbd->accents->kb_cnt; i++) {
337  if (kbd->accents->kbdiacr[i].diacr == d &&
338  kbd->accents->kbdiacr[i].base == ch) {
339  return kbd->accents->kbdiacr[i].result;
340  }
341  }
342 
343  if (ch == ' ' || ch == d)
344  return d;
345 
346  put_utf8(kbd, d);
347 
348  return ch;
349 }
350 
351 static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
352 {
353  return ((kbd->ledflagstate >> flag) & 1);
354 }
355 
356 static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
357 {
358  kbd->ledflagstate |= 1 << flag;
359 }
360 
361 static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
362 {
363  kbd->ledflagstate &= ~(1 << flag);
364 }
365 
366 static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
367 {
368  kbd->lockstate ^= 1 << flag;
369 }
370 
371 static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
372 {
373  kbd->slockstate ^= 1 << flag;
374 }
375 
376 static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
377 {
378  kbd->ledflagstate ^= 1 << flag;
379 }
380 
381 /*
382  * Special function handlers
383  */
384 
385 static void fn_enter(SDL_EVDEV_keyboard_state *kbd)
386 {
387  if (kbd->diacr) {
388  put_utf8(kbd, kbd->diacr);
389  kbd->diacr = 0;
390  }
391 }
392 
393 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd)
394 {
395  if (kbd->rep)
396  return;
397 
398  chg_vc_kbd_led(kbd, K_CAPSLOCK);
399 }
400 
401 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd)
402 {
403  if (kbd->rep)
404  return;
405 
406  set_vc_kbd_led(kbd, K_CAPSLOCK);
407 }
408 
409 static void fn_num(SDL_EVDEV_keyboard_state *kbd)
410 {
411  if (!kbd->rep)
412  chg_vc_kbd_led(kbd, K_NUMLOCK);
413 }
414 
415 static void fn_compose(SDL_EVDEV_keyboard_state *kbd)
416 {
417  kbd->dead_key_next = SDL_TRUE;
418 }
419 
420 /*
421  * Special key handlers
422  */
423 
424 static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
425 {
426 }
427 
428 static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
429 {
430  if (up_flag)
431  return;
432  if (value >= SDL_arraysize(fn_handler))
433  return;
434  if (fn_handler[value])
435  fn_handler[value](kbd);
436 }
437 
438 static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
439 {
440 }
441 
442 static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
443 {
444  if (up_flag)
445  return; /* no action, if this is a key release */
446 
447  if (kbd->diacr)
448  value = handle_diacr(kbd, value);
449 
450  if (kbd->dead_key_next) {
451  kbd->dead_key_next = SDL_FALSE;
452  kbd->diacr = value;
453  return;
454  }
455  put_utf8(kbd, value);
456 }
457 
458 static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
459 {
460  if (up_flag)
461  return;
462 
463  kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
464 }
465 
466 static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
467 {
468  const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
469 
470  k_deadunicode(kbd, ret_diacr[value], up_flag);
471 }
472 
473 static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
474 {
475  k_deadunicode(kbd, value, up_flag);
476 }
477 
478 static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
479 {
480 }
481 
482 static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
483 {
484 }
485 
486 static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
487 {
488 }
489 
490 static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
491 {
492  static const char pad_chars[] = "0123456789+-*/\015,.?()#";
493 
494  if (up_flag)
495  return; /* no action, if this is a key release */
496 
497  if (!vc_kbd_led(kbd, K_NUMLOCK)) {
498  /* unprintable action */
499  return;
500  }
501 
502  put_queue(kbd, pad_chars[value]);
503 }
504 
505 static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
506 {
507  int old_state = kbd->shift_state;
508 
509  if (kbd->rep)
510  return;
511  /*
512  * Mimic typewriter:
513  * a CapsShift key acts like Shift but undoes CapsLock
514  */
515  if (value == KVAL(K_CAPSSHIFT)) {
516  value = KVAL(K_SHIFT);
517  if (!up_flag)
518  clr_vc_kbd_led(kbd, K_CAPSLOCK);
519  }
520 
521  if (up_flag) {
522  /*
523  * handle the case that two shift or control
524  * keys are depressed simultaneously
525  */
526  if (kbd->shift_down[value])
527  kbd->shift_down[value]--;
528  } else
529  kbd->shift_down[value]++;
530 
531  if (kbd->shift_down[value])
532  kbd->shift_state |= (1 << value);
533  else
534  kbd->shift_state &= ~(1 << value);
535 
536  /* kludge */
537  if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
538  put_utf8(kbd, kbd->npadch);
539  kbd->npadch = -1;
540  }
541 }
542 
543 static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
544 {
545 }
546 
547 static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
548 {
549  int base;
550 
551  if (up_flag)
552  return;
553 
554  if (value < 10) {
555  /* decimal input of code, while Alt depressed */
556  base = 10;
557  } else {
558  /* hexadecimal input of code, while AltGr depressed */
559  value -= 10;
560  base = 16;
561  }
562 
563  if (kbd->npadch == -1)
564  kbd->npadch = value;
565  else
566  kbd->npadch = kbd->npadch * base + value;
567 }
568 
569 static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
570 {
571  if (up_flag || kbd->rep)
572  return;
573 
574  chg_vc_kbd_lock(kbd, value);
575 }
576 
577 static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
578 {
579  k_shift(kbd, value, up_flag);
580  if (up_flag || kbd->rep)
581  return;
582 
583  chg_vc_kbd_slock(kbd, value);
584  /* try to make Alt, oops, AltGr and such work */
585  if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
586  kbd->slockstate = 0;
587  chg_vc_kbd_slock(kbd, value);
588  }
589 }
590 
591 static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
592 {
593 }
594 
595 void
596 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
597 {
598  unsigned char shift_final;
599  unsigned char type;
600  unsigned short *key_map;
601  unsigned short keysym;
602 
603  if (!kbd) {
604  return;
605  }
606 
607  kbd->rep = (down == 2);
608 
609  shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
610  key_map = kbd->key_maps[shift_final];
611  if (!key_map) {
612  kbd->slockstate = 0;
613  return;
614  }
615 
616  if (keycode < NR_KEYS) {
617  keysym = key_map[keycode];
618  } else {
619  return;
620  }
621 
622  type = KTYP(keysym);
623 
624  if (type < 0xf0) {
625  if (down) {
626  put_utf8(kbd, keysym);
627  }
628  } else {
629  type -= 0xf0;
630 
631  /* if type is KT_LETTER then it can be affected by Caps Lock */
632  if (type == KT_LETTER) {
633  type = KT_LATIN;
634 
635  if (vc_kbd_led(kbd, K_CAPSLOCK)) {
636  key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
637  if (key_map) {
638  keysym = key_map[keycode];
639  }
640  }
641  }
642 
643  (*k_handler[type])(kbd, keysym & 0xff, !down);
644 
645  if (type != KT_SLOCK) {
646  kbd->slockstate = 0;
647  }
648  }
649 
650  if (kbd->text_len > 0) {
651  kbd->text[kbd->text_len] = '\0';
652  SDL_SendKeyboardText(kbd->text);
653  kbd->text_len = 0;
654  }
655 }
656 
657 #else /* !SDL_INPUT_LINUXKD */
658 
661 {
662  return NULL;
663 }
664 
665 void
666 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
667 {
668 }
669 
670 void
672 {
673 }
674 
675 #endif /* SDL_INPUT_LINUXKD */
676 
677 /* vi: set ts=4 sw=4 expandtab: */
struct xkb_state * state
static struct kbdiacrs default_accents
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:789
#define SDL_free
void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
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
const GLubyte * c
GLsizei const GLfloat * value
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:164
SDL_bool
Definition: SDL_stdinc.h:139
SDL_EVDEV_keyboard_state * SDL_EVDEV_kbd_init(void)
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
#define SDL_calloc
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
static unsigned short * default_key_maps[MAX_NR_KEYMAPS]
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state
Definition: SDL_evdev_kbd.h:23