src/core/linux/SDL_evdev.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 24 Jun 2015 17:54:39 -0700
changeset 9779 49b5a975a238
parent 9729 64f0929bcd2e
child 9780 7f9b74280df6
permissions -rw-r--r--
Fixed an issue with mouse/keyboard removal

Sometimes, on removal SDL_EVDEV_udev_callback() gets called with zero udev_class. This in turn seems to be caused the SDL_udev.c:guess_device_class() failing to find the attributes of the parent device.

Apparently this is normal, attributes are not guaranteed to be in place during removal, depending on timing. This lack of attributes causes guess_device_class() to return zero.

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