src/core/linux/SDL_evdev.c
author Edward Rudd <urkle@outoforder.cc>
Sun, 23 Nov 2014 21:09:54 -0500
changeset 9257 6f41196c2d6b
parent 9159 d743b9d03a52
child 9619 b94b6d0bff0f
permissions -rw-r--r--
add in support for passing down the "natural" (or flipped) scrolling direction in the MouseWheelEvent event
     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
    35 static _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 
    72 static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
    73 static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
    74 static int SDL_EVDEV_device_removed(const char *devpath);
    75 
    76 #if SDL_USE_LIBUDEV
    77 static int SDL_EVDEV_device_added(const char *devpath);
    78 void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
    79 #endif /* SDL_USE_LIBUDEV */
    80 
    81 static 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 
   333 static 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 
   344 static 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 
   360 static 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 */
   386 static 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 */
   403 static 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 */
   411 static 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 
   451 int
   452 SDL_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 
   504 void
   505 SDL_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
   544 void 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 
   570 void 
   571 SDL_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, SDL_MOUSEWHEEL_NORMAL);
   685                         break;
   686                     case REL_HWHEEL:
   687                         SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
   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 
   708 static SDL_Scancode
   709 SDL_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 
   722 static void
   723 SDL_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
   729 static int
   730 SDL_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 
   775 static int
   776 SDL_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