123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga <[email protected]>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "../../SDL_internal.h"
- #ifdef SDL_INPUT_LINUXEV
- /* This is based on the linux joystick driver */
- /* References: https://www.kernel.org/doc/Documentation/input/input.txt
- * https://www.kernel.org/doc/Documentation/input/event-codes.txt
- * /usr/include/linux/input.h
- * The evtest application is also useful to debug the protocol
- */
- #include "SDL_evdev.h"
- #define _THIS SDL_EVDEV_PrivateData *_this
- static _THIS = NULL;
- #include <sys/stat.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <limits.h> /* For the definition of PATH_MAX */
- #include <linux/input.h>
- #ifdef SDL_INPUT_LINUXKD
- #include <linux/kd.h>
- #include <linux/keyboard.h>
- #endif
- /* We need this to prevent keystrokes from appear in the console */
- #ifndef KDSKBMUTE
- #define KDSKBMUTE 0x4B51
- #endif
- #ifndef KDSKBMODE
- #define KDSKBMODE 0x4B45
- #endif
- #ifndef K_OFF
- #define K_OFF 0x04
- #endif
- #include "SDL.h"
- #include "SDL_assert.h"
- #include "SDL_endian.h"
- #include "../../core/linux/SDL_udev.h"
- #include "SDL_scancode.h"
- #include "../../events/SDL_events_c.h"
- /* This isn't defined in older Linux kernel headers */
- #ifndef SYN_DROPPED
- #define SYN_DROPPED 3
- #endif
- static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
- static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
- static int SDL_EVDEV_device_removed(const char *devpath);
- #if SDL_USE_LIBUDEV
- static int SDL_EVDEV_device_added(const char *devpath);
- void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
- #endif /* SDL_USE_LIBUDEV */
- static SDL_Scancode EVDEV_Keycodes[] = {
- SDL_SCANCODE_UNKNOWN, /* KEY_RESERVED 0 */
- SDL_SCANCODE_ESCAPE, /* KEY_ESC 1 */
- SDL_SCANCODE_1, /* KEY_1 2 */
- SDL_SCANCODE_2, /* KEY_2 3 */
- SDL_SCANCODE_3, /* KEY_3 4 */
- SDL_SCANCODE_4, /* KEY_4 5 */
- SDL_SCANCODE_5, /* KEY_5 6 */
- SDL_SCANCODE_6, /* KEY_6 7 */
- SDL_SCANCODE_7, /* KEY_7 8 */
- SDL_SCANCODE_8, /* KEY_8 9 */
- SDL_SCANCODE_9, /* KEY_9 10 */
- SDL_SCANCODE_0, /* KEY_0 11 */
- SDL_SCANCODE_MINUS, /* KEY_MINUS 12 */
- SDL_SCANCODE_EQUALS, /* KEY_EQUAL 13 */
- SDL_SCANCODE_BACKSPACE, /* KEY_BACKSPACE 14 */
- SDL_SCANCODE_TAB, /* KEY_TAB 15 */
- SDL_SCANCODE_Q, /* KEY_Q 16 */
- SDL_SCANCODE_W, /* KEY_W 17 */
- SDL_SCANCODE_E, /* KEY_E 18 */
- SDL_SCANCODE_R, /* KEY_R 19 */
- SDL_SCANCODE_T, /* KEY_T 20 */
- SDL_SCANCODE_Y, /* KEY_Y 21 */
- SDL_SCANCODE_U, /* KEY_U 22 */
- SDL_SCANCODE_I, /* KEY_I 23 */
- SDL_SCANCODE_O, /* KEY_O 24 */
- SDL_SCANCODE_P, /* KEY_P 25 */
- SDL_SCANCODE_LEFTBRACKET, /* KEY_LEFTBRACE 26 */
- SDL_SCANCODE_RIGHTBRACKET, /* KEY_RIGHTBRACE 27 */
- SDL_SCANCODE_RETURN, /* KEY_ENTER 28 */
- SDL_SCANCODE_LCTRL, /* KEY_LEFTCTRL 29 */
- SDL_SCANCODE_A, /* KEY_A 30 */
- SDL_SCANCODE_S, /* KEY_S 31 */
- SDL_SCANCODE_D, /* KEY_D 32 */
- SDL_SCANCODE_F, /* KEY_F 33 */
- SDL_SCANCODE_G, /* KEY_G 34 */
- SDL_SCANCODE_H, /* KEY_H 35 */
- SDL_SCANCODE_J, /* KEY_J 36 */
- SDL_SCANCODE_K, /* KEY_K 37 */
- SDL_SCANCODE_L, /* KEY_L 38 */
- SDL_SCANCODE_SEMICOLON, /* KEY_SEMICOLON 39 */
- SDL_SCANCODE_APOSTROPHE, /* KEY_APOSTROPHE 40 */
- SDL_SCANCODE_GRAVE, /* KEY_GRAVE 41 */
- SDL_SCANCODE_LSHIFT, /* KEY_LEFTSHIFT 42 */
- SDL_SCANCODE_BACKSLASH, /* KEY_BACKSLASH 43 */
- SDL_SCANCODE_Z, /* KEY_Z 44 */
- SDL_SCANCODE_X, /* KEY_X 45 */
- SDL_SCANCODE_C, /* KEY_C 46 */
- SDL_SCANCODE_V, /* KEY_V 47 */
- SDL_SCANCODE_B, /* KEY_B 48 */
- SDL_SCANCODE_N, /* KEY_N 49 */
- SDL_SCANCODE_M, /* KEY_M 50 */
- SDL_SCANCODE_COMMA, /* KEY_COMMA 51 */
- SDL_SCANCODE_PERIOD, /* KEY_DOT 52 */
- SDL_SCANCODE_SLASH, /* KEY_SLASH 53 */
- SDL_SCANCODE_RSHIFT, /* KEY_RIGHTSHIFT 54 */
- SDL_SCANCODE_KP_MULTIPLY, /* KEY_KPASTERISK 55 */
- SDL_SCANCODE_LALT, /* KEY_LEFTALT 56 */
- SDL_SCANCODE_SPACE, /* KEY_SPACE 57 */
- SDL_SCANCODE_CAPSLOCK, /* KEY_CAPSLOCK 58 */
- SDL_SCANCODE_F1, /* KEY_F1 59 */
- SDL_SCANCODE_F2, /* KEY_F2 60 */
- SDL_SCANCODE_F3, /* KEY_F3 61 */
- SDL_SCANCODE_F4, /* KEY_F4 62 */
- SDL_SCANCODE_F5, /* KEY_F5 63 */
- SDL_SCANCODE_F6, /* KEY_F6 64 */
- SDL_SCANCODE_F7, /* KEY_F7 65 */
- SDL_SCANCODE_F8, /* KEY_F8 66 */
- SDL_SCANCODE_F9, /* KEY_F9 67 */
- SDL_SCANCODE_F10, /* KEY_F10 68 */
- SDL_SCANCODE_NUMLOCKCLEAR, /* KEY_NUMLOCK 69 */
- SDL_SCANCODE_SCROLLLOCK, /* KEY_SCROLLLOCK 70 */
- SDL_SCANCODE_KP_7, /* KEY_KP7 71 */
- SDL_SCANCODE_KP_8, /* KEY_KP8 72 */
- SDL_SCANCODE_KP_9, /* KEY_KP9 73 */
- SDL_SCANCODE_KP_MINUS, /* KEY_KPMINUS 74 */
- SDL_SCANCODE_KP_4, /* KEY_KP4 75 */
- SDL_SCANCODE_KP_5, /* KEY_KP5 76 */
- SDL_SCANCODE_KP_6, /* KEY_KP6 77 */
- SDL_SCANCODE_KP_PLUS, /* KEY_KPPLUS 78 */
- SDL_SCANCODE_KP_1, /* KEY_KP1 79 */
- SDL_SCANCODE_KP_2, /* KEY_KP2 80 */
- SDL_SCANCODE_KP_3, /* KEY_KP3 81 */
- SDL_SCANCODE_KP_0, /* KEY_KP0 82 */
- SDL_SCANCODE_KP_PERIOD, /* KEY_KPDOT 83 */
- SDL_SCANCODE_UNKNOWN, /* 84 */
- SDL_SCANCODE_LANG5, /* KEY_ZENKAKUHANKAKU 85 */
- SDL_SCANCODE_UNKNOWN, /* KEY_102ND 86 */
- SDL_SCANCODE_F11, /* KEY_F11 87 */
- SDL_SCANCODE_F12, /* KEY_F12 88 */
- SDL_SCANCODE_UNKNOWN, /* KEY_RO 89 */
- SDL_SCANCODE_LANG3, /* KEY_KATAKANA 90 */
- SDL_SCANCODE_LANG4, /* KEY_HIRAGANA 91 */
- SDL_SCANCODE_UNKNOWN, /* KEY_HENKAN 92 */
- SDL_SCANCODE_LANG3, /* KEY_KATAKANAHIRAGANA 93 */
- SDL_SCANCODE_UNKNOWN, /* KEY_MUHENKAN 94 */
- SDL_SCANCODE_KP_COMMA, /* KEY_KPJPCOMMA 95 */
- SDL_SCANCODE_KP_ENTER, /* KEY_KPENTER 96 */
- SDL_SCANCODE_RCTRL, /* KEY_RIGHTCTRL 97 */
- SDL_SCANCODE_KP_DIVIDE, /* KEY_KPSLASH 98 */
- SDL_SCANCODE_SYSREQ, /* KEY_SYSRQ 99 */
- SDL_SCANCODE_RALT, /* KEY_RIGHTALT 100 */
- SDL_SCANCODE_UNKNOWN, /* KEY_LINEFEED 101 */
- SDL_SCANCODE_HOME, /* KEY_HOME 102 */
- SDL_SCANCODE_UP, /* KEY_UP 103 */
- SDL_SCANCODE_PAGEUP, /* KEY_PAGEUP 104 */
- SDL_SCANCODE_LEFT, /* KEY_LEFT 105 */
- SDL_SCANCODE_RIGHT, /* KEY_RIGHT 106 */
- SDL_SCANCODE_END, /* KEY_END 107 */
- SDL_SCANCODE_DOWN, /* KEY_DOWN 108 */
- SDL_SCANCODE_PAGEDOWN, /* KEY_PAGEDOWN 109 */
- SDL_SCANCODE_INSERT, /* KEY_INSERT 110 */
- SDL_SCANCODE_DELETE, /* KEY_DELETE 111 */
- SDL_SCANCODE_UNKNOWN, /* KEY_MACRO 112 */
- SDL_SCANCODE_MUTE, /* KEY_MUTE 113 */
- SDL_SCANCODE_VOLUMEDOWN, /* KEY_VOLUMEDOWN 114 */
- SDL_SCANCODE_VOLUMEUP, /* KEY_VOLUMEUP 115 */
- SDL_SCANCODE_POWER, /* KEY_POWER 116 SC System Power Down */
- SDL_SCANCODE_KP_EQUALS, /* KEY_KPEQUAL 117 */
- SDL_SCANCODE_KP_MINUS, /* KEY_KPPLUSMINUS 118 */
- SDL_SCANCODE_PAUSE, /* KEY_PAUSE 119 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SCALE 120 AL Compiz Scale (Expose) */
- SDL_SCANCODE_KP_COMMA, /* KEY_KPCOMMA 121 */
- SDL_SCANCODE_LANG1, /* KEY_HANGEUL,KEY_HANGUEL 122 */
- SDL_SCANCODE_LANG2, /* KEY_HANJA 123 */
- SDL_SCANCODE_INTERNATIONAL3,/* KEY_YEN 124 */
- SDL_SCANCODE_LGUI, /* KEY_LEFTMETA 125 */
- SDL_SCANCODE_RGUI, /* KEY_RIGHTMETA 126 */
- SDL_SCANCODE_APPLICATION, /* KEY_COMPOSE 127 */
- SDL_SCANCODE_STOP, /* KEY_STOP 128 AC Stop */
- SDL_SCANCODE_AGAIN, /* KEY_AGAIN 129 */
- SDL_SCANCODE_UNKNOWN, /* KEY_PROPS 130 AC Properties */
- SDL_SCANCODE_UNDO, /* KEY_UNDO 131 AC Undo */
- SDL_SCANCODE_UNKNOWN, /* KEY_FRONT 132 */
- SDL_SCANCODE_COPY, /* KEY_COPY 133 AC Copy */
- SDL_SCANCODE_UNKNOWN, /* KEY_OPEN 134 AC Open */
- SDL_SCANCODE_PASTE, /* KEY_PASTE 135 AC Paste */
- SDL_SCANCODE_FIND, /* KEY_FIND 136 AC Search */
- SDL_SCANCODE_CUT, /* KEY_CUT 137 AC Cut */
- SDL_SCANCODE_HELP, /* KEY_HELP 138 AL Integrated Help Center */
- SDL_SCANCODE_MENU, /* KEY_MENU 139 Menu (show menu) */
- SDL_SCANCODE_CALCULATOR, /* KEY_CALC 140 AL Calculator */
- SDL_SCANCODE_UNKNOWN, /* KEY_SETUP 141 */
- SDL_SCANCODE_SLEEP, /* KEY_SLEEP 142 SC System Sleep */
- SDL_SCANCODE_UNKNOWN, /* KEY_WAKEUP 143 System Wake Up */
- SDL_SCANCODE_UNKNOWN, /* KEY_FILE 144 AL Local Machine Browser */
- SDL_SCANCODE_UNKNOWN, /* KEY_SENDFILE 145 */
- SDL_SCANCODE_UNKNOWN, /* KEY_DELETEFILE 146 */
- SDL_SCANCODE_UNKNOWN, /* KEY_XFER 147 */
- SDL_SCANCODE_APP1, /* KEY_PROG1 148 */
- SDL_SCANCODE_APP1, /* KEY_PROG2 149 */
- SDL_SCANCODE_WWW, /* KEY_WWW 150 AL Internet Browser */
- SDL_SCANCODE_UNKNOWN, /* KEY_MSDOS 151 */
- SDL_SCANCODE_UNKNOWN, /* KEY_COFFEE,KEY_SCREENLOCK 152 AL Terminal Lock/Screensaver */
- SDL_SCANCODE_UNKNOWN, /* KEY_DIRECTION 153 */
- SDL_SCANCODE_UNKNOWN, /* KEY_CYCLEWINDOWS 154 */
- SDL_SCANCODE_MAIL, /* KEY_MAIL 155 */
- SDL_SCANCODE_AC_BOOKMARKS, /* KEY_BOOKMARKS 156 AC Bookmarks */
- SDL_SCANCODE_COMPUTER, /* KEY_COMPUTER 157 */
- SDL_SCANCODE_AC_BACK, /* KEY_BACK 158 AC Back */
- SDL_SCANCODE_AC_FORWARD, /* KEY_FORWARD 159 AC Forward */
- SDL_SCANCODE_UNKNOWN, /* KEY_CLOSECD 160 */
- SDL_SCANCODE_EJECT, /* KEY_EJECTCD 161 */
- SDL_SCANCODE_UNKNOWN, /* KEY_EJECTCLOSECD 162 */
- SDL_SCANCODE_AUDIONEXT, /* KEY_NEXTSONG 163 */
- SDL_SCANCODE_AUDIOPLAY, /* KEY_PLAYPAUSE 164 */
- SDL_SCANCODE_AUDIOPREV, /* KEY_PREVIOUSSONG 165 */
- SDL_SCANCODE_AUDIOSTOP, /* KEY_STOPCD 166 */
- SDL_SCANCODE_UNKNOWN, /* KEY_RECORD 167 */
- SDL_SCANCODE_UNKNOWN, /* KEY_REWIND 168 */
- SDL_SCANCODE_UNKNOWN, /* KEY_PHONE 169 Media Select Telephone */
- SDL_SCANCODE_UNKNOWN, /* KEY_ISO 170 */
- SDL_SCANCODE_UNKNOWN, /* KEY_CONFIG 171 AL Consumer Control Configuration */
- SDL_SCANCODE_AC_HOME, /* KEY_HOMEPAGE 172 AC Home */
- SDL_SCANCODE_AC_REFRESH, /* KEY_REFRESH 173 AC Refresh */
- SDL_SCANCODE_UNKNOWN, /* KEY_EXIT 174 AC Exit */
- SDL_SCANCODE_UNKNOWN, /* KEY_MOVE 175 */
- SDL_SCANCODE_UNKNOWN, /* KEY_EDIT 176 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLUP 177 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLDOWN 178 */
- SDL_SCANCODE_KP_LEFTPAREN, /* KEY_KPLEFTPAREN 179 */
- SDL_SCANCODE_KP_RIGHTPAREN, /* KEY_KPRIGHTPAREN 180 */
- SDL_SCANCODE_UNKNOWN, /* KEY_NEW 181 AC New */
- SDL_SCANCODE_AGAIN, /* KEY_REDO 182 AC Redo/Repeat */
- SDL_SCANCODE_F13, /* KEY_F13 183 */
- SDL_SCANCODE_F14, /* KEY_F14 184 */
- SDL_SCANCODE_F15, /* KEY_F15 185 */
- SDL_SCANCODE_F16, /* KEY_F16 186 */
- SDL_SCANCODE_F17, /* KEY_F17 187 */
- SDL_SCANCODE_F18, /* KEY_F18 188 */
- SDL_SCANCODE_F19, /* KEY_F19 189 */
- SDL_SCANCODE_F20, /* KEY_F20 190 */
- SDL_SCANCODE_F21, /* KEY_F21 191 */
- SDL_SCANCODE_F22, /* KEY_F22 192 */
- SDL_SCANCODE_F23, /* KEY_F23 193 */
- SDL_SCANCODE_F24, /* KEY_F24 194 */
- SDL_SCANCODE_UNKNOWN, /* 195 */
- SDL_SCANCODE_UNKNOWN, /* 196 */
- SDL_SCANCODE_UNKNOWN, /* 197 */
- SDL_SCANCODE_UNKNOWN, /* 198 */
- SDL_SCANCODE_UNKNOWN, /* 199 */
- SDL_SCANCODE_UNKNOWN, /* KEY_PLAYCD 200 */
- SDL_SCANCODE_UNKNOWN, /* KEY_PAUSECD 201 */
- SDL_SCANCODE_UNKNOWN, /* KEY_PROG3 202 */
- SDL_SCANCODE_UNKNOWN, /* KEY_PROG4 203 */
- SDL_SCANCODE_UNKNOWN, /* KEY_DASHBOARD 204 AL Dashboard */
- SDL_SCANCODE_UNKNOWN, /* KEY_SUSPEND 205 */
- SDL_SCANCODE_UNKNOWN, /* KEY_CLOSE 206 AC Close */
- SDL_SCANCODE_UNKNOWN, /* KEY_PLAY 207 */
- SDL_SCANCODE_UNKNOWN, /* KEY_FASTFORWARD 208 */
- SDL_SCANCODE_UNKNOWN, /* KEY_BASSBOOST 209 */
- SDL_SCANCODE_UNKNOWN, /* KEY_PRINT 210 AC Print */
- SDL_SCANCODE_UNKNOWN, /* KEY_HP 211 */
- SDL_SCANCODE_UNKNOWN, /* KEY_CAMERA 212 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SOUND 213 */
- SDL_SCANCODE_UNKNOWN, /* KEY_QUESTION 214 */
- SDL_SCANCODE_UNKNOWN, /* KEY_EMAIL 215 */
- SDL_SCANCODE_UNKNOWN, /* KEY_CHAT 216 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SEARCH 217 */
- SDL_SCANCODE_UNKNOWN, /* KEY_CONNECT 218 */
- SDL_SCANCODE_UNKNOWN, /* KEY_FINANCE 219 AL Checkbook/Finance */
- SDL_SCANCODE_UNKNOWN, /* KEY_SPORT 220 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SHOP 221 */
- SDL_SCANCODE_UNKNOWN, /* KEY_ALTERASE 222 */
- SDL_SCANCODE_UNKNOWN, /* KEY_CANCEL 223 AC Cancel */
- SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSDOWN 224 */
- SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSUP 225 */
- SDL_SCANCODE_UNKNOWN, /* KEY_MEDIA 226 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SWITCHVIDEOMODE 227 Cycle between available video outputs (Monitor/LCD/TV-out/etc) */
- SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMTOGGLE 228 */
- SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMDOWN 229 */
- SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMUP 230 */
- SDL_SCANCODE_UNKNOWN, /* KEY_SEND 231 AC Send */
- SDL_SCANCODE_UNKNOWN, /* KEY_REPLY 232 AC Reply */
- SDL_SCANCODE_UNKNOWN, /* KEY_FORWARDMAIL 233 AC Forward Msg */
- SDL_SCANCODE_UNKNOWN, /* KEY_SAVE 234 AC Save */
- SDL_SCANCODE_UNKNOWN, /* KEY_DOCUMENTS 235 */
- SDL_SCANCODE_UNKNOWN, /* KEY_BATTERY 236 */
- SDL_SCANCODE_UNKNOWN, /* KEY_BLUETOOTH 237 */
- SDL_SCANCODE_UNKNOWN, /* KEY_WLAN 238 */
- SDL_SCANCODE_UNKNOWN, /* KEY_UWB 239 */
- SDL_SCANCODE_UNKNOWN, /* KEY_UNKNOWN 240 */
- SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_NEXT 241 drive next video source */
- SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_PREV 242 drive previous video source */
- SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_CYCLE 243 brightness up, after max is min */
- SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_ZERO 244 brightness off, use ambient */
- SDL_SCANCODE_UNKNOWN, /* KEY_DISPLAY_OFF 245 display device to off state */
- SDL_SCANCODE_UNKNOWN, /* KEY_WIMAX 246 */
- SDL_SCANCODE_UNKNOWN, /* KEY_RFKILL 247 Key that controls all radios */
- SDL_SCANCODE_UNKNOWN, /* KEY_MICMUTE 248 Mute / unmute the microphone */
- };
- static Uint8 EVDEV_MouseButtons[] = {
- SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */
- SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */
- SDL_BUTTON_MIDDLE, /* BTN_MIDDLE 0x112 */
- SDL_BUTTON_X1, /* BTN_SIDE 0x113 */
- SDL_BUTTON_X2, /* BTN_EXTRA 0x114 */
- SDL_BUTTON_X2 + 1, /* BTN_FORWARD 0x115 */
- SDL_BUTTON_X2 + 2, /* BTN_BACK 0x116 */
- SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
- };
- static char* EVDEV_consoles[] = {
- "/proc/self/fd/0",
- "/dev/tty",
- "/dev/tty0",
- "/dev/tty1",
- "/dev/tty2",
- "/dev/tty3",
- "/dev/tty4",
- "/dev/tty5",
- "/dev/tty6",
- "/dev/vc/0",
- "/dev/console"
- };
- #define IS_CONSOLE(fd) isatty (fd) && ioctl(fd, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84))
- static int SDL_EVDEV_get_console_fd(void)
- {
- int fd, i;
- char arg = 0;
-
- /* Try a few consoles to see which one we have read access to */
-
- for( i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
- fd = open(EVDEV_consoles[i], O_RDONLY);
- if (fd >= 0) {
- if (IS_CONSOLE(fd)) return fd;
- close(fd);
- }
- }
-
- /* Try stdin, stdout, stderr */
-
- for( fd = 0; fd < 3; fd++) {
- if (IS_CONSOLE(fd)) return fd;
- }
-
- /* We won't be able to send SDL_TEXTINPUT events */
- return -1;
- }
- /* Prevent keystrokes from reaching the tty */
- static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode)
- {
- char arg;
-
- *kb_mode = 0; /* FIXME: Is this a sane default in case KDGKBMODE fails? */
- if (!IS_CONSOLE(tty)) {
- return SDL_SetError("Tried to mute an invalid tty");
- }
- ioctl(tty, KDGKBMODE, kb_mode); /* It's not fatal if this fails */
- if (ioctl(tty, KDSKBMUTE, 1) && ioctl(tty, KDSKBMODE, K_OFF)) {
- return SDL_SetError("EVDEV: Failed muting keyboard");
- }
-
- return 0;
- }
- /* Restore the keyboard mode for given tty */
- static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode)
- {
- if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) {
- SDL_Log("EVDEV: Failed restoring keyboard mode");
- }
- }
- /* Read /sys/class/tty/tty0/active and open the tty */
- static int SDL_EVDEV_get_active_tty()
- {
- int fd, len;
- char ttyname[NAME_MAX + 1];
- char ttypath[PATH_MAX+1] = "/dev/";
- char arg;
-
- fd = open("/sys/class/tty/tty0/active", O_RDONLY);
- if (fd < 0) {
- return SDL_SetError("Could not determine which tty is active");
- }
-
- len = read(fd, ttyname, NAME_MAX);
- close(fd);
-
- if (len <= 0) {
- return SDL_SetError("Could not read which tty is active");
- }
-
- if (ttyname[len-1] == '\n') {
- ttyname[len-1] = '\0';
- }
- else {
- ttyname[len] = '\0';
- }
-
- SDL_strlcat(ttypath, ttyname, PATH_MAX);
- fd = open(ttypath, O_RDWR | O_NOCTTY);
- if (fd < 0) {
- return SDL_SetError("Could not open tty: %s", ttypath);
- }
-
- if (!IS_CONSOLE(fd)) {
- close(fd);
- return SDL_SetError("Invalid tty obtained: %s", ttypath);
- }
- return fd;
- }
- int
- SDL_EVDEV_Init(void)
- {
- int retval = 0;
-
- if (_this == NULL) {
-
- _this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
- if(_this == NULL) {
- return SDL_OutOfMemory();
- }
- #if SDL_USE_LIBUDEV
- if (SDL_UDEV_Init() < 0) {
- SDL_free(_this);
- _this = NULL;
- return -1;
- }
- /* Set up the udev callback */
- if ( SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
- SDL_EVDEV_Quit();
- return -1;
- }
-
- /* Force a scan to build the initial device list */
- SDL_UDEV_Scan();
- #else
- /* TODO: Scan the devices manually, like a caveman */
- #endif /* SDL_USE_LIBUDEV */
-
- /* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */
- _this->console_fd = SDL_EVDEV_get_console_fd();
-
- /* Mute the keyboard so keystrokes only generate evdev events and do not leak through to the console */
- _this->tty = STDIN_FILENO;
- if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
- /* stdin is not a tty, probably we were launched remotely, so we try to disable the active tty */
- _this->tty = SDL_EVDEV_get_active_tty();
- if (_this->tty >= 0) {
- if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
- close(_this->tty);
- _this->tty = -1;
- }
- }
- }
- }
-
- _this->ref_count += 1;
-
- return retval;
- }
- void
- SDL_EVDEV_Quit(void)
- {
- if (_this == NULL) {
- return;
- }
-
- _this->ref_count -= 1;
-
- if (_this->ref_count < 1) {
-
- #if SDL_USE_LIBUDEV
- SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
- SDL_UDEV_Quit();
- #endif /* SDL_USE_LIBUDEV */
-
- if (_this->console_fd >= 0) {
- close(_this->console_fd);
- }
-
- if (_this->tty >= 0) {
- SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode);
- close(_this->tty);
- }
-
- /* Remove existing devices */
- while(_this->first != NULL) {
- SDL_EVDEV_device_removed(_this->first->path);
- }
-
- SDL_assert(_this->first == NULL);
- SDL_assert(_this->last == NULL);
- SDL_assert(_this->numdevices == 0);
-
- SDL_free(_this);
- _this = NULL;
- }
- }
- #if SDL_USE_LIBUDEV
- void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
- {
- if (devpath == NULL) {
- return;
- }
-
- if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) {
- return;
- }
- switch( udev_type ) {
- case SDL_UDEV_DEVICEADDED:
- SDL_EVDEV_device_added(devpath);
- break;
-
- case SDL_UDEV_DEVICEREMOVED:
- SDL_EVDEV_device_removed(devpath);
- break;
-
- default:
- break;
- }
- }
- #endif /* SDL_USE_LIBUDEV */
- void
- SDL_EVDEV_Poll(void)
- {
- struct input_event events[32];
- int i, len;
- SDL_evdevlist_item *item;
- SDL_Scancode scan_code;
- int mouse_button;
- SDL_Mouse *mouse;
- #ifdef SDL_INPUT_LINUXKD
- Uint16 modstate;
- struct kbentry kbe;
- static char keysym[8];
- char *end;
- Uint32 kval;
- #endif
- if (!_this) {
- return;
- }
- #if SDL_USE_LIBUDEV
- SDL_UDEV_Poll();
- #endif
- mouse = SDL_GetMouse();
- for (item = _this->first; item != NULL; item = item->next) {
- while ((len = read(item->fd, events, (sizeof events))) > 0) {
- len /= sizeof(events[0]);
- for (i = 0; i < len; ++i) {
- switch (events[i].type) {
- case EV_KEY:
- if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
- mouse_button = events[i].code - BTN_MOUSE;
- if (events[i].value == 0) {
- SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
- } else if (events[i].value == 1) {
- SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
- }
- break;
- }
- /* Probably keyboard */
- scan_code = SDL_EVDEV_translate_keycode(events[i].code);
- if (scan_code != SDL_SCANCODE_UNKNOWN) {
- if (events[i].value == 0) {
- SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
- } else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) {
- SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
- #ifdef SDL_INPUT_LINUXKD
- if (_this->console_fd >= 0) {
- kbe.kb_index = events[i].code;
- /* Convert the key to an UTF-8 char */
- /* Ref: http://www.linuxjournal.com/article/2783 */
- modstate = SDL_GetModState();
- kbe.kb_table = 0;
-
- /* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */
- kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL);
- kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL);
- kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT);
- kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT);
- kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT);
- kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR);
- if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 &&
- ((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER)))
- {
- kval = KVAL(kbe.kb_value);
-
- /* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it
- * because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table
- * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale!
- */
- if ( modstate & KMOD_CAPS && isalpha(kval) ) {
- if ( isupper(kval) ) {
- kval = tolower(kval);
- } else {
- kval = toupper(kval);
- }
- }
-
- /* Convert to UTF-8 and send */
- end = SDL_UCS4ToUTF8( kval, keysym);
- *end = '\0';
- SDL_SendKeyboardText(keysym);
- }
- }
- #endif /* SDL_INPUT_LINUXKD */
- }
- }
- break;
- case EV_ABS:
- switch(events[i].code) {
- case ABS_X:
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
- break;
- case ABS_Y:
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
- break;
- default:
- break;
- }
- break;
- case EV_REL:
- switch(events[i].code) {
- case REL_X:
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
- break;
- case REL_Y:
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
- break;
- case REL_WHEEL:
- SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value);
- break;
- case REL_HWHEEL:
- SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0);
- break;
- default:
- break;
- }
- break;
- case EV_SYN:
- switch (events[i].code) {
- case SYN_DROPPED:
- SDL_EVDEV_sync_device(item);
- break;
- default:
- break;
- }
- break;
- }
- }
- }
- }
- }
- static SDL_Scancode
- SDL_EVDEV_translate_keycode(int keycode)
- {
- SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
- if (keycode < SDL_arraysize(EVDEV_Keycodes)) {
- scancode = EVDEV_Keycodes[keycode];
- }
- if (scancode == SDL_SCANCODE_UNKNOWN) {
- 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 <[email protected]> EVDEV KeyCode %d \n", keycode);
- }
- return scancode;
- }
- static void
- SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
- {
- /* TODO: get full state of device and report whatever is required */
- }
- #if SDL_USE_LIBUDEV
- static int
- SDL_EVDEV_device_added(const char *devpath)
- {
- SDL_evdevlist_item *item;
- /* Check to make sure it's not already in list. */
- for (item = _this->first; item != NULL; item = item->next) {
- if (strcmp(devpath, item->path) == 0) {
- return -1; /* already have this one */
- }
- }
-
- item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
- if (item == NULL) {
- return SDL_OutOfMemory();
- }
- item->fd = open(devpath, O_RDONLY, 0);
- if (item->fd < 0) {
- SDL_free(item);
- return SDL_SetError("Unable to open %s", devpath);
- }
-
- item->path = SDL_strdup(devpath);
- if (item->path == NULL) {
- close(item->fd);
- SDL_free(item);
- return SDL_OutOfMemory();
- }
-
- /* Non blocking read mode */
- fcntl(item->fd, F_SETFL, O_NONBLOCK);
-
- if (_this->last == NULL) {
- _this->first = _this->last = item;
- } else {
- _this->last->next = item;
- _this->last = item;
- }
-
- SDL_EVDEV_sync_device(item);
-
- return _this->numdevices++;
- }
- #endif /* SDL_USE_LIBUDEV */
- static int
- SDL_EVDEV_device_removed(const char *devpath)
- {
- SDL_evdevlist_item *item;
- SDL_evdevlist_item *prev = NULL;
- for (item = _this->first; item != NULL; item = item->next) {
- /* found it, remove it. */
- if ( strcmp(devpath, item->path) ==0 ) {
- if (prev != NULL) {
- prev->next = item->next;
- } else {
- SDL_assert(_this->first == item);
- _this->first = item->next;
- }
- if (item == _this->last) {
- _this->last = prev;
- }
- close(item->fd);
- SDL_free(item->path);
- SDL_free(item);
- _this->numdevices--;
- return 0;
- }
- prev = item;
- }
- return -1;
- }
- #endif /* SDL_INPUT_LINUXEV */
- /* vi: set ts=4 sw=4 expandtab: */
|