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