sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_evdev_kbd.c (22134B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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"
     41 #include "SDL_evdev_kbd_default_accents.h"
     42 #include "SDL_evdev_kbd_default_keymap.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 
     87 struct SDL_EVDEV_keyboard_state
     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 
    341 SDL_EVDEV_keyboard_state *
    342 SDL_EVDEV_kbd_init(void)
    343 {
    344     SDL_EVDEV_keyboard_state *kbd;
    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              */
    398             if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
    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
    414 SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
    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 #elif !defined(SDL_INPUT_FBSDKBIO) /* !SDL_INPUT_LINUXKD */
    823 
    824 SDL_EVDEV_keyboard_state *
    825 SDL_EVDEV_kbd_init(void)
    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
    836 SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
    837 {
    838 }
    839 
    840 #endif /* SDL_INPUT_LINUXKD */
    841 
    842 /* vi: set ts=4 sw=4 expandtab: */