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 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
223 SDL_EVDEV_kbd_reraise_signal(
int sig)
228 siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo =
NULL;
229 void* SDL_EVDEV_kdb_cleanup_ucontext =
NULL;
231 static void kbd_cleanup_signal_action(
int signum, siginfo_t* info,
void* ucontext)
233 struct sigaction* old_action_p = &(old_sigaction[signum]);
237 sigaction(signum, old_action_p,
NULL);
240 sigemptyset(&sigset);
241 sigaddset(&sigset, signum);
242 sigprocmask(SIG_UNBLOCK, &sigset,
NULL);
245 SDL_EVDEV_kdb_cleanup_siginfo = info;
246 SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
252 SDL_EVDEV_kbd_reraise_signal(signum);
255 static void kbd_unregister_emerg_cleanup()
259 kbd_cleanup_state =
NULL;
261 if (!kbd_cleanup_sigactions_installed) {
264 kbd_cleanup_sigactions_installed = 0;
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]);
273 if (sigaction(signum,
NULL, &cur_action))
277 if (!(cur_action.sa_flags & SA_SIGINFO)
278 || cur_action.sa_sigaction != &kbd_cleanup_signal_action)
282 sigaction(signum, old_action_p,
NULL);
286 static void kbd_cleanup_atexit(
void)
292 kbd_unregister_emerg_cleanup();
299 if (kbd_cleanup_state !=
NULL) {
302 kbd_cleanup_state = kbd;
304 if (!kbd_cleanup_atexit_installed) {
309 atexit(kbd_cleanup_atexit);
310 kbd_cleanup_atexit_installed = 1;
313 if (kbd_cleanup_sigactions_installed) {
316 kbd_cleanup_sigactions_installed = 1;
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))
329 if ((signum == SIGHUP || signum == SIGPIPE)
330 && (old_action_p->sa_handler != SIG_DFL
331 || (
void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
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);
347 char shift_state[
sizeof (long) ] = {TIOCL_GETSHIFTSTATE, 0};
357 kbd->console_fd = open(
"/dev/tty", O_RDONLY);
359 if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
360 kbd->shift_state = *shift_state;
363 if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
364 kbd->ledflagstate = flag_state;
368 if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
373 if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
375 ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
377 if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
378 for (
i = 0;
i < MAX_NR_KEYMAPS; ++
i) {
379 if (kbd->key_maps[
i]) {
389 if (getenv(
"SDL_INPUT_LINUX_KEEP_KBD") ==
NULL) {
393 ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
399 kbd_register_emerg_cleanup(kbd);
405 SDL_EVDEV_dump_accents(kbd);
408 SDL_EVDEV_dump_keymap(kbd);
420 kbd_unregister_emerg_cleanup();
422 if (kbd->console_fd >= 0) {
424 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
426 close(kbd->console_fd);
427 kbd->console_fd = -1;
432 for (
i = 0;
i < MAX_NR_KEYMAPS; ++
i) {
433 if (kbd->key_maps[
i]) {
449 if (kbd->text_len < (
sizeof(kbd->text)-1)) {
450 kbd->text[kbd->text_len++] = (char)
c;
459 else if (
c < 0x800) {
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)
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) {
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));
490 unsigned int d = kbd->diacr;
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;
502 if (ch ==
' ' || ch ==
d)
512 return (kbd->ledflagstate & flag) != 0;
517 kbd->ledflagstate |= flag;
518 ioctl(kbd->console_fd, KDSETLED, (
unsigned long)(kbd->ledflagstate));
523 kbd->ledflagstate &= ~flag;
524 ioctl(kbd->console_fd, KDSETLED, (
unsigned long)(kbd->ledflagstate));
529 kbd->lockstate ^= 1 << flag;
534 kbd->slockstate ^= 1 << flag;
539 kbd->ledflagstate ^= flag;
540 ioctl(kbd->console_fd, KDSETLED, (
unsigned long)(kbd->ledflagstate));
550 put_utf8(kbd, kbd->diacr);
560 chg_vc_kbd_led(kbd, K_CAPSLOCK);
568 set_vc_kbd_led(kbd, K_CAPSLOCK);
574 chg_vc_kbd_led(kbd, K_NUMLOCK);
596 if (fn_handler[
value])
597 fn_handler[
value](kbd);
612 if (kbd->dead_key_next) {
617 put_utf8(kbd,
value);
625 kbd->diacr = (kbd->diacr ? handle_diacr(kbd,
value) :
value);
630 const unsigned char ret_diacr[NR_DEAD] = {
'`',
'\'',
'^',
'~',
'"',
',' };
632 k_deadunicode(kbd, ret_diacr[
value], up_flag);
637 k_deadunicode(kbd,
value, up_flag);
654 static const char pad_chars[] =
"0123456789+-*/\015,.?()#";
659 if (!vc_kbd_led(kbd, K_NUMLOCK)) {
664 put_queue(kbd, pad_chars[
value]);
669 int old_state = kbd->shift_state;
677 if (
value == KVAL(K_CAPSSHIFT)) {
678 value = KVAL(K_SHIFT);
680 clr_vc_kbd_led(kbd, K_CAPSLOCK);
688 if (kbd->shift_down[
value])
689 kbd->shift_down[
value]--;
691 kbd->shift_down[
value]++;
693 if (kbd->shift_down[
value])
694 kbd->shift_state |= (1 <<
value);
696 kbd->shift_state &= ~(1 <<
value);
699 if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
700 put_utf8(kbd, kbd->npadch);
725 if (kbd->npadch == -1)
728 kbd->npadch = kbd->npadch *
base +
value;
733 if (up_flag || kbd->rep)
736 chg_vc_kbd_lock(kbd,
value);
741 k_shift(kbd,
value, up_flag);
742 if (up_flag || kbd->rep)
745 chg_vc_kbd_slock(kbd,
value);
747 if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
749 chg_vc_kbd_slock(kbd,
value);
760 unsigned char shift_final;
762 unsigned short *key_map;
763 unsigned short keysym;
769 kbd->rep = (down == 2);
771 shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
772 key_map = kbd->key_maps[shift_final];
775 kbd->shift_state = 0;
781 if (keycode < NR_KEYS) {
782 keysym = key_map[keycode];
791 put_utf8(kbd, keysym);
797 if (
type == KT_LETTER) {
800 if (vc_kbd_led(kbd, K_CAPSLOCK)) {
801 key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
803 keysym = key_map[keycode];
808 (*k_handler[
type])(kbd, keysym & 0xff, !down);
810 if (
type != KT_SLOCK) {
815 if (kbd->text_len > 0) {
816 kbd->text[kbd->text_len] =
'\0';