SDL  2.0
SDL_evdev.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 const 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  switch(udev_type) {
551  case SDL_UDEV_DEVICEADDED:
552  if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) {
553  return;
554  }
555  SDL_EVDEV_device_added(devpath);
556  break;
557 
558  case SDL_UDEV_DEVICEREMOVED:
559  SDL_EVDEV_device_removed(devpath);
560  break;
561 
562  default:
563  break;
564  }
565 }
566 
567 #endif /* SDL_USE_LIBUDEV */
568 
569 void
570 SDL_EVDEV_Poll(void)
571 {
572  struct input_event events[32];
573  int i, len;
574  SDL_evdevlist_item *item;
575  SDL_Scancode scan_code;
576  int mouse_button;
577  SDL_Mouse *mouse;
578 #ifdef SDL_INPUT_LINUXKD
579  Uint16 modstate;
580  struct kbentry kbe;
581  static char keysym[8];
582  char *end;
583  Uint32 kval;
584 #endif
585 
586  if (!_this) {
587  return;
588  }
589 
590 #if SDL_USE_LIBUDEV
591  SDL_UDEV_Poll();
592 #endif
593 
594  mouse = SDL_GetMouse();
595 
596  for (item = _this->first; item != NULL; item = item->next) {
597  while ((len = read(item->fd, events, (sizeof events))) > 0) {
598  len /= sizeof(events[0]);
599  for (i = 0; i < len; ++i) {
600  switch (events[i].type) {
601  case EV_KEY:
602  if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
603  mouse_button = events[i].code - BTN_MOUSE;
604  if (events[i].value == 0) {
605  SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
606  } else if (events[i].value == 1) {
607  SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
608  }
609  break;
610  }
611 
612  /* Probably keyboard */
613  scan_code = SDL_EVDEV_translate_keycode(events[i].code);
614  if (scan_code != SDL_SCANCODE_UNKNOWN) {
615  if (events[i].value == 0) {
616  SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
617  } else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */) {
618  SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
619 #ifdef SDL_INPUT_LINUXKD
620  if (_this->console_fd >= 0) {
621  kbe.kb_index = events[i].code;
622  /* Convert the key to an UTF-8 char */
623  /* Ref: http://www.linuxjournal.com/article/2783 */
624  modstate = SDL_GetModState();
625  kbe.kb_table = 0;
626 
627  /* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */
628  kbe.kb_table |= -((modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL);
629  kbe.kb_table |= -((modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL);
630  kbe.kb_table |= -((modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT);
631  kbe.kb_table |= -((modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT);
632  kbe.kb_table |= -((modstate & KMOD_LALT) != 0) & (1 << KG_ALT);
633  kbe.kb_table |= -((modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR);
634 
635  if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 &&
636  ((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER)))
637  {
638  kval = KVAL(kbe.kb_value);
639 
640  /* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it
641  * because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table
642  * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale!
643  */
644  if (modstate & KMOD_CAPS && isalpha(kval)) {
645  if (isupper(kval)) {
646  kval = tolower(kval);
647  } else {
648  kval = toupper(kval);
649  }
650  }
651 
652  /* Convert to UTF-8 and send */
653  end = SDL_UCS4ToUTF8(kval, keysym);
654  *end = '\0';
655  SDL_SendKeyboardText(keysym);
656  }
657  }
658 #endif /* SDL_INPUT_LINUXKD */
659  }
660  }
661  break;
662  case EV_ABS:
663  switch(events[i].code) {
664  case ABS_X:
665  SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
666  break;
667  case ABS_Y:
668  SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
669  break;
670  default:
671  break;
672  }
673  break;
674  case EV_REL:
675  switch(events[i].code) {
676  case REL_X:
677  SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
678  break;
679  case REL_Y:
680  SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
681  break;
682  case REL_WHEEL:
683  SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
684  break;
685  case REL_HWHEEL:
686  SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
687  break;
688  default:
689  break;
690  }
691  break;
692  case EV_SYN:
693  switch (events[i].code) {
694  case SYN_DROPPED:
695  SDL_EVDEV_sync_device(item);
696  break;
697  default:
698  break;
699  }
700  break;
701  }
702  }
703  }
704  }
705 }
706 
707 static SDL_Scancode
708 SDL_EVDEV_translate_keycode(int keycode)
709 {
711 
712  if (keycode < SDL_arraysize(EVDEV_Keycodes)) {
713  scancode = EVDEV_Keycodes[keycode];
714  }
715  if (scancode == SDL_SCANCODE_UNKNOWN) {
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);
717  }
718  return scancode;
719 }
720 
721 static void
722 SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
723 {
724  /* TODO: get full state of device and report whatever is required */
725 }
726 
727 #if SDL_USE_LIBUDEV
728 static int
729 SDL_EVDEV_device_added(const char *devpath)
730 {
731  SDL_evdevlist_item *item;
732 
733  /* Check to make sure it's not already in list. */
734  for (item = _this->first; item != NULL; item = item->next) {
735  if (SDL_strcmp(devpath, item->path) == 0) {
736  return -1; /* already have this one */
737  }
738  }
739 
740  item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
741  if (item == NULL) {
742  return SDL_OutOfMemory();
743  }
744 
745  item->fd = open(devpath, O_RDONLY, 0);
746  if (item->fd < 0) {
747  SDL_free(item);
748  return SDL_SetError("Unable to open %s", devpath);
749  }
750 
751  item->path = SDL_strdup(devpath);
752  if (item->path == NULL) {
753  close(item->fd);
754  SDL_free(item);
755  return SDL_OutOfMemory();
756  }
757 
758  /* Non blocking read mode */
759  fcntl(item->fd, F_SETFL, O_NONBLOCK);
760 
761  if (_this->last == NULL) {
762  _this->first = _this->last = item;
763  } else {
764  _this->last->next = item;
765  _this->last = item;
766  }
767 
768  SDL_EVDEV_sync_device(item);
769 
770  return _this->numdevices++;
771 }
772 #endif /* SDL_USE_LIBUDEV */
773 
774 static int
775 SDL_EVDEV_device_removed(const char *devpath)
776 {
777  SDL_evdevlist_item *item;
778  SDL_evdevlist_item *prev = NULL;
779 
780  for (item = _this->first; item != NULL; item = item->next) {
781  /* found it, remove it. */
782  if (SDL_strcmp(devpath, item->path) == 0) {
783  if (prev != NULL) {
784  prev->next = item->next;
785  } else {
786  SDL_assert(_this->first == item);
787  _this->first = item->next;
788  }
789  if (item == _this->last) {
790  _this->last = prev;
791  }
792  close(item->fd);
793  SDL_free(item->path);
794  SDL_free(item);
795  _this->numdevices--;
796  return 0;
797  }
798  prev = item;
799  }
800 
801  return -1;
802 }
803 
804 
805 #endif /* SDL_INPUT_LINUXEV */
806 
807 /* vi: set ts=4 sw=4 expandtab: */
808 
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:66
#define SDL_strlcat
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
SDL_Window * focus
Definition: SDL_mouse_c.h:77
GLuint GLuint end
Definition: SDL_opengl.h:1564
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:282
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:36
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:283
GLenum GLsizei len
SDL_MouseID mouseID
Definition: SDL_mouse_c.h:76
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:661
static SDL_VideoDevice * _this
Definition: SDL_video.c:114
SDL_bool retval
#define SDL_Log
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1564
void * SDL_calloc(size_t nmemb, size_t size)
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:188
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:280
GLsizei const GLfloat * value
#define _THIS
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:774
void SDL_free(void *mem)
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:281
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
#define SDL_assert(condition)
Definition: SDL_assert.h:167
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
char * SDL_UCS4ToUTF8(Uint32 ch, char *dst)
Definition: SDL_keyboard.c:512
#define SDL_SetError
#define SDL_strdup
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:147
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:406
#define SDL_strcmp
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_BUTTON_X2
Definition: SDL_mouse.h:284
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_GetModState
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:326
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43