cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_evdev.c (33428B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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#ifdef SDL_INPUT_LINUXEV
     24
     25/* This is based on the linux joystick driver */
     26/* References: https://www.kernel.org/doc/Documentation/input/input.txt 
     27 *             https://www.kernel.org/doc/Documentation/input/event-codes.txt
     28 *             /usr/include/linux/input.h
     29 *             The evtest application is also useful to debug the protocol
     30 */
     31
     32
     33#include "SDL_evdev.h"
     34#define _THIS SDL_EVDEV_PrivateData *_this
     35static _THIS = NULL;
     36
     37#include <sys/stat.h>
     38#include <unistd.h>
     39#include <fcntl.h>
     40#include <sys/ioctl.h>
     41#include <limits.h>             /* For the definition of PATH_MAX */
     42#include <linux/input.h>
     43#ifdef SDL_INPUT_LINUXKD
     44#include <linux/kd.h>
     45#include <linux/keyboard.h>
     46#endif
     47
     48
     49/* We need this to prevent keystrokes from appear in the console */
     50#ifndef KDSKBMUTE
     51#define KDSKBMUTE 0x4B51
     52#endif
     53#ifndef KDSKBMODE
     54#define KDSKBMODE 0x4B45
     55#endif
     56#ifndef K_OFF
     57#define K_OFF 0x04
     58#endif
     59
     60#include "SDL.h"
     61#include "SDL_assert.h"
     62#include "SDL_endian.h"
     63#include "../../core/linux/SDL_udev.h"
     64#include "SDL_scancode.h"
     65#include "../../events/SDL_events_c.h"
     66
     67/* This isn't defined in older Linux kernel headers */
     68#ifndef SYN_DROPPED
     69#define SYN_DROPPED 3
     70#endif
     71
     72static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
     73static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
     74static int SDL_EVDEV_device_removed(const char *devpath);
     75
     76#if SDL_USE_LIBUDEV
     77static int SDL_EVDEV_device_added(const char *devpath);
     78void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
     79#endif /* SDL_USE_LIBUDEV */
     80
     81static SDL_Scancode EVDEV_Keycodes[] = {
     82    SDL_SCANCODE_UNKNOWN,       /*  KEY_RESERVED        0 */
     83    SDL_SCANCODE_ESCAPE,        /*  KEY_ESC         1 */
     84    SDL_SCANCODE_1,             /*  KEY_1           2 */
     85    SDL_SCANCODE_2,             /*  KEY_2           3 */
     86    SDL_SCANCODE_3,             /*  KEY_3           4 */
     87    SDL_SCANCODE_4,             /*  KEY_4           5 */
     88    SDL_SCANCODE_5,             /*  KEY_5           6 */
     89    SDL_SCANCODE_6,             /*  KEY_6           7 */
     90    SDL_SCANCODE_7,             /*  KEY_7           8 */
     91    SDL_SCANCODE_8,             /*  KEY_8           9 */
     92    SDL_SCANCODE_9,             /*  KEY_9           10 */
     93    SDL_SCANCODE_0,             /*  KEY_0           11 */
     94    SDL_SCANCODE_MINUS,         /*  KEY_MINUS       12 */
     95    SDL_SCANCODE_EQUALS,        /*  KEY_EQUAL       13 */
     96    SDL_SCANCODE_BACKSPACE,     /*  KEY_BACKSPACE       14 */
     97    SDL_SCANCODE_TAB,           /*  KEY_TAB         15 */
     98    SDL_SCANCODE_Q,             /*  KEY_Q           16 */
     99    SDL_SCANCODE_W,             /*  KEY_W           17 */
    100    SDL_SCANCODE_E,             /*  KEY_E           18 */
    101    SDL_SCANCODE_R,             /*  KEY_R           19 */
    102    SDL_SCANCODE_T,             /*  KEY_T           20 */
    103    SDL_SCANCODE_Y,             /*  KEY_Y           21 */
    104    SDL_SCANCODE_U,             /*  KEY_U           22 */
    105    SDL_SCANCODE_I,             /*  KEY_I           23 */
    106    SDL_SCANCODE_O,             /*  KEY_O           24 */
    107    SDL_SCANCODE_P,             /*  KEY_P           25 */
    108    SDL_SCANCODE_LEFTBRACKET,   /*  KEY_LEFTBRACE       26 */
    109    SDL_SCANCODE_RIGHTBRACKET,  /*  KEY_RIGHTBRACE      27 */
    110    SDL_SCANCODE_RETURN,        /*  KEY_ENTER       28 */
    111    SDL_SCANCODE_LCTRL,         /*  KEY_LEFTCTRL        29 */
    112    SDL_SCANCODE_A,             /*  KEY_A           30 */
    113    SDL_SCANCODE_S,             /*  KEY_S           31 */
    114    SDL_SCANCODE_D,             /*  KEY_D           32 */
    115    SDL_SCANCODE_F,             /*  KEY_F           33 */
    116    SDL_SCANCODE_G,             /*  KEY_G           34 */
    117    SDL_SCANCODE_H,             /*  KEY_H           35 */
    118    SDL_SCANCODE_J,             /*  KEY_J           36 */
    119    SDL_SCANCODE_K,             /*  KEY_K           37 */
    120    SDL_SCANCODE_L,             /*  KEY_L           38 */
    121    SDL_SCANCODE_SEMICOLON,     /*  KEY_SEMICOLON       39 */
    122    SDL_SCANCODE_APOSTROPHE,    /*  KEY_APOSTROPHE      40 */
    123    SDL_SCANCODE_GRAVE,         /*  KEY_GRAVE       41 */
    124    SDL_SCANCODE_LSHIFT,        /*  KEY_LEFTSHIFT       42 */
    125    SDL_SCANCODE_BACKSLASH,     /*  KEY_BACKSLASH       43 */
    126    SDL_SCANCODE_Z,             /*  KEY_Z           44 */
    127    SDL_SCANCODE_X,             /*  KEY_X           45 */
    128    SDL_SCANCODE_C,             /*  KEY_C           46 */
    129    SDL_SCANCODE_V,             /*  KEY_V           47 */
    130    SDL_SCANCODE_B,             /*  KEY_B           48 */
    131    SDL_SCANCODE_N,             /*  KEY_N           49 */
    132    SDL_SCANCODE_M,             /*  KEY_M           50 */
    133    SDL_SCANCODE_COMMA,         /*  KEY_COMMA       51 */
    134    SDL_SCANCODE_PERIOD,        /*  KEY_DOT         52 */
    135    SDL_SCANCODE_SLASH,         /*  KEY_SLASH       53 */
    136    SDL_SCANCODE_RSHIFT,        /*  KEY_RIGHTSHIFT      54 */
    137    SDL_SCANCODE_KP_MULTIPLY,   /*  KEY_KPASTERISK      55 */
    138    SDL_SCANCODE_LALT,          /*  KEY_LEFTALT     56 */
    139    SDL_SCANCODE_SPACE,         /*  KEY_SPACE       57 */
    140    SDL_SCANCODE_CAPSLOCK,      /*  KEY_CAPSLOCK        58 */
    141    SDL_SCANCODE_F1,            /*  KEY_F1          59 */
    142    SDL_SCANCODE_F2,            /*  KEY_F2          60 */
    143    SDL_SCANCODE_F3,            /*  KEY_F3          61 */
    144    SDL_SCANCODE_F4,            /*  KEY_F4          62 */
    145    SDL_SCANCODE_F5,            /*  KEY_F5          63 */
    146    SDL_SCANCODE_F6,            /*  KEY_F6          64 */
    147    SDL_SCANCODE_F7,            /*  KEY_F7          65 */
    148    SDL_SCANCODE_F8,            /*  KEY_F8          66 */
    149    SDL_SCANCODE_F9,            /*  KEY_F9          67 */
    150    SDL_SCANCODE_F10,           /*  KEY_F10         68 */
    151    SDL_SCANCODE_NUMLOCKCLEAR,  /*  KEY_NUMLOCK     69 */
    152    SDL_SCANCODE_SCROLLLOCK,    /*  KEY_SCROLLLOCK      70 */
    153    SDL_SCANCODE_KP_7,          /*  KEY_KP7         71 */
    154    SDL_SCANCODE_KP_8,          /*  KEY_KP8         72 */
    155    SDL_SCANCODE_KP_9,          /*  KEY_KP9         73 */
    156    SDL_SCANCODE_KP_MINUS,      /*  KEY_KPMINUS     74 */
    157    SDL_SCANCODE_KP_4,          /*  KEY_KP4         75 */
    158    SDL_SCANCODE_KP_5,          /*  KEY_KP5         76 */
    159    SDL_SCANCODE_KP_6,          /*  KEY_KP6         77 */
    160    SDL_SCANCODE_KP_PLUS,       /*  KEY_KPPLUS      78 */
    161    SDL_SCANCODE_KP_1,          /*  KEY_KP1         79 */
    162    SDL_SCANCODE_KP_2,          /*  KEY_KP2         80 */
    163    SDL_SCANCODE_KP_3,          /*  KEY_KP3         81 */
    164    SDL_SCANCODE_KP_0,          /*  KEY_KP0         82 */
    165    SDL_SCANCODE_KP_PERIOD,     /*  KEY_KPDOT       83 */
    166    SDL_SCANCODE_UNKNOWN,       /*  84 */
    167    SDL_SCANCODE_LANG5,         /*  KEY_ZENKAKUHANKAKU  85 */
    168    SDL_SCANCODE_UNKNOWN,       /*  KEY_102ND       86 */
    169    SDL_SCANCODE_F11,           /*  KEY_F11         87 */
    170    SDL_SCANCODE_F12,           /*  KEY_F12         88 */
    171    SDL_SCANCODE_UNKNOWN,       /*  KEY_RO          89 */
    172    SDL_SCANCODE_LANG3,         /*  KEY_KATAKANA        90 */
    173    SDL_SCANCODE_LANG4,         /*  KEY_HIRAGANA        91 */
    174    SDL_SCANCODE_UNKNOWN,       /*  KEY_HENKAN      92 */
    175    SDL_SCANCODE_LANG3,         /*  KEY_KATAKANAHIRAGANA    93 */
    176    SDL_SCANCODE_UNKNOWN,       /*  KEY_MUHENKAN        94 */
    177    SDL_SCANCODE_KP_COMMA,      /*  KEY_KPJPCOMMA       95 */
    178    SDL_SCANCODE_KP_ENTER,      /*  KEY_KPENTER     96 */
    179    SDL_SCANCODE_RCTRL,         /*  KEY_RIGHTCTRL       97 */
    180    SDL_SCANCODE_KP_DIVIDE,     /*  KEY_KPSLASH     98 */
    181    SDL_SCANCODE_SYSREQ,        /*  KEY_SYSRQ       99 */
    182    SDL_SCANCODE_RALT,          /*  KEY_RIGHTALT        100 */
    183    SDL_SCANCODE_UNKNOWN,       /*  KEY_LINEFEED        101 */
    184    SDL_SCANCODE_HOME,          /*  KEY_HOME        102 */
    185    SDL_SCANCODE_UP,            /*  KEY_UP          103 */
    186    SDL_SCANCODE_PAGEUP,        /*  KEY_PAGEUP      104 */
    187    SDL_SCANCODE_LEFT,          /*  KEY_LEFT        105 */
    188    SDL_SCANCODE_RIGHT,         /*  KEY_RIGHT       106 */
    189    SDL_SCANCODE_END,           /*  KEY_END         107 */
    190    SDL_SCANCODE_DOWN,          /*  KEY_DOWN        108 */
    191    SDL_SCANCODE_PAGEDOWN,      /*  KEY_PAGEDOWN        109 */
    192    SDL_SCANCODE_INSERT,        /*  KEY_INSERT      110 */
    193    SDL_SCANCODE_DELETE,        /*  KEY_DELETE      111 */
    194    SDL_SCANCODE_UNKNOWN,       /*  KEY_MACRO       112 */
    195    SDL_SCANCODE_MUTE,          /*  KEY_MUTE        113 */
    196    SDL_SCANCODE_VOLUMEDOWN,    /*  KEY_VOLUMEDOWN      114 */
    197    SDL_SCANCODE_VOLUMEUP,      /*  KEY_VOLUMEUP        115 */
    198    SDL_SCANCODE_POWER,         /*  KEY_POWER       116 SC System Power Down */
    199    SDL_SCANCODE_KP_EQUALS,     /*  KEY_KPEQUAL     117 */
    200    SDL_SCANCODE_KP_MINUS,      /*  KEY_KPPLUSMINUS     118 */
    201    SDL_SCANCODE_PAUSE,         /*  KEY_PAUSE       119 */
    202    SDL_SCANCODE_UNKNOWN,       /*  KEY_SCALE       120 AL Compiz Scale (Expose) */
    203    SDL_SCANCODE_KP_COMMA,      /*  KEY_KPCOMMA     121 */
    204    SDL_SCANCODE_LANG1,         /*  KEY_HANGEUL,KEY_HANGUEL 122 */
    205    SDL_SCANCODE_LANG2,         /*  KEY_HANJA       123 */
    206    SDL_SCANCODE_INTERNATIONAL3,/*  KEY_YEN         124 */
    207    SDL_SCANCODE_LGUI,          /*  KEY_LEFTMETA        125 */
    208    SDL_SCANCODE_RGUI,          /*  KEY_RIGHTMETA       126 */
    209    SDL_SCANCODE_APPLICATION,   /*  KEY_COMPOSE     127 */
    210    SDL_SCANCODE_STOP,          /*  KEY_STOP        128 AC Stop */
    211    SDL_SCANCODE_AGAIN,         /*  KEY_AGAIN       129 */
    212    SDL_SCANCODE_UNKNOWN,       /*  KEY_PROPS       130 AC Properties */
    213    SDL_SCANCODE_UNDO,          /*  KEY_UNDO        131 AC Undo */
    214    SDL_SCANCODE_UNKNOWN,       /*  KEY_FRONT       132 */
    215    SDL_SCANCODE_COPY,          /*  KEY_COPY        133 AC Copy */
    216    SDL_SCANCODE_UNKNOWN,       /*  KEY_OPEN        134 AC Open */
    217    SDL_SCANCODE_PASTE,         /*  KEY_PASTE       135 AC Paste */
    218    SDL_SCANCODE_FIND,          /*  KEY_FIND        136 AC Search */
    219    SDL_SCANCODE_CUT,           /*  KEY_CUT         137 AC Cut */
    220    SDL_SCANCODE_HELP,          /*  KEY_HELP        138 AL Integrated Help Center */
    221    SDL_SCANCODE_MENU,          /*  KEY_MENU        139 Menu (show menu) */
    222    SDL_SCANCODE_CALCULATOR,    /*  KEY_CALC        140 AL Calculator */
    223    SDL_SCANCODE_UNKNOWN,       /*  KEY_SETUP       141 */
    224    SDL_SCANCODE_SLEEP,         /*  KEY_SLEEP       142 SC System Sleep */
    225    SDL_SCANCODE_UNKNOWN,       /*  KEY_WAKEUP      143 System Wake Up */
    226    SDL_SCANCODE_UNKNOWN,       /*  KEY_FILE        144 AL Local Machine Browser */
    227    SDL_SCANCODE_UNKNOWN,       /*  KEY_SENDFILE        145 */
    228    SDL_SCANCODE_UNKNOWN,       /*  KEY_DELETEFILE      146 */
    229    SDL_SCANCODE_UNKNOWN,       /*  KEY_XFER        147 */
    230    SDL_SCANCODE_APP1,          /*  KEY_PROG1       148 */
    231    SDL_SCANCODE_APP1,          /*  KEY_PROG2       149 */
    232    SDL_SCANCODE_WWW,           /*  KEY_WWW         150 AL Internet Browser */
    233    SDL_SCANCODE_UNKNOWN,       /*  KEY_MSDOS       151 */
    234    SDL_SCANCODE_UNKNOWN,       /*  KEY_COFFEE,KEY_SCREENLOCK      152 AL Terminal Lock/Screensaver */
    235    SDL_SCANCODE_UNKNOWN,       /*  KEY_DIRECTION       153 */
    236    SDL_SCANCODE_UNKNOWN,       /*  KEY_CYCLEWINDOWS    154 */
    237    SDL_SCANCODE_MAIL,          /*  KEY_MAIL        155 */
    238    SDL_SCANCODE_AC_BOOKMARKS,  /*  KEY_BOOKMARKS       156 AC Bookmarks */
    239    SDL_SCANCODE_COMPUTER,      /*  KEY_COMPUTER        157 */
    240    SDL_SCANCODE_AC_BACK,       /*  KEY_BACK        158 AC Back */
    241    SDL_SCANCODE_AC_FORWARD,    /*  KEY_FORWARD     159 AC Forward */
    242    SDL_SCANCODE_UNKNOWN,       /*  KEY_CLOSECD     160 */
    243    SDL_SCANCODE_EJECT,         /*  KEY_EJECTCD     161 */
    244    SDL_SCANCODE_UNKNOWN,       /*  KEY_EJECTCLOSECD    162 */
    245    SDL_SCANCODE_AUDIONEXT,     /*  KEY_NEXTSONG        163 */
    246    SDL_SCANCODE_AUDIOPLAY,     /*  KEY_PLAYPAUSE       164 */
    247    SDL_SCANCODE_AUDIOPREV,     /*  KEY_PREVIOUSSONG    165 */
    248    SDL_SCANCODE_AUDIOSTOP,     /*  KEY_STOPCD      166 */
    249    SDL_SCANCODE_UNKNOWN,       /*  KEY_RECORD      167 */
    250    SDL_SCANCODE_UNKNOWN,       /*  KEY_REWIND      168 */
    251    SDL_SCANCODE_UNKNOWN,       /*  KEY_PHONE       169 Media Select Telephone */
    252    SDL_SCANCODE_UNKNOWN,       /*  KEY_ISO         170 */
    253    SDL_SCANCODE_UNKNOWN,       /*  KEY_CONFIG      171 AL Consumer Control Configuration */
    254    SDL_SCANCODE_AC_HOME,       /*  KEY_HOMEPAGE        172 AC Home */
    255    SDL_SCANCODE_AC_REFRESH,    /*  KEY_REFRESH     173 AC Refresh */
    256    SDL_SCANCODE_UNKNOWN,       /*  KEY_EXIT        174 AC Exit */
    257    SDL_SCANCODE_UNKNOWN,       /*  KEY_MOVE        175 */
    258    SDL_SCANCODE_UNKNOWN,       /*  KEY_EDIT        176 */
    259    SDL_SCANCODE_UNKNOWN,       /*  KEY_SCROLLUP        177 */
    260    SDL_SCANCODE_UNKNOWN,       /*  KEY_SCROLLDOWN      178 */
    261    SDL_SCANCODE_KP_LEFTPAREN,  /*  KEY_KPLEFTPAREN     179 */
    262    SDL_SCANCODE_KP_RIGHTPAREN, /*  KEY_KPRIGHTPAREN    180 */
    263    SDL_SCANCODE_UNKNOWN,       /*  KEY_NEW         181 AC New */
    264    SDL_SCANCODE_AGAIN,         /*  KEY_REDO        182 AC Redo/Repeat */
    265    SDL_SCANCODE_F13,           /*  KEY_F13         183 */
    266    SDL_SCANCODE_F14,           /*  KEY_F14         184 */
    267    SDL_SCANCODE_F15,           /*  KEY_F15         185 */
    268    SDL_SCANCODE_F16,           /*  KEY_F16         186 */
    269    SDL_SCANCODE_F17,           /*  KEY_F17         187 */
    270    SDL_SCANCODE_F18,           /*  KEY_F18         188 */
    271    SDL_SCANCODE_F19,           /*  KEY_F19         189 */
    272    SDL_SCANCODE_F20,           /*  KEY_F20         190 */
    273    SDL_SCANCODE_F21,           /*  KEY_F21         191 */
    274    SDL_SCANCODE_F22,           /*  KEY_F22         192 */
    275    SDL_SCANCODE_F23,           /*  KEY_F23         193 */
    276    SDL_SCANCODE_F24,           /*  KEY_F24         194 */
    277    SDL_SCANCODE_UNKNOWN,       /*  195 */
    278    SDL_SCANCODE_UNKNOWN,       /*  196 */
    279    SDL_SCANCODE_UNKNOWN,       /*  197 */
    280    SDL_SCANCODE_UNKNOWN,       /*  198 */
    281    SDL_SCANCODE_UNKNOWN,       /*  199 */
    282    SDL_SCANCODE_UNKNOWN,       /*  KEY_PLAYCD      200 */
    283    SDL_SCANCODE_UNKNOWN,       /*  KEY_PAUSECD     201 */
    284    SDL_SCANCODE_UNKNOWN,       /*  KEY_PROG3       202 */
    285    SDL_SCANCODE_UNKNOWN,       /*  KEY_PROG4       203 */
    286    SDL_SCANCODE_UNKNOWN,       /*  KEY_DASHBOARD       204 AL Dashboard */
    287    SDL_SCANCODE_UNKNOWN,       /*  KEY_SUSPEND     205 */
    288    SDL_SCANCODE_UNKNOWN,       /*  KEY_CLOSE       206 AC Close */
    289    SDL_SCANCODE_UNKNOWN,       /*  KEY_PLAY        207 */
    290    SDL_SCANCODE_UNKNOWN,       /*  KEY_FASTFORWARD     208 */
    291    SDL_SCANCODE_UNKNOWN,       /*  KEY_BASSBOOST       209 */
    292    SDL_SCANCODE_UNKNOWN,       /*  KEY_PRINT       210 AC Print */
    293    SDL_SCANCODE_UNKNOWN,       /*  KEY_HP          211 */
    294    SDL_SCANCODE_UNKNOWN,       /*  KEY_CAMERA      212 */
    295    SDL_SCANCODE_UNKNOWN,       /*  KEY_SOUND       213 */
    296    SDL_SCANCODE_UNKNOWN,       /*  KEY_QUESTION        214 */
    297    SDL_SCANCODE_UNKNOWN,       /*  KEY_EMAIL       215 */
    298    SDL_SCANCODE_UNKNOWN,       /*  KEY_CHAT        216 */
    299    SDL_SCANCODE_UNKNOWN,       /*  KEY_SEARCH      217 */
    300    SDL_SCANCODE_UNKNOWN,       /*  KEY_CONNECT     218 */
    301    SDL_SCANCODE_UNKNOWN,       /*  KEY_FINANCE     219 AL Checkbook/Finance */
    302    SDL_SCANCODE_UNKNOWN,       /*  KEY_SPORT       220 */
    303    SDL_SCANCODE_UNKNOWN,       /*  KEY_SHOP        221 */
    304    SDL_SCANCODE_UNKNOWN,       /*  KEY_ALTERASE        222 */
    305    SDL_SCANCODE_UNKNOWN,       /*  KEY_CANCEL      223 AC Cancel */
    306    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESSDOWN  224 */
    307    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESSUP    225 */
    308    SDL_SCANCODE_UNKNOWN,       /*  KEY_MEDIA       226 */
    309    SDL_SCANCODE_UNKNOWN,       /*  KEY_SWITCHVIDEOMODE 227 Cycle between available video outputs (Monitor/LCD/TV-out/etc) */
    310    SDL_SCANCODE_UNKNOWN,       /*  KEY_KBDILLUMTOGGLE  228 */
    311    SDL_SCANCODE_UNKNOWN,       /*  KEY_KBDILLUMDOWN    229 */
    312    SDL_SCANCODE_UNKNOWN,       /*  KEY_KBDILLUMUP      230 */
    313    SDL_SCANCODE_UNKNOWN,       /*  KEY_SEND        231 AC Send */
    314    SDL_SCANCODE_UNKNOWN,       /*  KEY_REPLY       232 AC Reply */
    315    SDL_SCANCODE_UNKNOWN,       /*  KEY_FORWARDMAIL     233 AC Forward Msg */
    316    SDL_SCANCODE_UNKNOWN,       /*  KEY_SAVE        234 AC Save */
    317    SDL_SCANCODE_UNKNOWN,       /*  KEY_DOCUMENTS       235 */
    318    SDL_SCANCODE_UNKNOWN,       /*  KEY_BATTERY     236  */
    319    SDL_SCANCODE_UNKNOWN,       /*  KEY_BLUETOOTH       237 */
    320    SDL_SCANCODE_UNKNOWN,       /*  KEY_WLAN        238 */
    321    SDL_SCANCODE_UNKNOWN,       /*  KEY_UWB         239 */
    322    SDL_SCANCODE_UNKNOWN,       /*  KEY_UNKNOWN     240 */
    323    SDL_SCANCODE_UNKNOWN,       /*  KEY_VIDEO_NEXT      241 drive next video source */
    324    SDL_SCANCODE_UNKNOWN,       /*  KEY_VIDEO_PREV      242 drive previous video source */
    325    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESS_CYCLE    243 brightness up, after max is min */
    326    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESS_ZERO 244 brightness off, use ambient */
    327    SDL_SCANCODE_UNKNOWN,       /*  KEY_DISPLAY_OFF     245 display device to off state */
    328    SDL_SCANCODE_UNKNOWN,       /*  KEY_WIMAX       246 */
    329    SDL_SCANCODE_UNKNOWN,       /*  KEY_RFKILL      247 Key that controls all radios */
    330    SDL_SCANCODE_UNKNOWN,       /*  KEY_MICMUTE     248 Mute / unmute the microphone */
    331};
    332
    333static Uint8 EVDEV_MouseButtons[] = {
    334    SDL_BUTTON_LEFT,            /*  BTN_LEFT        0x110 */
    335    SDL_BUTTON_RIGHT,           /*  BTN_RIGHT       0x111 */
    336    SDL_BUTTON_MIDDLE,          /*  BTN_MIDDLE      0x112 */
    337    SDL_BUTTON_X1,              /*  BTN_SIDE        0x113 */
    338    SDL_BUTTON_X2,              /*  BTN_EXTRA       0x114 */
    339    SDL_BUTTON_X2 + 1,          /*  BTN_FORWARD     0x115 */
    340    SDL_BUTTON_X2 + 2,          /*  BTN_BACK        0x116 */
    341    SDL_BUTTON_X2 + 3           /*  BTN_TASK        0x117 */
    342};
    343
    344static char* EVDEV_consoles[] = {
    345    "/proc/self/fd/0",
    346    "/dev/tty",
    347    "/dev/tty0",
    348    "/dev/tty1",
    349    "/dev/tty2",
    350    "/dev/tty3",
    351    "/dev/tty4",
    352    "/dev/tty5",
    353    "/dev/tty6",
    354    "/dev/vc/0",
    355    "/dev/console"
    356};
    357
    358#define IS_CONSOLE(fd) isatty (fd) && ioctl(fd, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84))
    359
    360static int SDL_EVDEV_get_console_fd(void)
    361{
    362    int fd, i;
    363    char arg = 0;
    364    
    365    /* Try a few consoles to see which one we have read access to */
    366    
    367    for( i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
    368        fd = open(EVDEV_consoles[i], O_RDONLY);
    369        if (fd >= 0) {
    370            if (IS_CONSOLE(fd)) return fd;
    371            close(fd);
    372        }
    373    }
    374    
    375    /* Try stdin, stdout, stderr */
    376    
    377    for( fd = 0; fd < 3; fd++) {
    378        if (IS_CONSOLE(fd)) return fd;
    379    }
    380    
    381    /* We won't be able to send SDL_TEXTINPUT events */
    382    return -1;
    383}
    384
    385/* Prevent keystrokes from reaching the tty */
    386static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode)
    387{
    388    char arg;
    389    
    390    *kb_mode = 0; /* FIXME: Is this a sane default in case KDGKBMODE fails? */
    391    if (!IS_CONSOLE(tty)) {
    392        return SDL_SetError("Tried to mute an invalid tty");
    393    }
    394    ioctl(tty, KDGKBMODE, kb_mode); /* It's not fatal if this fails */
    395    if (ioctl(tty, KDSKBMUTE, 1) && ioctl(tty, KDSKBMODE, K_OFF)) {
    396        return SDL_SetError("EVDEV: Failed muting keyboard");
    397    }
    398    
    399    return 0;  
    400}
    401
    402/* Restore the keyboard mode for given tty */
    403static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode)
    404{
    405    if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) {
    406        SDL_Log("EVDEV: Failed restoring keyboard mode");
    407    }
    408}
    409
    410/* Read /sys/class/tty/tty0/active and open the tty */
    411static int SDL_EVDEV_get_active_tty()
    412{
    413    int fd, len;
    414    char ttyname[NAME_MAX + 1];
    415    char ttypath[PATH_MAX+1] = "/dev/";
    416    char arg;
    417    
    418    fd = open("/sys/class/tty/tty0/active", O_RDONLY);
    419    if (fd < 0) {
    420        return SDL_SetError("Could not determine which tty is active");
    421    }
    422    
    423    len = read(fd, ttyname, NAME_MAX);
    424    close(fd);
    425    
    426    if (len <= 0) {
    427        return SDL_SetError("Could not read which tty is active");
    428    }
    429    
    430    if (ttyname[len-1] == '\n') {
    431        ttyname[len-1] = '\0';
    432    }
    433    else {
    434        ttyname[len] = '\0';
    435    }
    436    
    437    SDL_strlcat(ttypath, ttyname, PATH_MAX);
    438    fd = open(ttypath, O_RDWR | O_NOCTTY);
    439    if (fd < 0) {
    440        return SDL_SetError("Could not open tty: %s", ttypath);
    441    }
    442    
    443    if (!IS_CONSOLE(fd)) {
    444        close(fd);
    445        return SDL_SetError("Invalid tty obtained: %s", ttypath);
    446    }
    447
    448    return fd;  
    449}
    450
    451int
    452SDL_EVDEV_Init(void)
    453{
    454    int retval = 0;
    455    
    456    if (_this == NULL) {
    457        
    458        _this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
    459        if(_this == NULL) {
    460            return SDL_OutOfMemory();
    461        }
    462
    463#if SDL_USE_LIBUDEV
    464        if (SDL_UDEV_Init() < 0) {
    465            SDL_free(_this);
    466            _this = NULL;
    467            return -1;
    468        }
    469
    470        /* Set up the udev callback */
    471        if ( SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
    472            SDL_EVDEV_Quit();
    473            return -1;
    474        }
    475        
    476        /* Force a scan to build the initial device list */
    477        SDL_UDEV_Scan();
    478#else
    479        /* TODO: Scan the devices manually, like a caveman */
    480#endif /* SDL_USE_LIBUDEV */
    481        
    482        /* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */
    483        _this->console_fd = SDL_EVDEV_get_console_fd();
    484        
    485        /* Mute the keyboard so keystrokes only generate evdev events and do not leak through to the console */
    486        _this->tty = STDIN_FILENO;
    487        if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
    488            /* stdin is not a tty, probably we were launched remotely, so we try to disable the active tty */
    489            _this->tty = SDL_EVDEV_get_active_tty();
    490            if (_this->tty >= 0) {
    491                if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
    492                    close(_this->tty);
    493                    _this->tty = -1;
    494                }
    495            }
    496        }
    497    }
    498    
    499    _this->ref_count += 1;
    500    
    501    return retval;
    502}
    503
    504void
    505SDL_EVDEV_Quit(void)
    506{
    507    if (_this == NULL) {
    508        return;
    509    }
    510    
    511    _this->ref_count -= 1;
    512    
    513    if (_this->ref_count < 1) {
    514        
    515#if SDL_USE_LIBUDEV
    516        SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
    517        SDL_UDEV_Quit();
    518#endif /* SDL_USE_LIBUDEV */
    519       
    520        if (_this->console_fd >= 0) {
    521            close(_this->console_fd);
    522        }
    523        
    524        if (_this->tty >= 0) {
    525            SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode);
    526            close(_this->tty);
    527        }
    528        
    529        /* Remove existing devices */
    530        while(_this->first != NULL) {
    531            SDL_EVDEV_device_removed(_this->first->path);
    532        }
    533        
    534        SDL_assert(_this->first == NULL);
    535        SDL_assert(_this->last == NULL);
    536        SDL_assert(_this->numdevices == 0);
    537        
    538        SDL_free(_this);
    539        _this = NULL;
    540    }
    541}
    542
    543#if SDL_USE_LIBUDEV
    544void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
    545{
    546    if (devpath == NULL) {
    547        return;
    548    }
    549    
    550    if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) {
    551        return;
    552    }
    553
    554    switch( udev_type ) {
    555    case SDL_UDEV_DEVICEADDED:
    556        SDL_EVDEV_device_added(devpath);
    557        break;
    558            
    559    case SDL_UDEV_DEVICEREMOVED:
    560        SDL_EVDEV_device_removed(devpath);
    561        break;
    562            
    563    default:
    564        break;
    565    }
    566}
    567
    568#endif /* SDL_USE_LIBUDEV */
    569
    570void 
    571SDL_EVDEV_Poll(void)
    572{
    573    struct input_event events[32];
    574    int i, len;
    575    SDL_evdevlist_item *item;
    576    SDL_Scancode scan_code;
    577    int mouse_button;
    578    SDL_Mouse *mouse;
    579#ifdef SDL_INPUT_LINUXKD
    580    Uint16 modstate;
    581    struct kbentry kbe;
    582    static char keysym[8];
    583    char *end;
    584    Uint32 kval;
    585#endif
    586
    587    if (!_this) {
    588        return;
    589    }
    590
    591#if SDL_USE_LIBUDEV
    592    SDL_UDEV_Poll();
    593#endif
    594
    595    mouse = SDL_GetMouse();
    596
    597    for (item = _this->first; item != NULL; item = item->next) {
    598        while ((len = read(item->fd, events, (sizeof events))) > 0) {
    599            len /= sizeof(events[0]);
    600            for (i = 0; i < len; ++i) {
    601                switch (events[i].type) {
    602                case EV_KEY:
    603                    if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
    604                        mouse_button = events[i].code - BTN_MOUSE;
    605                        if (events[i].value == 0) {
    606                            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
    607                        } else if (events[i].value == 1) {
    608                            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
    609                        }
    610                        break;
    611                    }
    612
    613                    /* Probably keyboard */
    614                    scan_code = SDL_EVDEV_translate_keycode(events[i].code);
    615                    if (scan_code != SDL_SCANCODE_UNKNOWN) {
    616                        if (events[i].value == 0) {
    617                            SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
    618                        } else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) {
    619                            SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
    620#ifdef SDL_INPUT_LINUXKD
    621                            if (_this->console_fd >= 0) {
    622                                kbe.kb_index = events[i].code;
    623                                /* Convert the key to an UTF-8 char */
    624                                /* Ref: http://www.linuxjournal.com/article/2783 */
    625                                modstate = SDL_GetModState();
    626                                kbe.kb_table = 0;
    627                                
    628                                /* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */
    629                                kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL);
    630                                kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL);
    631                                kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT);
    632                                kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT);
    633                                kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT);
    634                                kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR);
    635
    636                                if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 && 
    637                                    ((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER))) 
    638                                {
    639                                    kval = KVAL(kbe.kb_value);
    640                                    
    641                                    /* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it
    642                                     * because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table 
    643                                     * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale!
    644                                     */
    645                                    if ( modstate & KMOD_CAPS && isalpha(kval) ) {
    646                                        if ( isupper(kval) ) {
    647                                            kval = tolower(kval);
    648                                        } else {
    649                                            kval = toupper(kval);
    650                                        }
    651                                    }
    652                                     
    653                                    /* Convert to UTF-8 and send */
    654                                    end = SDL_UCS4ToUTF8( kval, keysym);
    655                                    *end = '\0';
    656                                    SDL_SendKeyboardText(keysym);
    657                                }
    658                            }
    659#endif /* SDL_INPUT_LINUXKD */
    660                        }
    661                    }
    662                    break;
    663                case EV_ABS:
    664                    switch(events[i].code) {
    665                    case ABS_X:
    666                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
    667                        break;
    668                    case ABS_Y:
    669                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
    670                        break;
    671                    default:
    672                        break;
    673                    }
    674                    break;
    675                case EV_REL:
    676                    switch(events[i].code) {
    677                    case REL_X:
    678                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
    679                        break;
    680                    case REL_Y:
    681                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
    682                        break;
    683                    case REL_WHEEL:
    684                        SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value);
    685                        break;
    686                    case REL_HWHEEL:
    687                        SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0);
    688                        break;
    689                    default:
    690                        break;
    691                    }
    692                    break;
    693                case EV_SYN:
    694                    switch (events[i].code) {
    695                    case SYN_DROPPED:
    696                        SDL_EVDEV_sync_device(item);
    697                        break;
    698                    default:
    699                        break;
    700                    }
    701                    break;
    702                }
    703            }
    704        }    
    705    }
    706}
    707
    708static SDL_Scancode
    709SDL_EVDEV_translate_keycode(int keycode)
    710{
    711    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
    712
    713    if (keycode < SDL_arraysize(EVDEV_Keycodes)) {
    714        scancode = EVDEV_Keycodes[keycode];
    715    }
    716    if (scancode == SDL_SCANCODE_UNKNOWN) {
    717        SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list <sdl@libsdl.org> EVDEV KeyCode %d \n", keycode);
    718    }
    719    return scancode;
    720}
    721
    722static void
    723SDL_EVDEV_sync_device(SDL_evdevlist_item *item) 
    724{
    725    /* TODO: get full state of device and report whatever is required */
    726}
    727
    728#if SDL_USE_LIBUDEV
    729static int
    730SDL_EVDEV_device_added(const char *devpath)
    731{
    732    SDL_evdevlist_item *item;
    733
    734    /* Check to make sure it's not already in list. */
    735    for (item = _this->first; item != NULL; item = item->next) {
    736        if (strcmp(devpath, item->path) == 0) {
    737            return -1;  /* already have this one */
    738        }
    739    }
    740    
    741    item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
    742    if (item == NULL) {
    743        return SDL_OutOfMemory();
    744    }
    745
    746    item->fd = open(devpath, O_RDONLY, 0);
    747    if (item->fd < 0) {
    748        SDL_free(item);
    749        return SDL_SetError("Unable to open %s", devpath);
    750    }
    751    
    752    item->path = SDL_strdup(devpath);
    753    if (item->path == NULL) {
    754        close(item->fd);
    755        SDL_free(item);
    756        return SDL_OutOfMemory();
    757    }
    758    
    759    /* Non blocking read mode */
    760    fcntl(item->fd, F_SETFL, O_NONBLOCK);
    761    
    762    if (_this->last == NULL) {
    763        _this->first = _this->last = item;
    764    } else {
    765        _this->last->next = item;
    766        _this->last = item;
    767    }
    768    
    769    SDL_EVDEV_sync_device(item);
    770    
    771    return _this->numdevices++;
    772}
    773#endif /* SDL_USE_LIBUDEV */
    774
    775static int
    776SDL_EVDEV_device_removed(const char *devpath)
    777{
    778    SDL_evdevlist_item *item;
    779    SDL_evdevlist_item *prev = NULL;
    780
    781    for (item = _this->first; item != NULL; item = item->next) {
    782        /* found it, remove it. */
    783        if ( strcmp(devpath, item->path) ==0 ) {
    784            if (prev != NULL) {
    785                prev->next = item->next;
    786            } else {
    787                SDL_assert(_this->first == item);
    788                _this->first = item->next;
    789            }
    790            if (item == _this->last) {
    791                _this->last = prev;
    792            }
    793            close(item->fd);
    794            SDL_free(item->path);
    795            SDL_free(item);
    796            _this->numdevices--;
    797            return 0;
    798        }
    799        prev = item;
    800    }
    801
    802    return -1;
    803}
    804
    805
    806#endif /* SDL_INPUT_LINUXEV */
    807
    808/* vi: set ts=4 sw=4 expandtab: */
    809