2
Simple DirectMedia Layer
3
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21
#include "SDL_config.h"
23
#ifdef SDL_INPUT_LINUXEV
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
33
#include "SDL_evdev.h"
34
#define _THIS SDL_EVDEV_PrivateData *_this
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
45
#include <linux/keyboard.h>
49
/* We need this to prevent keystrokes from appear in the console */
51
#define KDSKBMUTE 0x4B51
54
#define KDSKBMODE 0x4B45
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"
67
/* This isn't defined in older Linux kernel headers */
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);
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 */
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 */
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 */
344
static char* EVDEV_consoles[] = {
358
#define IS_CONSOLE(fd) isatty (fd) && ioctl(fd, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84))
360
static int SDL_EVDEV_get_console_fd(void)
365
/* Try a few consoles to see which one we have read access to */
367
for( i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
368
fd = open(EVDEV_consoles[i], O_RDONLY);
370
if (IS_CONSOLE(fd)) return fd;
375
/* Try stdin, stdout, stderr */
377
for( fd = 0; fd < 3; fd++) {
378
if (IS_CONSOLE(fd)) return fd;
381
/* We won't be able to send SDL_TEXTINPUT events */
385
/* Prevent keystrokes from reaching the tty */
386
static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode)
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");
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");
402
/* Restore the keyboard mode for given tty */
403
static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode)
405
if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) {
406
SDL_Log("EVDEV: Failed restoring keyboard mode");
410
/* Read /sys/class/tty/tty0/active and open the tty */
411
static int SDL_EVDEV_get_active_tty()
414
char ttyname[NAME_MAX + 1];
415
char ttypath[PATH_MAX+1] = "/dev/";
418
fd = open("/sys/class/tty/tty0/active", O_RDONLY);
420
return SDL_SetError("Could not determine which tty is active");
423
len = read(fd, ttyname, NAME_MAX);
427
return SDL_SetError("Could not read which tty is active");
430
if (ttyname[len-1] == '\n') {
431
ttyname[len-1] = '\0';
437
SDL_strlcat(ttypath, ttyname, PATH_MAX);
438
fd = open(ttypath, O_RDWR | O_NOCTTY);
440
return SDL_SetError("Could not open tty: %s", ttypath);
443
if (!IS_CONSOLE(fd)) {
445
return SDL_SetError("Invalid tty obtained: %s", ttypath);
458
_this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
460
return SDL_OutOfMemory();
464
if (SDL_UDEV_Init() < 0) {
470
/* Set up the udev callback */
471
if ( SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
476
/* Force a scan to build the initial device list */
479
/* TODO: Scan the devices manually, like a caveman */
480
#endif /* SDL_USE_LIBUDEV */
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();
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) {
499
_this->ref_count += 1;
511
_this->ref_count -= 1;
513
if (_this->ref_count < 1) {
516
SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
518
#endif /* SDL_USE_LIBUDEV */
520
if (_this->console_fd >= 0) {
521
close(_this->console_fd);
524
if (_this->tty >= 0) {
525
SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode);
529
/* Remove existing devices */
530
while(_this->first != NULL) {
531
SDL_EVDEV_device_removed(_this->first->path);
534
SDL_assert(_this->first == NULL);
535
SDL_assert(_this->last == NULL);
536
SDL_assert(_this->numdevices == 0);
544
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
546
if (devpath == NULL) {
550
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) {
554
switch( udev_type ) {
555
case SDL_UDEV_DEVICEADDED:
556
SDL_EVDEV_device_added(devpath);
559
case SDL_UDEV_DEVICEREMOVED:
560
SDL_EVDEV_device_removed(devpath);
568
#endif /* SDL_USE_LIBUDEV */
573
struct input_event events[32];
575
SDL_evdevlist_item *item;
576
SDL_Scancode scan_code;
579
#ifdef SDL_INPUT_LINUXKD
582
static char keysym[8];
591
mouse = SDL_GetMouse();
593
for (item = _this->first; item != NULL; item = item->next) {
594
while ((len = read(item->fd, events, (sizeof events))) > 0) {
595
len /= sizeof(events[0]);
596
for (i = 0; i < len; ++i) {
597
switch (events[i].type) {
599
if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
600
mouse_button = events[i].code - BTN_MOUSE;
601
if (events[i].value == 0) {
602
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
603
} else if (events[i].value == 1) {
604
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
609
/* Probably keyboard */
610
scan_code = SDL_EVDEV_translate_keycode(events[i].code);
611
if (scan_code != SDL_SCANCODE_UNKNOWN) {
612
if (events[i].value == 0) {
613
SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
614
} else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) {
615
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
616
#ifdef SDL_INPUT_LINUXKD
617
if (_this->console_fd >= 0) {
618
kbe.kb_index = events[i].code;
619
/* Convert the key to an UTF-8 char */
620
/* Ref: http://www.linuxjournal.com/article/2783 */
621
modstate = SDL_GetModState();
624
/* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */
625
kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL);
626
kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL);
627
kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT);
628
kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT);
629
kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT);
630
kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR);
632
if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 &&
633
((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER)))
635
kval = KVAL(kbe.kb_value);
637
/* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it
638
* because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table
639
* So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale!
641
if ( modstate & KMOD_CAPS && isalpha(kval) ) {
642
if ( isupper(kval) ) {
643
kval = tolower(kval);
645
kval = toupper(kval);
649
/* Convert to UTF-8 and send */
650
end = SDL_UCS4ToUTF8( kval, keysym);
652
SDL_SendKeyboardText(keysym);
655
#endif /* SDL_INPUT_LINUXKD */
660
switch(events[i].code) {
662
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
665
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
672
switch(events[i].code) {
674
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
677
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
680
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value);
683
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0);
690
switch (events[i].code) {
692
SDL_EVDEV_sync_device(item);
705
SDL_EVDEV_translate_keycode(int keycode)
707
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
709
if (keycode < SDL_arraysize(EVDEV_Keycodes)) {
710
scancode = EVDEV_Keycodes[keycode];
712
if (scancode == SDL_SCANCODE_UNKNOWN) {
713
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);
719
SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
721
/* TODO: get full state of device and report whatever is required */
726
SDL_EVDEV_device_added(const char *devpath)
728
SDL_evdevlist_item *item;
730
/* Check to make sure it's not already in list. */
731
for (item = _this->first; item != NULL; item = item->next) {
732
if (strcmp(devpath, item->path) == 0) {
733
return -1; /* already have this one */
737
item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
739
return SDL_OutOfMemory();
742
item->fd = open(devpath, O_RDONLY, 0);
745
return SDL_SetError("Unable to open %s", devpath);
748
item->path = SDL_strdup(devpath);
749
if (item->path == NULL) {
752
return SDL_OutOfMemory();
755
/* Non blocking read mode */
756
fcntl(item->fd, F_SETFL, O_NONBLOCK);
758
if (_this->last == NULL) {
759
_this->first = _this->last = item;
761
_this->last->next = item;
765
SDL_EVDEV_sync_device(item);
767
return _this->numdevices++;
769
#endif /* SDL_USE_LIBUDEV */
772
SDL_EVDEV_device_removed(const char *devpath)
774
SDL_evdevlist_item *item;
775
SDL_evdevlist_item *prev = NULL;
777
for (item = _this->first; item != NULL; item = item->next) {
778
/* found it, remove it. */
779
if ( strcmp(devpath, item->path) ==0 ) {
781
prev->next = item->next;
783
SDL_assert(_this->first == item);
784
_this->first = item->next;
786
if (item == _this->last) {
790
SDL_free(item->path);
802
#endif /* SDL_INPUT_LINUXEV */
804
/* vi: set ts=4 sw=4 expandtab: */