21 #include "../../SDL_internal.h"
26 #ifdef SDL_INPUT_LINUXKD
32 #include <sys/ioctl.h>
34 #include <linux/keyboard.h>
36 #include <linux/tiocl.h>
40 #include "../../events/SDL_events_c.h"
46 #define K_UNICODE 0x03
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
63 static k_handler_fn K_HANDLERS;
64 static k_handler_fn *k_handler[16] = { K_HANDLERS };
73 static fn_handler_fn *fn_handler[] =
91 unsigned short **key_maps;
92 unsigned char shift_down[NR_SHIFT];
95 struct kbdiacrs *accents;
98 unsigned char lockstate;
99 unsigned char slockstate;
100 unsigned char ledflagstate;
103 unsigned int text_len;
111 printf(
"static struct kbdiacrs default_accents = {\n");
112 printf(
" %d,\n", kbd->accents->kb_cnt);
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);
120 printf(
" { 0x00, 0x00, 0x00 },\n");
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) {
140 printf(
"0x%.4x, ", kbd->key_maps[
i][
j]);
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);
162 kbd->key_maps = (
unsigned short **)
SDL_calloc(MAX_NR_KEYMAPS,
sizeof(
unsigned short *));
163 if (!kbd->key_maps) {
167 for (
i = 0;
i < MAX_NR_KEYMAPS; ++
i) {
172 if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
176 if (kbe.kb_value == K_NOSUCHMAP) {
180 kbd->key_maps[
i] = (
unsigned short *)
SDL_malloc(NR_KEYS *
sizeof(
unsigned short));
181 if (!kbd->key_maps[
i]) {
185 for (
j = 0;
j < NR_KEYS; ++
j) {
188 if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
191 kbd->key_maps[
i][
j] = (kbe.kb_value ^ 0xf000);
198 static int kbd_cleanup_sigactions_installed = 0;
199 static int kbd_cleanup_atexit_installed = 0;
201 static struct sigaction old_sigaction[NSIG];
203 static int fatal_signals[] =
206 SIGHUP, SIGQUIT, SIGILL, SIGABRT,
207 SIGFPE, SIGSEGV, SIGPIPE, SIGBUS,
211 static void kbd_cleanup(
void)
217 kbd_cleanup_state =
NULL;
219 fprintf(stderr,
"(SDL restoring keyboard) ");
220 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
224 SDL_EVDEV_kbd_reraise_signal(
int sig)
229 siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo =
NULL;
230 void* SDL_EVDEV_kdb_cleanup_ucontext =
NULL;
232 static void kbd_cleanup_signal_action(
int signum, siginfo_t* info,
void* ucontext)
234 struct sigaction* old_action_p = &(old_sigaction[signum]);
238 sigaction(signum, old_action_p,
NULL);
241 sigemptyset(&sigset);
242 sigaddset(&sigset, signum);
243 sigprocmask(SIG_UNBLOCK, &sigset,
NULL);
246 SDL_EVDEV_kdb_cleanup_siginfo = info;
247 SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
253 SDL_EVDEV_kbd_reraise_signal(signum);
256 static void kbd_unregister_emerg_cleanup()
260 kbd_cleanup_state =
NULL;
262 if (!kbd_cleanup_sigactions_installed) {
265 kbd_cleanup_sigactions_installed = 0;
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]);
274 if (sigaction(signum,
NULL, &cur_action))
278 if (!(cur_action.sa_flags & SA_SIGINFO)
279 || cur_action.sa_sigaction != &kbd_cleanup_signal_action)
283 sigaction(signum, old_action_p,
NULL);
287 static void kbd_cleanup_atexit(
void)
293 kbd_unregister_emerg_cleanup();
300 if (kbd_cleanup_state !=
NULL) {
303 kbd_cleanup_state = kbd;
305 if (!kbd_cleanup_atexit_installed) {
310 atexit(kbd_cleanup_atexit);
311 kbd_cleanup_atexit_installed = 1;
314 if (kbd_cleanup_sigactions_installed) {
317 kbd_cleanup_sigactions_installed = 1;
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))
330 if ((signum == SIGHUP || signum == SIGPIPE)
331 && (old_action_p->sa_handler != SIG_DFL
332 || (
void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
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);
348 char shift_state[2] = {TIOCL_GETSHIFTSTATE, 0};
358 kbd->console_fd = open(
"/dev/tty", O_RDONLY);
360 if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
361 kbd->shift_state = *shift_state;
364 if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
365 kbd->ledflagstate = flag_state;
369 if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
374 if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
376 ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
378 if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
379 for (
i = 0;
i < MAX_NR_KEYMAPS; ++
i) {
380 if (kbd->key_maps[
i]) {
390 if (getenv(
"SDL_INPUT_LINUX_KEEP_KBD") ==
NULL) {
394 ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
400 kbd_register_emerg_cleanup(kbd);
406 SDL_EVDEV_dump_accents(kbd);
409 SDL_EVDEV_dump_keymap(kbd);
421 kbd_unregister_emerg_cleanup();
423 if (kbd->console_fd >= 0) {
425 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
427 close(kbd->console_fd);
428 kbd->console_fd = -1;
433 for (
i = 0;
i < MAX_NR_KEYMAPS; ++
i) {
434 if (kbd->key_maps[
i]) {
450 if (kbd->text_len < (
sizeof(kbd->text)-1)) {
451 kbd->text[kbd->text_len++] = (char)
c;
460 else if (
c < 0x800) {
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)
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) {
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));
491 unsigned int d = kbd->diacr;
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;
503 if (ch ==
' ' || ch ==
d)
513 return ((kbd->ledflagstate >> flag) & 1);
518 kbd->ledflagstate |= 1 << flag;
523 kbd->ledflagstate &= ~(1 << flag);
528 kbd->lockstate ^= 1 << flag;
533 kbd->slockstate ^= 1 << flag;
538 kbd->ledflagstate ^= 1 << flag;
548 put_utf8(kbd, kbd->diacr);
558 chg_vc_kbd_led(kbd, K_CAPSLOCK);
566 set_vc_kbd_led(kbd, K_CAPSLOCK);
572 chg_vc_kbd_led(kbd, K_NUMLOCK);
594 if (fn_handler[
value])
595 fn_handler[
value](kbd);
610 if (kbd->dead_key_next) {
615 put_utf8(kbd,
value);
623 kbd->diacr = (kbd->diacr ? handle_diacr(kbd,
value) :
value);
628 const unsigned char ret_diacr[NR_DEAD] = {
'`',
'\'',
'^',
'~',
'"',
',' };
630 k_deadunicode(kbd, ret_diacr[
value], up_flag);
635 k_deadunicode(kbd,
value, up_flag);
652 static const char pad_chars[] =
"0123456789+-*/\015,.?()#";
657 if (!vc_kbd_led(kbd, K_NUMLOCK)) {
662 put_queue(kbd, pad_chars[
value]);
667 int old_state = kbd->shift_state;
675 if (
value == KVAL(K_CAPSSHIFT)) {
676 value = KVAL(K_SHIFT);
678 clr_vc_kbd_led(kbd, K_CAPSLOCK);
686 if (kbd->shift_down[
value])
687 kbd->shift_down[
value]--;
689 kbd->shift_down[
value]++;
691 if (kbd->shift_down[
value])
692 kbd->shift_state |= (1 <<
value);
694 kbd->shift_state &= ~(1 <<
value);
697 if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
698 put_utf8(kbd, kbd->npadch);
723 if (kbd->npadch == -1)
726 kbd->npadch = kbd->npadch * base +
value;
731 if (up_flag || kbd->rep)
734 chg_vc_kbd_lock(kbd,
value);
739 k_shift(kbd,
value, up_flag);
740 if (up_flag || kbd->rep)
743 chg_vc_kbd_slock(kbd,
value);
745 if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
747 chg_vc_kbd_slock(kbd,
value);
758 unsigned char shift_final;
760 unsigned short *key_map;
761 unsigned short keysym;
767 kbd->rep = (down == 2);
769 shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
770 key_map = kbd->key_maps[shift_final];
773 kbd->shift_state = 0;
779 if (keycode < NR_KEYS) {
780 keysym = key_map[keycode];
789 put_utf8(kbd, keysym);
795 if (
type == KT_LETTER) {
798 if (vc_kbd_led(kbd, K_CAPSLOCK)) {
799 key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
801 keysym = key_map[keycode];
806 (*k_handler[
type])(kbd, keysym & 0xff, !down);
808 if (
type != KT_SLOCK) {
813 if (kbd->text_len > 0) {
814 kbd->text[kbd->text_len] =
'\0';