SDL  2.0
SDL_evdev_kbd.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2019 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  ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
220 }
221 
222 void
223 SDL_EVDEV_kbd_reraise_signal(int sig)
224 {
225  raise(sig);
226 }
227 
228 siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL;
229 void* SDL_EVDEV_kdb_cleanup_ucontext = NULL;
230 
231 static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext)
232 {
233  struct sigaction* old_action_p = &(old_sigaction[signum]);
234  sigset_t sigset;
235 
236  /* Restore original signal handler before going any further. */
237  sigaction(signum, old_action_p, NULL);
238 
239  /* Unmask current signal. */
240  sigemptyset(&sigset);
241  sigaddset(&sigset, signum);
242  sigprocmask(SIG_UNBLOCK, &sigset, NULL);
243 
244  /* Save original signal info and context for archeologists. */
245  SDL_EVDEV_kdb_cleanup_siginfo = info;
246  SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
247 
248  /* Restore keyboard. */
249  kbd_cleanup();
250 
251  /* Reraise signal. */
252  SDL_EVDEV_kbd_reraise_signal(signum);
253 }
254 
255 static void kbd_unregister_emerg_cleanup()
256 {
257  int tabidx, signum;
258 
259  kbd_cleanup_state = NULL;
260 
261  if (!kbd_cleanup_sigactions_installed) {
262  return;
263  }
264  kbd_cleanup_sigactions_installed = 0;
265 
266  for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
267  struct sigaction* old_action_p;
268  struct sigaction cur_action;
269  signum = fatal_signals[tabidx];
270  old_action_p = &(old_sigaction[signum]);
271 
272  /* Examine current signal action */
273  if (sigaction(signum, NULL, &cur_action))
274  continue;
275 
276  /* Check if action installed and not modifed */
277  if (!(cur_action.sa_flags & SA_SIGINFO)
278  || cur_action.sa_sigaction != &kbd_cleanup_signal_action)
279  continue;
280 
281  /* Restore original action */
282  sigaction(signum, old_action_p, NULL);
283  }
284 }
285 
286 static void kbd_cleanup_atexit(void)
287 {
288  /* Restore keyboard. */
289  kbd_cleanup();
290 
291  /* Try to restore signal handlers in case shared library is being unloaded */
292  kbd_unregister_emerg_cleanup();
293 }
294 
295 static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd)
296 {
297  int tabidx, signum;
298 
299  if (kbd_cleanup_state != NULL) {
300  return;
301  }
302  kbd_cleanup_state = kbd;
303 
304  if (!kbd_cleanup_atexit_installed) {
305  /* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish
306  * functions that are called when the shared library is unloaded.
307  * -- man atexit(3)
308  */
309  atexit(kbd_cleanup_atexit);
310  kbd_cleanup_atexit_installed = 1;
311  }
312 
313  if (kbd_cleanup_sigactions_installed) {
314  return;
315  }
316  kbd_cleanup_sigactions_installed = 1;
317 
318  for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
319  struct sigaction* old_action_p;
320  struct sigaction new_action;
321  signum = fatal_signals[tabidx];
322  old_action_p = &(old_sigaction[signum]);
323  if (sigaction(signum, NULL, old_action_p))
324  continue;
325 
326  /* Skip SIGHUP and SIGPIPE if handler is already installed
327  * - assume the handler will do the cleanup
328  */
329  if ((signum == SIGHUP || signum == SIGPIPE)
330  && (old_action_p->sa_handler != SIG_DFL
331  || (void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
332  continue;
333 
334  new_action = *old_action_p;
335  new_action.sa_flags |= SA_SIGINFO;
336  new_action.sa_sigaction = &kbd_cleanup_signal_action;
337  sigaction(signum, &new_action, NULL);
338  }
339 }
340 
342 SDL_EVDEV_kbd_init(void)
343 {
345  int i;
346  char flag_state;
347  char shift_state[ sizeof (long) ] = {TIOCL_GETSHIFTSTATE, 0};
348 
349  kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
350  if (!kbd) {
351  return NULL;
352  }
353 
354  kbd->npadch = -1;
355 
356  /* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
357  kbd->console_fd = open("/dev/tty", O_RDONLY);
358 
359  if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
360  kbd->shift_state = *shift_state;
361  }
362 
363  if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
364  kbd->ledflagstate = flag_state;
365  }
366 
367  kbd->accents = &default_accents;
368  if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
369  /* No worries, we'll use the default accent table */
370  }
371 
372  kbd->key_maps = default_key_maps;
373  if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
374  /* Set the keyboard in UNICODE mode and load the keymaps */
375  ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
376 
377  if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
378  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
379  if (kbd->key_maps[i]) {
380  SDL_free(kbd->key_maps[i]);
381  }
382  }
383  SDL_free(kbd->key_maps);
384 
385  kbd->key_maps = default_key_maps;
386  }
387 
388  /* Allow inhibiting keyboard mute with env. variable for debugging etc. */
389  if (getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
390  /* Mute the keyboard so keystrokes only generate evdev events
391  * and do not leak through to the console
392  */
393  ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
394 
395  /* Make sure to restore keyboard if application fails to call
396  * SDL_Quit before exit or fatal signal is raised.
397  */
399  kbd_register_emerg_cleanup(kbd);
400  }
401  }
402  }
403 
404 #ifdef DUMP_ACCENTS
405  SDL_EVDEV_dump_accents(kbd);
406 #endif
407 #ifdef DUMP_KEYMAP
408  SDL_EVDEV_dump_keymap(kbd);
409 #endif
410  return kbd;
411 }
412 
413 void
415 {
416  if (!kbd) {
417  return;
418  }
419 
420  kbd_unregister_emerg_cleanup();
421 
422  if (kbd->console_fd >= 0) {
423  /* Restore the original keyboard mode */
424  ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
425 
426  close(kbd->console_fd);
427  kbd->console_fd = -1;
428  }
429 
430  if (kbd->key_maps && kbd->key_maps != default_key_maps) {
431  int i;
432  for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
433  if (kbd->key_maps[i]) {
434  SDL_free(kbd->key_maps[i]);
435  }
436  }
437  SDL_free(kbd->key_maps);
438  }
439 
440  SDL_free(kbd);
441 }
442 
443 /*
444  * Helper Functions.
445  */
446 static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
447 {
448  /* c is already part of a UTF-8 sequence and safe to add as a character */
449  if (kbd->text_len < (sizeof(kbd->text)-1)) {
450  kbd->text[kbd->text_len++] = (char)c;
451  }
452 }
453 
454 static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
455 {
456  if (c < 0x80)
457  /* 0******* */
458  put_queue(kbd, c);
459  else if (c < 0x800) {
460  /* 110***** 10****** */
461  put_queue(kbd, 0xc0 | (c >> 6));
462  put_queue(kbd, 0x80 | (c & 0x3f));
463  } else if (c < 0x10000) {
464  if (c >= 0xD800 && c < 0xE000)
465  return;
466  if (c == 0xFFFF)
467  return;
468  /* 1110**** 10****** 10****** */
469  put_queue(kbd, 0xe0 | (c >> 12));
470  put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
471  put_queue(kbd, 0x80 | (c & 0x3f));
472  } else if (c < 0x110000) {
473  /* 11110*** 10****** 10****** 10****** */
474  put_queue(kbd, 0xf0 | (c >> 18));
475  put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
476  put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
477  put_queue(kbd, 0x80 | (c & 0x3f));
478  }
479 }
480 
481 /*
482  * We have a combining character DIACR here, followed by the character CH.
483  * If the combination occurs in the table, return the corresponding value.
484  * Otherwise, if CH is a space or equals DIACR, return DIACR.
485  * Otherwise, conclude that DIACR was not combining after all,
486  * queue it and return CH.
487  */
488 static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
489 {
490  unsigned int d = kbd->diacr;
491  unsigned int i;
492 
493  kbd->diacr = 0;
494 
495  for (i = 0; i < kbd->accents->kb_cnt; i++) {
496  if (kbd->accents->kbdiacr[i].diacr == d &&
497  kbd->accents->kbdiacr[i].base == ch) {
498  return kbd->accents->kbdiacr[i].result;
499  }
500  }
501 
502  if (ch == ' ' || ch == d)
503  return d;
504 
505  put_utf8(kbd, d);
506 
507  return ch;
508 }
509 
510 static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
511 {
512  return (kbd->ledflagstate & flag) != 0;
513 }
514 
515 static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
516 {
517  kbd->ledflagstate |= flag;
518  ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
519 }
520 
521 static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
522 {
523  kbd->ledflagstate &= ~flag;
524  ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
525 }
526 
527 static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
528 {
529  kbd->lockstate ^= 1 << flag;
530 }
531 
532 static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
533 {
534  kbd->slockstate ^= 1 << flag;
535 }
536 
537 static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
538 {
539  kbd->ledflagstate ^= flag;
540  ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
541 }
542 
543 /*
544  * Special function handlers
545  */
546 
547 static void fn_enter(SDL_EVDEV_keyboard_state *kbd)
548 {
549  if (kbd->diacr) {
550  put_utf8(kbd, kbd->diacr);
551  kbd->diacr = 0;
552  }
553 }
554 
555 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd)
556 {
557  if (kbd->rep)
558  return;
559 
560  chg_vc_kbd_led(kbd, K_CAPSLOCK);
561 }
562 
563 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd)
564 {
565  if (kbd->rep)
566  return;
567 
568  set_vc_kbd_led(kbd, K_CAPSLOCK);
569 }
570 
571 static void fn_num(SDL_EVDEV_keyboard_state *kbd)
572 {
573  if (!kbd->rep)
574  chg_vc_kbd_led(kbd, K_NUMLOCK);
575 }
576 
577 static void fn_compose(SDL_EVDEV_keyboard_state *kbd)
578 {
579  kbd->dead_key_next = SDL_TRUE;
580 }
581 
582 /*
583  * Special key handlers
584  */
585 
586 static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
587 {
588 }
589 
590 static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
591 {
592  if (up_flag)
593  return;
594  if (value >= SDL_arraysize(fn_handler))
595  return;
596  if (fn_handler[value])
597  fn_handler[value](kbd);
598 }
599 
600 static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
601 {
602 }
603 
604 static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
605 {
606  if (up_flag)
607  return; /* no action, if this is a key release */
608 
609  if (kbd->diacr)
610  value = handle_diacr(kbd, value);
611 
612  if (kbd->dead_key_next) {
613  kbd->dead_key_next = SDL_FALSE;
614  kbd->diacr = value;
615  return;
616  }
617  put_utf8(kbd, value);
618 }
619 
620 static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
621 {
622  if (up_flag)
623  return;
624 
625  kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
626 }
627 
628 static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
629 {
630  const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
631 
632  k_deadunicode(kbd, ret_diacr[value], up_flag);
633 }
634 
635 static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
636 {
637  k_deadunicode(kbd, value, up_flag);
638 }
639 
640 static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
641 {
642 }
643 
644 static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
645 {
646 }
647 
648 static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
649 {
650 }
651 
652 static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
653 {
654  static const char pad_chars[] = "0123456789+-*/\015,.?()#";
655 
656  if (up_flag)
657  return; /* no action, if this is a key release */
658 
659  if (!vc_kbd_led(kbd, K_NUMLOCK)) {
660  /* unprintable action */
661  return;
662  }
663 
664  put_queue(kbd, pad_chars[value]);
665 }
666 
667 static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
668 {
669  int old_state = kbd->shift_state;
670 
671  if (kbd->rep)
672  return;
673  /*
674  * Mimic typewriter:
675  * a CapsShift key acts like Shift but undoes CapsLock
676  */
677  if (value == KVAL(K_CAPSSHIFT)) {
678  value = KVAL(K_SHIFT);
679  if (!up_flag)
680  clr_vc_kbd_led(kbd, K_CAPSLOCK);
681  }
682 
683  if (up_flag) {
684  /*
685  * handle the case that two shift or control
686  * keys are depressed simultaneously
687  */
688  if (kbd->shift_down[value])
689  kbd->shift_down[value]--;
690  } else
691  kbd->shift_down[value]++;
692 
693  if (kbd->shift_down[value])
694  kbd->shift_state |= (1 << value);
695  else
696  kbd->shift_state &= ~(1 << value);
697 
698  /* kludge */
699  if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
700  put_utf8(kbd, kbd->npadch);
701  kbd->npadch = -1;
702  }
703 }
704 
705 static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
706 {
707 }
708 
709 static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
710 {
711  int base;
712 
713  if (up_flag)
714  return;
715 
716  if (value < 10) {
717  /* decimal input of code, while Alt depressed */
718  base = 10;
719  } else {
720  /* hexadecimal input of code, while AltGr depressed */
721  value -= 10;
722  base = 16;
723  }
724 
725  if (kbd->npadch == -1)
726  kbd->npadch = value;
727  else
728  kbd->npadch = kbd->npadch * base + value;
729 }
730 
731 static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
732 {
733  if (up_flag || kbd->rep)
734  return;
735 
736  chg_vc_kbd_lock(kbd, value);
737 }
738 
739 static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
740 {
741  k_shift(kbd, value, up_flag);
742  if (up_flag || kbd->rep)
743  return;
744 
745  chg_vc_kbd_slock(kbd, value);
746  /* try to make Alt, oops, AltGr and such work */
747  if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
748  kbd->slockstate = 0;
749  chg_vc_kbd_slock(kbd, value);
750  }
751 }
752 
753 static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
754 {
755 }
756 
757 void
758 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
759 {
760  unsigned char shift_final;
761  unsigned char type;
762  unsigned short *key_map;
763  unsigned short keysym;
764 
765  if (!kbd) {
766  return;
767  }
768 
769  kbd->rep = (down == 2);
770 
771  shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
772  key_map = kbd->key_maps[shift_final];
773  if (!key_map) {
774  /* Unsupported shift state (e.g. ctrl = 4, alt = 8), just reset to the default state */
775  kbd->shift_state = 0;
776  kbd->slockstate = 0;
777  kbd->lockstate = 0;
778  return;
779  }
780 
781  if (keycode < NR_KEYS) {
782  keysym = key_map[keycode];
783  } else {
784  return;
785  }
786 
787  type = KTYP(keysym);
788 
789  if (type < 0xf0) {
790  if (down) {
791  put_utf8(kbd, keysym);
792  }
793  } else {
794  type -= 0xf0;
795 
796  /* if type is KT_LETTER then it can be affected by Caps Lock */
797  if (type == KT_LETTER) {
798  type = KT_LATIN;
799 
800  if (vc_kbd_led(kbd, K_CAPSLOCK)) {
801  key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
802  if (key_map) {
803  keysym = key_map[keycode];
804  }
805  }
806  }
807 
808  (*k_handler[type])(kbd, keysym & 0xff, !down);
809 
810  if (type != KT_SLOCK) {
811  kbd->slockstate = 0;
812  }
813  }
814 
815  if (kbd->text_len > 0) {
816  kbd->text[kbd->text_len] = '\0';
817  SDL_SendKeyboardText(kbd->text);
818  kbd->text_len = 0;
819  }
820 }
821 
822 #else /* !SDL_INPUT_LINUXKD */
823 
826 {
827  return NULL;
828 }
829 
830 void
831 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
832 {
833 }
834 
835 void
837 {
838 }
839 
840 #endif /* SDL_INPUT_LINUXKD */
841 
842 /* vi: set ts=4 sw=4 expandtab: */
SDL_evdev_kbd_default_keymap.h
SDL_EVDEV_kbd_keycode
void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
Definition: SDL_evdev_kbd.c:831
NULL
#define NULL
Definition: begin_code.h:167
uint
#define uint
SDL_EVDEV_keyboard_state
struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state
Definition: SDL_evdev_kbd.h:26
c
const GLubyte * c
Definition: SDL_opengl_glext.h:11093
SDL_evdev_kbd_default_accents.h
SDL_SendKeyboardText
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:789
SDL_GetHintBoolean
#define SDL_GetHintBoolean
Definition: SDL_dynapi_overrides.h:608
SDL_EVDEV_kbd_init
SDL_EVDEV_keyboard_state * SDL_EVDEV_kbd_init(void)
Definition: SDL_evdev_kbd.c:825
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
default_key_maps
static unsigned short * default_key_maps[MAX_NR_KEYMAPS]
Definition: SDL_evdev_kbd_default_keymap.h:4377
SDL_FALSE
Definition: SDL_stdinc.h:163
text
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
SDL_EVDEV_kbd_quit
void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
Definition: SDL_evdev_kbd.c:836
SDL_evdev_kbd.h
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
SDL_HINT_NO_SIGNAL_HANDLERS
#define SDL_HINT_NO_SIGNAL_HANDLERS
Tell SDL not to catch the SIGINT or SIGTERM signals.
Definition: SDL_hints.h:923
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:698
j
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
SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_hints.h
default_accents
static struct kbdiacrs default_accents
Definition: SDL_evdev_kbd_default_accents.h:22
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
void
const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char const char const SDL_SCANF_FORMAT_STRING char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
Definition: SDL_dynapi_procs.h:89
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1570
state
struct xkb_state * state
Definition: SDL_waylandsym.h:113
i
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
d
const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char const char const SDL_SCANF_FORMAT_STRING 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
Definition: SDL_dynapi_procs.h:117