src/core/linux/SDL_evdev_kbd.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 18 Aug 2017 20:00:29 -0400
changeset 11323 46861f3fc187
parent 11163 3fe70754ed33
child 11811 5d94cb6b24d3
permissions -rw-r--r--
cmake: added a FIXME for later.

Have to figure out what cmake version fixed this and bump the minimum to that.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 
    25 #ifdef SDL_INPUT_LINUXKD
    26 
    27 /* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source */
    28 
    29 #include <unistd.h>
    30 #include <fcntl.h>
    31 #include <sys/ioctl.h>
    32 #include <linux/kd.h>
    33 #include <linux/keyboard.h>
    34 #include <linux/vt.h>
    35 #include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
    36 
    37 #include "../../events/SDL_events_c.h"
    38 #include "SDL_evdev_kbd_default_accents.h"
    39 #include "SDL_evdev_kbd_default_keymap.h"
    40 
    41 /* These are not defined in older Linux kernel headers */
    42 #ifndef K_UNICODE
    43 #define K_UNICODE 0x03
    44 #endif
    45 #ifndef K_OFF
    46 #define K_OFF 0x04
    47 #endif
    48 
    49 /*
    50  * Handler Tables.
    51  */
    52 
    53 #define K_HANDLERS\
    54     k_self,     k_fn,       k_spec,       k_pad,\
    55     k_dead,     k_cons,     k_cur,        k_shift,\
    56     k_meta,     k_ascii,    k_lock,       k_lowercase,\
    57     k_slock,    k_dead2,    k_brl,        k_ignore
    58 
    59 typedef void (k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag);
    60 static k_handler_fn K_HANDLERS;
    61 static k_handler_fn *k_handler[16] = { K_HANDLERS };
    62 
    63 typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
    64 static void fn_enter(SDL_EVDEV_keyboard_state *kbd);
    65 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd);
    66 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd);
    67 static void fn_num(SDL_EVDEV_keyboard_state *kbd);
    68 static void fn_compose(SDL_EVDEV_keyboard_state *kbd);
    69 
    70 static fn_handler_fn *fn_handler[] =
    71 {
    72     NULL,       fn_enter,   NULL,       NULL,
    73     NULL,       NULL,       NULL,       fn_caps_toggle,
    74     fn_num,     NULL,       NULL,       NULL,
    75     NULL,       fn_caps_on, fn_compose, NULL,
    76     NULL,       NULL,       NULL,       fn_num
    77 };
    78 
    79 
    80 /*
    81  * Keyboard State
    82  */
    83 
    84 struct SDL_EVDEV_keyboard_state
    85 {
    86     int console_fd;
    87     int old_kbd_mode;
    88     unsigned short **key_maps;
    89     unsigned char shift_down[NR_SHIFT];        /* shift state counters.. */
    90     SDL_bool dead_key_next;
    91     int npadch;                    /* -1 or number assembled on pad */
    92     struct kbdiacrs *accents;
    93     unsigned int diacr;
    94     SDL_bool rep;                    /* flag telling character repeat */
    95     unsigned char lockstate;
    96     unsigned char slockstate;
    97     unsigned char ledflagstate;
    98     char shift_state;
    99     char text[128];
   100     unsigned int text_len;
   101 };
   102 
   103 #ifdef DUMP_ACCENTS
   104 static void SDL_EVDEV_dump_accents(SDL_EVDEV_keyboard_state *kbd)
   105 {
   106     unsigned int i;
   107 
   108     printf("static struct kbdiacrs default_accents = {\n");
   109     printf("    %d,\n", kbd->accents->kb_cnt);
   110     printf("    {\n");
   111     for (i = 0; i < kbd->accents->kb_cnt; ++i) {
   112         struct kbdiacr *diacr = &kbd->accents->kbdiacr[i];
   113         printf("        { 0x%.2x, 0x%.2x, 0x%.2x },\n",
   114             diacr->diacr, diacr->base, diacr->result);
   115     }
   116     while (i < 256) {
   117         printf("        { 0x00, 0x00, 0x00 },\n");
   118         ++i;
   119     }
   120     printf("    }\n");
   121     printf("};\n");
   122 }
   123 #endif /* DUMP_ACCENTS */
   124 
   125 #ifdef DUMP_KEYMAP
   126 static void SDL_EVDEV_dump_keymap(SDL_EVDEV_keyboard_state *kbd)
   127 {
   128     int i, j;
   129 
   130     for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
   131         if (kbd->key_maps[i]) {
   132             printf("static unsigned short default_key_map_%d[NR_KEYS] = {", i);
   133             for (j = 0; j < NR_KEYS; ++j) {
   134                 if ((j%8) == 0) {
   135                     printf("\n    ");
   136                 }
   137                 printf("0x%.4x, ", kbd->key_maps[i][j]);
   138             }
   139             printf("\n};\n");
   140         }
   141     }
   142     printf("\n");
   143     printf("static unsigned short *default_key_maps[MAX_NR_KEYMAPS] = {\n");
   144     for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
   145         if (kbd->key_maps[i]) {
   146             printf("    default_key_map_%d,\n", i);
   147         } else {
   148             printf("    NULL,\n");
   149         }
   150     }
   151     printf("};\n");
   152 }
   153 #endif /* DUMP_KEYMAP */
   154 
   155 static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
   156 {
   157     int i, j;
   158 
   159     kbd->key_maps = (unsigned short **)SDL_calloc(MAX_NR_KEYMAPS, sizeof(unsigned short *));
   160     if (!kbd->key_maps) {
   161         return -1;
   162     }
   163 
   164     for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
   165         struct kbentry kbe;
   166 
   167         kbe.kb_table = i;
   168         kbe.kb_index = 0;
   169         if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
   170             return -1;
   171         }
   172 
   173         if (kbe.kb_value == K_NOSUCHMAP) {
   174             continue;
   175         }
   176 
   177         kbd->key_maps[i] = (unsigned short *)SDL_malloc(NR_KEYS * sizeof(unsigned short));
   178         if (!kbd->key_maps[i]) {
   179             return -1;
   180         }
   181 
   182         for (j = 0; j < NR_KEYS; ++j) {
   183             kbe.kb_table = i;
   184             kbe.kb_index = j;
   185             if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
   186                 return -1;
   187             }
   188             kbd->key_maps[i][j] = (kbe.kb_value ^ 0xf000);
   189         }
   190     }
   191     return 0;
   192 }
   193 
   194 SDL_EVDEV_keyboard_state *
   195 SDL_EVDEV_kbd_init(void)
   196 {
   197     SDL_EVDEV_keyboard_state *kbd;
   198     int i;
   199     char flag_state;
   200     char shift_state[2] = {TIOCL_GETSHIFTSTATE, 0};
   201 
   202     kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
   203     if (!kbd) {
   204         return NULL;
   205     }
   206 
   207     kbd->npadch = -1;
   208 
   209     /* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
   210     kbd->console_fd = open("/dev/tty", O_RDONLY);
   211 
   212     if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
   213         kbd->shift_state = *shift_state;
   214     }
   215 
   216     if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
   217         kbd->ledflagstate = flag_state;
   218     }
   219 
   220     kbd->accents = &default_accents;
   221     if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
   222         /* No worries, we'll use the default accent table */
   223     }
   224 
   225     kbd->key_maps = default_key_maps;
   226     if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
   227         /* Set the keyboard in UNICODE mode and load the keymaps */
   228         ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
   229 
   230         if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
   231             for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
   232                 if (kbd->key_maps[i]) {
   233                     SDL_free(kbd->key_maps[i]);
   234                 }
   235             }
   236             SDL_free(kbd->key_maps);
   237 
   238             kbd->key_maps = default_key_maps;
   239         }
   240 
   241         /* Mute the keyboard so keystrokes only generate evdev events
   242          * and do not leak through to the console
   243          */
   244         ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
   245     }
   246 
   247 #ifdef DUMP_ACCENTS
   248     SDL_EVDEV_dump_accents(kbd);
   249 #endif
   250 #ifdef DUMP_KEYMAP
   251     SDL_EVDEV_dump_keymap(kbd);
   252 #endif
   253     return kbd;
   254 }
   255 
   256 void
   257 SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
   258 {
   259     if (!kbd) {
   260         return;
   261     }
   262 
   263     if (kbd->console_fd >= 0) {
   264         /* Restore the original keyboard mode */
   265         ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
   266 
   267         close(kbd->console_fd);
   268         kbd->console_fd = -1;
   269     }
   270 
   271     if (kbd->key_maps && kbd->key_maps != default_key_maps) {
   272         int i;
   273         for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
   274             if (kbd->key_maps[i]) {
   275                 SDL_free(kbd->key_maps[i]);
   276             }
   277         }
   278         SDL_free(kbd->key_maps);
   279     }
   280 
   281     SDL_free(kbd);
   282 }
   283 
   284 /*
   285  * Helper Functions.
   286  */
   287 static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
   288 {
   289     /* c is already part of a UTF-8 sequence and safe to add as a character */
   290     if (kbd->text_len < (sizeof(kbd->text)-1)) {
   291         kbd->text[kbd->text_len++] = (char)c;
   292     }
   293 }
   294 
   295 static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
   296 {
   297     if (c < 0x80)
   298         /*  0******* */
   299         put_queue(kbd, c);
   300     else if (c < 0x800) {
   301         /* 110***** 10****** */
   302         put_queue(kbd, 0xc0 | (c >> 6));
   303         put_queue(kbd, 0x80 | (c & 0x3f));
   304     } else if (c < 0x10000) {
   305         if (c >= 0xD800 && c < 0xE000)
   306             return;
   307         if (c == 0xFFFF)
   308             return;
   309         /* 1110**** 10****** 10****** */
   310         put_queue(kbd, 0xe0 | (c >> 12));
   311         put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
   312         put_queue(kbd, 0x80 | (c & 0x3f));
   313     } else if (c < 0x110000) {
   314         /* 11110*** 10****** 10****** 10****** */
   315         put_queue(kbd, 0xf0 | (c >> 18));
   316         put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
   317         put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
   318         put_queue(kbd, 0x80 | (c & 0x3f));
   319     }
   320 }
   321 
   322 /*
   323  * We have a combining character DIACR here, followed by the character CH.
   324  * If the combination occurs in the table, return the corresponding value.
   325  * Otherwise, if CH is a space or equals DIACR, return DIACR.
   326  * Otherwise, conclude that DIACR was not combining after all,
   327  * queue it and return CH.
   328  */
   329 static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
   330 {
   331     unsigned int d = kbd->diacr;
   332     unsigned int i;
   333 
   334     kbd->diacr = 0;
   335 
   336     for (i = 0; i < kbd->accents->kb_cnt; i++) {
   337         if (kbd->accents->kbdiacr[i].diacr == d &&
   338             kbd->accents->kbdiacr[i].base == ch) {
   339             return kbd->accents->kbdiacr[i].result;
   340         }
   341     }
   342 
   343     if (ch == ' ' || ch == d)
   344         return d;
   345 
   346     put_utf8(kbd, d);
   347 
   348     return ch;
   349 }
   350 
   351 static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
   352 {
   353     return ((kbd->ledflagstate >> flag) & 1);
   354 }
   355 
   356 static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
   357 {
   358     kbd->ledflagstate |= 1 << flag;
   359 }
   360 
   361 static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
   362 {
   363     kbd->ledflagstate &= ~(1 << flag);
   364 }
   365 
   366 static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
   367 {
   368     kbd->lockstate ^= 1 << flag;
   369 }
   370 
   371 static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
   372 {
   373     kbd->slockstate ^= 1 << flag;
   374 }
   375 
   376 static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
   377 {
   378     kbd->ledflagstate ^= 1 << flag;
   379 }
   380 
   381 /*
   382  * Special function handlers
   383  */
   384 
   385 static void fn_enter(SDL_EVDEV_keyboard_state *kbd)
   386 {
   387     if (kbd->diacr) {
   388         put_utf8(kbd, kbd->diacr);
   389         kbd->diacr = 0;
   390     }
   391 }
   392 
   393 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd)
   394 {
   395     if (kbd->rep)
   396         return;
   397 
   398     chg_vc_kbd_led(kbd, K_CAPSLOCK);
   399 }
   400 
   401 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd)
   402 {
   403     if (kbd->rep)
   404         return;
   405 
   406     set_vc_kbd_led(kbd, K_CAPSLOCK);
   407 }
   408 
   409 static void fn_num(SDL_EVDEV_keyboard_state *kbd)
   410 {
   411     if (!kbd->rep)
   412         chg_vc_kbd_led(kbd, K_NUMLOCK);
   413 }
   414 
   415 static void fn_compose(SDL_EVDEV_keyboard_state *kbd)
   416 {
   417     kbd->dead_key_next = SDL_TRUE;
   418 }
   419 
   420 /*
   421  * Special key handlers
   422  */
   423 
   424 static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   425 {
   426 }
   427 
   428 static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   429 {
   430     if (up_flag)
   431         return;
   432     if (value >= SDL_arraysize(fn_handler))
   433         return;
   434     if (fn_handler[value])
   435         fn_handler[value](kbd);
   436 }
   437 
   438 static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   439 {
   440 }
   441 
   442 static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   443 {
   444     if (up_flag)
   445         return;        /* no action, if this is a key release */
   446 
   447     if (kbd->diacr)
   448         value = handle_diacr(kbd, value);
   449 
   450     if (kbd->dead_key_next) {
   451         kbd->dead_key_next = SDL_FALSE;
   452         kbd->diacr = value;
   453         return;
   454     }
   455     put_utf8(kbd, value);
   456 }
   457 
   458 static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
   459 {
   460     if (up_flag)
   461         return;
   462 
   463     kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
   464 }
   465 
   466 static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   467 {
   468     const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
   469 
   470     k_deadunicode(kbd, ret_diacr[value], up_flag);
   471 }
   472 
   473 static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   474 {
   475     k_deadunicode(kbd, value, up_flag);
   476 }
   477 
   478 static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   479 {
   480 }
   481 
   482 static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   483 {
   484 }
   485 
   486 static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   487 {
   488 }
   489 
   490 static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   491 {
   492     static const char pad_chars[] = "0123456789+-*/\015,.?()#";
   493 
   494     if (up_flag)
   495         return;        /* no action, if this is a key release */
   496 
   497     if (!vc_kbd_led(kbd, K_NUMLOCK)) {
   498         /* unprintable action */
   499         return;
   500     }
   501 
   502     put_queue(kbd, pad_chars[value]);
   503 }
   504 
   505 static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   506 {
   507     int old_state = kbd->shift_state;
   508 
   509     if (kbd->rep)
   510         return;
   511     /*
   512      * Mimic typewriter:
   513      * a CapsShift key acts like Shift but undoes CapsLock
   514      */
   515     if (value == KVAL(K_CAPSSHIFT)) {
   516         value = KVAL(K_SHIFT);
   517         if (!up_flag)
   518             clr_vc_kbd_led(kbd, K_CAPSLOCK);
   519     }
   520 
   521     if (up_flag) {
   522         /*
   523          * handle the case that two shift or control
   524          * keys are depressed simultaneously
   525          */
   526         if (kbd->shift_down[value])
   527             kbd->shift_down[value]--;
   528     } else
   529         kbd->shift_down[value]++;
   530 
   531     if (kbd->shift_down[value])
   532         kbd->shift_state |= (1 << value);
   533     else
   534         kbd->shift_state &= ~(1 << value);
   535 
   536     /* kludge */
   537     if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
   538         put_utf8(kbd, kbd->npadch);
   539         kbd->npadch = -1;
   540     }
   541 }
   542 
   543 static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   544 {
   545 }
   546 
   547 static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   548 {
   549     int base;
   550 
   551     if (up_flag)
   552         return;
   553 
   554     if (value < 10) {
   555         /* decimal input of code, while Alt depressed */
   556         base = 10;
   557     } else {
   558         /* hexadecimal input of code, while AltGr depressed */
   559         value -= 10;
   560         base = 16;
   561     }
   562 
   563     if (kbd->npadch == -1)
   564         kbd->npadch = value;
   565     else
   566         kbd->npadch = kbd->npadch * base + value;
   567 }
   568 
   569 static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   570 {
   571     if (up_flag || kbd->rep)
   572         return;
   573 
   574     chg_vc_kbd_lock(kbd, value);
   575 }
   576 
   577 static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   578 {
   579     k_shift(kbd, value, up_flag);
   580     if (up_flag || kbd->rep)
   581         return;
   582 
   583     chg_vc_kbd_slock(kbd, value);
   584     /* try to make Alt, oops, AltGr and such work */
   585     if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
   586         kbd->slockstate = 0;
   587         chg_vc_kbd_slock(kbd, value);
   588     }
   589 }
   590 
   591 static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
   592 {
   593 }
   594 
   595 void
   596 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
   597 {
   598     unsigned char shift_final;
   599     unsigned char type;
   600     unsigned short *key_map;
   601     unsigned short keysym;
   602 
   603     if (!kbd) {
   604         return;
   605     }
   606 
   607     kbd->rep = (down == 2);
   608 
   609     shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
   610     key_map = kbd->key_maps[shift_final];
   611     if (!key_map) {
   612         kbd->slockstate = 0;
   613         return;
   614     }
   615 
   616     if (keycode < NR_KEYS) {
   617         keysym = key_map[keycode];
   618     } else {
   619         return;
   620     }
   621 
   622     type = KTYP(keysym);
   623 
   624     if (type < 0xf0) {
   625         if (down) {
   626             put_utf8(kbd, keysym);
   627         }
   628     } else {
   629         type -= 0xf0;
   630 
   631         /* if type is KT_LETTER then it can be affected by Caps Lock */
   632         if (type == KT_LETTER) {
   633             type = KT_LATIN;
   634 
   635             if (vc_kbd_led(kbd, K_CAPSLOCK)) {
   636                 key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
   637                 if (key_map) {
   638                     keysym = key_map[keycode];
   639                 }
   640             }
   641         }
   642 
   643         (*k_handler[type])(kbd, keysym & 0xff, !down);
   644 
   645         if (type != KT_SLOCK) {
   646             kbd->slockstate = 0;
   647         }
   648     }
   649 
   650     if (kbd->text_len > 0) {
   651         kbd->text[kbd->text_len] = '\0';
   652         SDL_SendKeyboardText(kbd->text);
   653         kbd->text_len = 0;
   654     }
   655 }
   656 
   657 #else /* !SDL_INPUT_LINUXKD */
   658 
   659 SDL_EVDEV_keyboard_state *
   660 SDL_EVDEV_kbd_init(void)
   661 {
   662     return NULL;
   663 }
   664 
   665 void
   666 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
   667 {
   668 }
   669 
   670 void
   671 SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
   672 {
   673 }
   674 
   675 #endif /* SDL_INPUT_LINUXKD */
   676 
   677 /* vi: set ts=4 sw=4 expandtab: */