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 #include "SDL_hints.h"
25 
26 #ifdef SDL_INPUT_LINUXKD
27 
28 /* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source */
29 
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/ioctl.h>
33 #include <linux/kd.h>
34 #include <linux/keyboard.h>
35 #include <linux/vt.h>
36 #include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
37 
38 #include <signal.h>
39 
40 #include "../../events/SDL_events_c.h"
43 
44 /* These are not defined in older Linux kernel headers */
45 #ifndef K_UNICODE
46 #define K_UNICODE 0x03
47 #endif
48 #ifndef K_OFF
49 #define K_OFF 0x04
50 #endif
51 
52 /*
53  * Handler Tables.
54  */
55 
56 #define K_HANDLERS\
57  k_self, k_fn, k_spec, k_pad,\
58  k_dead, k_cons, k_cur, k_shift,\
59  k_meta, k_ascii, k_lock, k_lowercase,\
60  k_slock, k_dead2, k_brl, k_ignore
61 
62 typedef void (k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag);
63 static k_handler_fn K_HANDLERS;
64 static k_handler_fn *k_handler[16] = { K_HANDLERS };
65 
66 typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
67 static void fn_enter(SDL_EVDEV_keyboard_state *kbd);
68 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd);
69 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd);
70 static void fn_num(SDL_EVDEV_keyboard_state *kbd);
71 static void fn_compose(SDL_EVDEV_keyboard_state *kbd);
72 
73 static fn_handler_fn *fn_handler[] =
74 {
75  NULL, fn_enter, NULL, NULL,
76  NULL, NULL, NULL, fn_caps_toggle,
77  fn_num, NULL, NULL, NULL,
78  NULL, fn_caps_on, fn_compose, NULL,
79  NULL, NULL, NULL, fn_num
80 };
81 
82 
83 /*
84  * Keyboard State
85  */
86 
88 {
89  int console_fd;
90  int old_kbd_mode;
91  unsigned short **key_maps;
92  unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
93  SDL_bool dead_key_next;
94  int npadch; /* -1 or number assembled on pad */
95  struct kbdiacrs *accents;
96  unsigned int diacr;
97  SDL_bool rep; /* flag telling character repeat */
98  unsigned char lockstate;
99  unsigned char slockstate;
100  unsigned char ledflagstate;
101  char shift_state;
102  char text[128];
103  unsigned int text_len;
104 };
105 
106 #ifdef DUMP_ACCENTS
107 static void SDL_EVDEV_dump_accents(SDL_EVDEV_keyboard_state *kbd)
108 {
109  unsigned int i;
110 
111  printf("static struct kbdiacrs default_accents = {\n");
112  printf(" %d,\n", kbd->accents->kb_cnt);
113  printf(" {\n");
114  for (i = 0; i < kbd->accents->kb_cnt; ++i) {
115  struct kbdiacr *diacr = &kbd->accents->kbdiacr[i];
116  printf(" { 0x%.2x, 0x%.2x, 0x%.2x },\n",
117  diacr->diacr, diacr->base, diacr->result);
118  }
119  while (i < 256) {
120  printf(" { 0x00, 0x00, 0x00 },\n");
121  ++i;
122  }
123  printf(" }\n");
124  printf("};\n");
125 }
126 #endif /* DUMP_ACCENTS */
127 
128 #ifdef DUMP_KEYMAP
129 static void SDL_EVDEV_dump_keymap(SDL_EVDEV_keyboard_state *kbd)
130 {
131  int i, j;
132 
133  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
134  if (kbd->key_maps[i]) {
135  printf("static unsigned short default_key_map_%d[NR_KEYS] = {", i);
136  for (j = 0; j < NR_KEYS; ++j) {
137  if ((j%8) == 0) {
138  printf("\n ");
139  }
140  printf("0x%.4x, ", kbd->key_maps[i][j]);
141  }
142  printf("\n};\n");
143  }
144  }
145  printf("\n");
146  printf("static unsigned short *default_key_maps[MAX_NR_KEYMAPS] = {\n");
147  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
148  if (kbd->key_maps[i]) {
149  printf(" default_key_map_%d,\n", i);
150  } else {
151  printf(" NULL,\n");
152  }
153  }
154  printf("};\n");
155 }
156 #endif /* DUMP_KEYMAP */
157 
158 static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
159 {
160  int i, j;
161 
162  kbd->key_maps = (unsigned short **)SDL_calloc(MAX_NR_KEYMAPS, sizeof(unsigned short *));
163  if (!kbd->key_maps) {
164  return -1;
165  }
166 
167  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
168  struct kbentry kbe;
169 
170  kbe.kb_table = i;
171  kbe.kb_index = 0;
172  if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
173  return -1;
174  }
175 
176  if (kbe.kb_value == K_NOSUCHMAP) {
177  continue;
178  }
179 
180  kbd->key_maps[i] = (unsigned short *)SDL_malloc(NR_KEYS * sizeof(unsigned short));
181  if (!kbd->key_maps[i]) {
182  return -1;
183  }
184 
185  for (j = 0; j < NR_KEYS; ++j) {
186  kbe.kb_table = i;
187  kbe.kb_index = j;
188  if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
189  return -1;
190  }
191  kbd->key_maps[i][j] = (kbe.kb_value ^ 0xf000);
192  }
193  }
194  return 0;
195 }
196 
197 static SDL_EVDEV_keyboard_state * kbd_cleanup_state = NULL;
198 static int kbd_cleanup_sigactions_installed = 0;
199 static int kbd_cleanup_atexit_installed = 0;
200 
201 static struct sigaction old_sigaction[NSIG];
202 
203 static int fatal_signals[] =
204 {
205  /* Handlers for SIGTERM and SIGINT are installed in SDL_QuitInit. */
206  SIGHUP, SIGQUIT, SIGILL, SIGABRT,
207  SIGFPE, SIGSEGV, SIGPIPE, SIGBUS,
208  SIGSYS
209 };
210 
211 static void kbd_cleanup(void)
212 {
213  SDL_EVDEV_keyboard_state* kbd = kbd_cleanup_state;
214  if (kbd == NULL) {
215  return;
216  }
217  kbd_cleanup_state = NULL;
218 
219  fprintf(stderr, "(SDL restoring keyboard) ");
220  ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
221 }
222 
223 void
224 SDL_EVDEV_kbd_reraise_signal(int sig)
225 {
226  raise(sig);
227 }
228 
229 siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL;
230 void* SDL_EVDEV_kdb_cleanup_ucontext = NULL;
231 
232 static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext)
233 {
234  struct sigaction* old_action_p = &(old_sigaction[signum]);
235  sigset_t sigset;
236 
237  /* Restore original signal handler before going any further. */
238  sigaction(signum, old_action_p, NULL);
239 
240  /* Unmask current signal. */
241  sigemptyset(&sigset);
242  sigaddset(&sigset, signum);
243  sigprocmask(SIG_UNBLOCK, &sigset, NULL);
244 
245  /* Save original signal info and context for archeologists. */
246  SDL_EVDEV_kdb_cleanup_siginfo = info;
247  SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
248 
249  /* Restore keyboard. */
250  kbd_cleanup();
251 
252  /* Reraise signal. */
253  SDL_EVDEV_kbd_reraise_signal(signum);
254 }
255 
256 static void kbd_unregister_emerg_cleanup()
257 {
258  int tabidx, signum;
259 
260  kbd_cleanup_state = NULL;
261 
262  if (!kbd_cleanup_sigactions_installed) {
263  return;
264  }
265  kbd_cleanup_sigactions_installed = 0;
266 
267  for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
268  struct sigaction* old_action_p;
269  struct sigaction cur_action;
270  signum = fatal_signals[tabidx];
271  old_action_p = &(old_sigaction[signum]);
272 
273  /* Examine current signal action */
274  if (sigaction(signum, NULL, &cur_action))
275  continue;
276 
277  /* Check if action installed and not modifed */
278  if (!(cur_action.sa_flags & SA_SIGINFO)
279  || cur_action.sa_sigaction != &kbd_cleanup_signal_action)
280  continue;
281 
282  /* Restore original action */
283  sigaction(signum, old_action_p, NULL);
284  }
285 }
286 
287 static void kbd_cleanup_atexit(void)
288 {
289  /* Restore keyboard. */
290  kbd_cleanup();
291 
292  /* Try to restore signal handlers in case shared library is being unloaded */
293  kbd_unregister_emerg_cleanup();
294 }
295 
296 static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd)
297 {
298  int tabidx, signum;
299 
300  if (kbd_cleanup_state != NULL) {
301  return;
302  }
303  kbd_cleanup_state = kbd;
304 
305  if (!kbd_cleanup_atexit_installed) {
306  /* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish
307  * functions that are called when the shared library is unloaded.
308  * -- man atexit(3)
309  */
310  atexit(kbd_cleanup_atexit);
311  kbd_cleanup_atexit_installed = 1;
312  }
313 
314  if (kbd_cleanup_sigactions_installed) {
315  return;
316  }
317  kbd_cleanup_sigactions_installed = 1;
318 
319  for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
320  struct sigaction* old_action_p;
321  struct sigaction new_action;
322  signum = fatal_signals[tabidx];
323  old_action_p = &(old_sigaction[signum]);
324  if (sigaction(signum, NULL, old_action_p))
325  continue;
326 
327  /* Skip SIGHUP and SIGPIPE if handler is already installed
328  * - assume the handler will do the cleanup
329  */
330  if ((signum == SIGHUP || signum == SIGPIPE)
331  && (old_action_p->sa_handler != SIG_DFL
332  || (void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
333  continue;
334 
335  new_action = *old_action_p;
336  new_action.sa_flags |= SA_SIGINFO;
337  new_action.sa_sigaction = &kbd_cleanup_signal_action;
338  sigaction(signum, &new_action, NULL);
339  }
340 }
341 
343 SDL_EVDEV_kbd_init(void)
344 {
346  int i;
347  char flag_state;
348  char shift_state[2] = {TIOCL_GETSHIFTSTATE, 0};
349 
350  kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
351  if (!kbd) {
352  return NULL;
353  }
354 
355  kbd->npadch = -1;
356 
357  /* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
358  kbd->console_fd = open("/dev/tty", O_RDONLY);
359 
360  if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
361  kbd->shift_state = *shift_state;
362  }
363 
364  if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
365  kbd->ledflagstate = flag_state;
366  }
367 
368  kbd->accents = &default_accents;
369  if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
370  /* No worries, we'll use the default accent table */
371  }
372 
373  kbd->key_maps = default_key_maps;
374  if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
375  /* Set the keyboard in UNICODE mode and load the keymaps */
376  ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
377 
378  if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
379  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
380  if (kbd->key_maps[i]) {
381  SDL_free(kbd->key_maps[i]);
382  }
383  }
384  SDL_free(kbd->key_maps);
385 
386  kbd->key_maps = default_key_maps;
387  }
388 
389  /* Allow inhibiting keyboard mute with env. variable for debugging etc. */
390  if (getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
391  /* Mute the keyboard so keystrokes only generate evdev events
392  * and do not leak through to the console
393  */
394  ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
395 
396  /* Make sure to restore keyboard if application fails to call
397  * SDL_Quit before exit or fatal signal is raised.
398  */
400  kbd_register_emerg_cleanup(kbd);
401  }
402  }
403  }
404 
405 #ifdef DUMP_ACCENTS
406  SDL_EVDEV_dump_accents(kbd);
407 #endif
408 #ifdef DUMP_KEYMAP
409  SDL_EVDEV_dump_keymap(kbd);
410 #endif
411  return kbd;
412 }
413 
414 void
416 {
417  if (!kbd) {
418  return;
419  }
420 
421  kbd_unregister_emerg_cleanup();
422 
423  if (kbd->console_fd >= 0) {
424  /* Restore the original keyboard mode */
425  ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
426 
427  close(kbd->console_fd);
428  kbd->console_fd = -1;
429  }
430 
431  if (kbd->key_maps && kbd->key_maps != default_key_maps) {
432  int i;
433  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
434  if (kbd->key_maps[i]) {
435  SDL_free(kbd->key_maps[i]);
436  }
437  }
438  SDL_free(kbd->key_maps);
439  }
440 
441  SDL_free(kbd);
442 }
443 
444 /*
445  * Helper Functions.
446  */
447 static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
448 {
449  /* c is already part of a UTF-8 sequence and safe to add as a character */
450  if (kbd->text_len < (sizeof(kbd->text)-1)) {
451  kbd->text[kbd->text_len++] = (char)c;
452  }
453 }
454 
455 static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
456 {
457  if (c < 0x80)
458  /* 0******* */
459  put_queue(kbd, c);
460  else if (c < 0x800) {
461  /* 110***** 10****** */
462  put_queue(kbd, 0xc0 | (c >> 6));
463  put_queue(kbd, 0x80 | (c & 0x3f));
464  } else if (c < 0x10000) {
465  if (c >= 0xD800 && c < 0xE000)
466  return;
467  if (c == 0xFFFF)
468  return;
469  /* 1110**** 10****** 10****** */
470  put_queue(kbd, 0xe0 | (c >> 12));
471  put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
472  put_queue(kbd, 0x80 | (c & 0x3f));
473  } else if (c < 0x110000) {
474  /* 11110*** 10****** 10****** 10****** */
475  put_queue(kbd, 0xf0 | (c >> 18));
476  put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
477  put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
478  put_queue(kbd, 0x80 | (c & 0x3f));
479  }
480 }
481 
482 /*
483  * We have a combining character DIACR here, followed by the character CH.
484  * If the combination occurs in the table, return the corresponding value.
485  * Otherwise, if CH is a space or equals DIACR, return DIACR.
486  * Otherwise, conclude that DIACR was not combining after all,
487  * queue it and return CH.
488  */
489 static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
490 {
491  unsigned int d = kbd->diacr;
492  unsigned int i;
493 
494  kbd->diacr = 0;
495 
496  for (i = 0; i < kbd->accents->kb_cnt; i++) {
497  if (kbd->accents->kbdiacr[i].diacr == d &&
498  kbd->accents->kbdiacr[i].base == ch) {
499  return kbd->accents->kbdiacr[i].result;
500  }
501  }
502 
503  if (ch == ' ' || ch == d)
504  return d;
505 
506  put_utf8(kbd, d);
507 
508  return ch;
509 }
510 
511 static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
512 {
513  return ((kbd->ledflagstate >> flag) & 1);
514 }
515 
516 static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
517 {
518  kbd->ledflagstate |= 1 << flag;
519 }
520 
521 static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
522 {
523  kbd->ledflagstate &= ~(1 << flag);
524 }
525 
526 static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
527 {
528  kbd->lockstate ^= 1 << flag;
529 }
530 
531 static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
532 {
533  kbd->slockstate ^= 1 << flag;
534 }
535 
536 static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
537 {
538  kbd->ledflagstate ^= 1 << flag;
539 }
540 
541 /*
542  * Special function handlers
543  */
544 
545 static void fn_enter(SDL_EVDEV_keyboard_state *kbd)
546 {
547  if (kbd->diacr) {
548  put_utf8(kbd, kbd->diacr);
549  kbd->diacr = 0;
550  }
551 }
552 
553 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd)
554 {
555  if (kbd->rep)
556  return;
557 
558  chg_vc_kbd_led(kbd, K_CAPSLOCK);
559 }
560 
561 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd)
562 {
563  if (kbd->rep)
564  return;
565 
566  set_vc_kbd_led(kbd, K_CAPSLOCK);
567 }
568 
569 static void fn_num(SDL_EVDEV_keyboard_state *kbd)
570 {
571  if (!kbd->rep)
572  chg_vc_kbd_led(kbd, K_NUMLOCK);
573 }
574 
575 static void fn_compose(SDL_EVDEV_keyboard_state *kbd)
576 {
577  kbd->dead_key_next = SDL_TRUE;
578 }
579 
580 /*
581  * Special key handlers
582  */
583 
584 static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
585 {
586 }
587 
588 static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
589 {
590  if (up_flag)
591  return;
592  if (value >= SDL_arraysize(fn_handler))
593  return;
594  if (fn_handler[value])
595  fn_handler[value](kbd);
596 }
597 
598 static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
599 {
600 }
601 
602 static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
603 {
604  if (up_flag)
605  return; /* no action, if this is a key release */
606 
607  if (kbd->diacr)
608  value = handle_diacr(kbd, value);
609 
610  if (kbd->dead_key_next) {
611  kbd->dead_key_next = SDL_FALSE;
612  kbd->diacr = value;
613  return;
614  }
615  put_utf8(kbd, value);
616 }
617 
618 static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
619 {
620  if (up_flag)
621  return;
622 
623  kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
624 }
625 
626 static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
627 {
628  const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
629 
630  k_deadunicode(kbd, ret_diacr[value], up_flag);
631 }
632 
633 static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
634 {
635  k_deadunicode(kbd, value, up_flag);
636 }
637 
638 static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
639 {
640 }
641 
642 static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
643 {
644 }
645 
646 static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
647 {
648 }
649 
650 static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
651 {
652  static const char pad_chars[] = "0123456789+-*/\015,.?()#";
653 
654  if (up_flag)
655  return; /* no action, if this is a key release */
656 
657  if (!vc_kbd_led(kbd, K_NUMLOCK)) {
658  /* unprintable action */
659  return;
660  }
661 
662  put_queue(kbd, pad_chars[value]);
663 }
664 
665 static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
666 {
667  int old_state = kbd->shift_state;
668 
669  if (kbd->rep)
670  return;
671  /*
672  * Mimic typewriter:
673  * a CapsShift key acts like Shift but undoes CapsLock
674  */
675  if (value == KVAL(K_CAPSSHIFT)) {
676  value = KVAL(K_SHIFT);
677  if (!up_flag)
678  clr_vc_kbd_led(kbd, K_CAPSLOCK);
679  }
680 
681  if (up_flag) {
682  /*
683  * handle the case that two shift or control
684  * keys are depressed simultaneously
685  */
686  if (kbd->shift_down[value])
687  kbd->shift_down[value]--;
688  } else
689  kbd->shift_down[value]++;
690 
691  if (kbd->shift_down[value])
692  kbd->shift_state |= (1 << value);
693  else
694  kbd->shift_state &= ~(1 << value);
695 
696  /* kludge */
697  if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
698  put_utf8(kbd, kbd->npadch);
699  kbd->npadch = -1;
700  }
701 }
702 
703 static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
704 {
705 }
706 
707 static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
708 {
709  int base;
710 
711  if (up_flag)
712  return;
713 
714  if (value < 10) {
715  /* decimal input of code, while Alt depressed */
716  base = 10;
717  } else {
718  /* hexadecimal input of code, while AltGr depressed */
719  value -= 10;
720  base = 16;
721  }
722 
723  if (kbd->npadch == -1)
724  kbd->npadch = value;
725  else
726  kbd->npadch = kbd->npadch * base + value;
727 }
728 
729 static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
730 {
731  if (up_flag || kbd->rep)
732  return;
733 
734  chg_vc_kbd_lock(kbd, value);
735 }
736 
737 static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
738 {
739  k_shift(kbd, value, up_flag);
740  if (up_flag || kbd->rep)
741  return;
742 
743  chg_vc_kbd_slock(kbd, value);
744  /* try to make Alt, oops, AltGr and such work */
745  if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
746  kbd->slockstate = 0;
747  chg_vc_kbd_slock(kbd, value);
748  }
749 }
750 
751 static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
752 {
753 }
754 
755 void
756 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
757 {
758  unsigned char shift_final;
759  unsigned char type;
760  unsigned short *key_map;
761  unsigned short keysym;
762 
763  if (!kbd) {
764  return;
765  }
766 
767  kbd->rep = (down == 2);
768 
769  shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
770  key_map = kbd->key_maps[shift_final];
771  if (!key_map) {
772  /* Unsupported shift state (e.g. ctrl = 4, alt = 8), just reset to the default state */
773  kbd->shift_state = 0;
774  kbd->slockstate = 0;
775  kbd->lockstate = 0;
776  return;
777  }
778 
779  if (keycode < NR_KEYS) {
780  keysym = key_map[keycode];
781  } else {
782  return;
783  }
784 
785  type = KTYP(keysym);
786 
787  if (type < 0xf0) {
788  if (down) {
789  put_utf8(kbd, keysym);
790  }
791  } else {
792  type -= 0xf0;
793 
794  /* if type is KT_LETTER then it can be affected by Caps Lock */
795  if (type == KT_LETTER) {
796  type = KT_LATIN;
797 
798  if (vc_kbd_led(kbd, K_CAPSLOCK)) {
799  key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
800  if (key_map) {
801  keysym = key_map[keycode];
802  }
803  }
804  }
805 
806  (*k_handler[type])(kbd, keysym & 0xff, !down);
807 
808  if (type != KT_SLOCK) {
809  kbd->slockstate = 0;
810  }
811  }
812 
813  if (kbd->text_len > 0) {
814  kbd->text[kbd->text_len] = '\0';
815  SDL_SendKeyboardText(kbd->text);
816  kbd->text_len = 0;
817  }
818 }
819 
820 #else /* !SDL_INPUT_LINUXKD */
821 
824 {
825  return NULL;
826 }
827 
828 void
829 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
830 {
831 }
832 
833 void
835 {
836 }
837 
838 #endif /* SDL_INPUT_LINUXKD */
839 
840 /* vi: set ts=4 sw=4 expandtab: */
struct xkb_state * state
static struct kbdiacrs default_accents
#define SDL_GetHintBoolean
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
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)
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 int in j)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:161
SDL_EVDEV_keyboard_state * SDL_EVDEV_kbd_init(void)
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
#define SDL_calloc
#define SDL_HINT_NO_SIGNAL_HANDLERS
Tell SDL not to catch the SIGINT or SIGTERM signals.
Definition: SDL_hints.h:904
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:115
#define SDL_malloc
struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state
Definition: SDL_evdev_kbd.h:26