SDL_evdev.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2017 Sam Lantinga <[email protected]>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #ifdef SDL_INPUT_LINUXEV
  20. /* This is based on the linux joystick driver */
  21. /* References: https://www.kernel.org/doc/Documentation/input/input.txt
  22. * https://www.kernel.org/doc/Documentation/input/event-codes.txt
  23. * /usr/include/linux/input.h
  24. * The evtest application is also useful to debug the protocol
  25. */
  26. #include "SDL_evdev.h"
  27. #include <sys/stat.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <sys/ioctl.h>
  31. #include <limits.h> /* For the definition of PATH_MAX */
  32. #include <linux/input.h>
  33. #ifdef SDL_INPUT_LINUXKD
  34. #include <linux/kd.h>
  35. #include <linux/keyboard.h>
  36. #include <linux/vt.h>
  37. #include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
  38. #endif
  39. #include "SDL.h"
  40. #include "SDL_assert.h"
  41. #include "SDL_endian.h"
  42. #include "../../core/linux/SDL_udev.h"
  43. #include "SDL_scancode.h"
  44. #include "../../events/SDL_events_c.h"
  45. #include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
  46. /* These are not defined in older Linux kernel headers */
  47. #ifndef SYN_DROPPED
  48. #define SYN_DROPPED 3
  49. #endif
  50. #ifndef ABS_MT_SLOT
  51. #define ABS_MT_SLOT 0x2f
  52. #define ABS_MT_POSITION_X 0x35
  53. #define ABS_MT_POSITION_Y 0x36
  54. #define ABS_MT_TRACKING_ID 0x39
  55. #endif
  56. #ifndef K_OFF
  57. #define K_OFF 0x04
  58. #endif
  59. typedef struct SDL_evdevlist_item
  60. {
  61. char *path;
  62. int fd;
  63. /* TODO: use this for every device, not just touchscreen */
  64. int out_of_sync;
  65. /* TODO: expand on this to have data for every possible class (mouse,
  66. keyboard, touchpad, etc.). Also there's probably some things in here we
  67. can pull out to the SDL_evdevlist_item i.e. name */
  68. int is_touchscreen;
  69. struct {
  70. char* name;
  71. int min_x, max_x, range_x;
  72. int min_y, max_y, range_y;
  73. int max_slots;
  74. int current_slot;
  75. struct {
  76. enum {
  77. EVDEV_TOUCH_SLOTDELTA_NONE = 0,
  78. EVDEV_TOUCH_SLOTDELTA_DOWN,
  79. EVDEV_TOUCH_SLOTDELTA_UP,
  80. EVDEV_TOUCH_SLOTDELTA_MOVE
  81. } delta;
  82. int tracking_id;
  83. int x, y;
  84. } * slots;
  85. } * touchscreen_data;
  86. struct SDL_evdevlist_item *next;
  87. } SDL_evdevlist_item;
  88. typedef struct SDL_EVDEV_PrivateData
  89. {
  90. SDL_evdevlist_item *first;
  91. SDL_evdevlist_item *last;
  92. int num_devices;
  93. int ref_count;
  94. int console_fd;
  95. int old_kb_mode;
  96. } SDL_EVDEV_PrivateData;
  97. #define _THIS SDL_EVDEV_PrivateData *_this
  98. static _THIS = NULL;
  99. static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
  100. static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
  101. static int SDL_EVDEV_device_removed(const char *dev_path);
  102. #if SDL_USE_LIBUDEV
  103. static int SDL_EVDEV_device_added(const char *dev_path, int udev_class);
  104. void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
  105. const char *dev_path);
  106. #endif /* SDL_USE_LIBUDEV */
  107. static Uint8 EVDEV_MouseButtons[] = {
  108. SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */
  109. SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */
  110. SDL_BUTTON_MIDDLE, /* BTN_MIDDLE 0x112 */
  111. SDL_BUTTON_X1, /* BTN_SIDE 0x113 */
  112. SDL_BUTTON_X2, /* BTN_EXTRA 0x114 */
  113. SDL_BUTTON_X2 + 1, /* BTN_FORWARD 0x115 */
  114. SDL_BUTTON_X2 + 2, /* BTN_BACK 0x116 */
  115. SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
  116. };
  117. /* Prevent keystrokes from reaching the tty */
  118. static int SDL_EVDEV_mute_keyboard(int tty_fd, int* old_kb_mode)
  119. {
  120. if (ioctl(tty_fd, KDGKBMODE, old_kb_mode) < 0) {
  121. return SDL_SetError("Failed to get keyboard mode during muting");
  122. }
  123. if (ioctl(tty_fd, KDSKBMODE, K_OFF) < 0) {
  124. return SDL_SetError("Failed to set keyboard mode during muting");
  125. }
  126. return 0;
  127. }
  128. /* Restore the keyboard mode for given tty */
  129. static void SDL_EVDEV_unmute_keyboard(int tty_fd, int old_kb_mode)
  130. {
  131. if (ioctl(tty_fd, KDSKBMODE, old_kb_mode) < 0) {
  132. SDL_SetError("Failed to set keyboard mode during unmuting");
  133. }
  134. }
  135. int
  136. SDL_EVDEV_Init(void)
  137. {
  138. if (_this == NULL) {
  139. _this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
  140. if (_this == NULL) {
  141. return SDL_OutOfMemory();
  142. }
  143. #if SDL_USE_LIBUDEV
  144. if (SDL_UDEV_Init() < 0) {
  145. SDL_free(_this);
  146. _this = NULL;
  147. return -1;
  148. }
  149. /* Set up the udev callback */
  150. if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
  151. SDL_UDEV_Quit();
  152. SDL_free(_this);
  153. _this = NULL;
  154. return -1;
  155. }
  156. /* Force a scan to build the initial device list */
  157. SDL_UDEV_Scan();
  158. #else
  159. /* TODO: Scan the devices manually, like a caveman */
  160. #endif /* SDL_USE_LIBUDEV */
  161. /* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
  162. _this->console_fd = open("/dev/tty", O_RDONLY);
  163. /* Mute the keyboard so keystrokes only generate evdev events and do not
  164. leak through to the console */
  165. if (_this->console_fd >= 0) {
  166. SDL_EVDEV_mute_keyboard(_this->console_fd, &_this->old_kb_mode);
  167. }
  168. }
  169. _this->ref_count += 1;
  170. return 0;
  171. }
  172. void
  173. SDL_EVDEV_Quit(void)
  174. {
  175. if (_this == NULL) {
  176. return;
  177. }
  178. _this->ref_count -= 1;
  179. if (_this->ref_count < 1) {
  180. #if SDL_USE_LIBUDEV
  181. SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
  182. SDL_UDEV_Quit();
  183. #endif /* SDL_USE_LIBUDEV */
  184. if (_this->console_fd >= 0) {
  185. SDL_EVDEV_unmute_keyboard(_this->console_fd, _this->old_kb_mode);
  186. close(_this->console_fd);
  187. }
  188. /* Remove existing devices */
  189. while(_this->first != NULL) {
  190. SDL_EVDEV_device_removed(_this->first->path);
  191. }
  192. SDL_assert(_this->first == NULL);
  193. SDL_assert(_this->last == NULL);
  194. SDL_assert(_this->num_devices == 0);
  195. SDL_free(_this);
  196. _this = NULL;
  197. }
  198. }
  199. #if SDL_USE_LIBUDEV
  200. void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
  201. const char* dev_path)
  202. {
  203. if (dev_path == NULL) {
  204. return;
  205. }
  206. switch(udev_event) {
  207. case SDL_UDEV_DEVICEADDED:
  208. if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
  209. SDL_UDEV_DEVICE_TOUCHSCREEN)))
  210. return;
  211. SDL_EVDEV_device_added(dev_path, udev_class);
  212. break;
  213. case SDL_UDEV_DEVICEREMOVED:
  214. SDL_EVDEV_device_removed(dev_path);
  215. break;
  216. default:
  217. break;
  218. }
  219. }
  220. #endif /* SDL_USE_LIBUDEV */
  221. #ifdef SDL_INPUT_LINUXKD
  222. /* this logic is pulled from kbd_keycode() in drivers/tty/vt/keyboard.c in the
  223. Linux kernel source */
  224. static void SDL_EVDEV_do_text_input(unsigned short keycode)
  225. {
  226. char shift_state;
  227. int locks_state;
  228. struct kbentry kbe;
  229. unsigned char type;
  230. char text[2] = { 0 };
  231. if (_this->console_fd < 0)
  232. return;
  233. shift_state = TIOCL_GETSHIFTSTATE;
  234. if (ioctl(_this->console_fd, TIOCLINUX, &shift_state) < 0) {
  235. /* TODO: error */
  236. return;
  237. }
  238. kbe.kb_table = shift_state;
  239. kbe.kb_index = keycode;
  240. if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
  241. /* TODO: error */
  242. return;
  243. }
  244. if (kbe.kb_value == K_HOLE || kbe.kb_value == K_NOSUCHMAP) {
  245. return;
  246. }
  247. kbe.kb_value ^= 0xf000;
  248. type = KTYP(kbe.kb_value);
  249. if (type < 0xf0) {
  250. /*
  251. * FIXME: keysyms with a type below 0xf0 represent a unicode character
  252. * which requires special handling due to dead characters, diacritics,
  253. * etc. For perfect input a proper way to deal with such characters
  254. * should be implemented.
  255. *
  256. * For reference, the only place I was able to find out about this
  257. * special 0xf0 value was in an unused? couple of patches listed below.
  258. *
  259. * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-keyboard.diff
  260. * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-console.diff
  261. */
  262. return;
  263. }
  264. type -= 0xf0;
  265. /* if type is KT_LETTER then it can be affected by Caps Lock */
  266. if (type == KT_LETTER) {
  267. type = KT_LATIN;
  268. if (ioctl(_this->console_fd, KDGKBLED, &locks_state) < 0) {
  269. /* TODO: error */
  270. return;
  271. }
  272. if (locks_state & K_CAPSLOCK) {
  273. kbe.kb_table = shift_state ^ (1 << KG_SHIFT);
  274. if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
  275. /* TODO: error */
  276. return;
  277. }
  278. }
  279. }
  280. /* TODO: convert values >= 0x80 from ISO-8859-1? to UTF-8 */
  281. if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80)
  282. return;
  283. *text = KVAL(kbe.kb_value);
  284. SDL_SendKeyboardText(text);
  285. }
  286. #endif /* SDL_INPUT_LINUXKD */
  287. void
  288. SDL_EVDEV_Poll(void)
  289. {
  290. struct input_event events[32];
  291. int i, j, len;
  292. SDL_evdevlist_item *item;
  293. SDL_Scancode scan_code;
  294. int mouse_button;
  295. SDL_Mouse *mouse;
  296. float norm_x, norm_y;
  297. if (!_this) {
  298. return;
  299. }
  300. #if SDL_USE_LIBUDEV
  301. SDL_UDEV_Poll();
  302. #endif
  303. mouse = SDL_GetMouse();
  304. for (item = _this->first; item != NULL; item = item->next) {
  305. while ((len = read(item->fd, events, (sizeof events))) > 0) {
  306. len /= sizeof(events[0]);
  307. for (i = 0; i < len; ++i) {
  308. /* special handling for touchscreen, that should eventually be
  309. used for all devices */
  310. if (item->out_of_sync && item->is_touchscreen &&
  311. events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
  312. break;
  313. }
  314. switch (events[i].type) {
  315. case EV_KEY:
  316. if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
  317. mouse_button = events[i].code - BTN_MOUSE;
  318. if (events[i].value == 0) {
  319. SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
  320. } else if (events[i].value == 1) {
  321. SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
  322. }
  323. break;
  324. }
  325. /* Probably keyboard */
  326. scan_code = SDL_EVDEV_translate_keycode(events[i].code);
  327. if (scan_code != SDL_SCANCODE_UNKNOWN) {
  328. if (events[i].value == 0) {
  329. SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
  330. } else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) {
  331. SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
  332. #ifdef SDL_INPUT_LINUXKD
  333. SDL_EVDEV_do_text_input(events[i].code);
  334. #endif /* SDL_INPUT_LINUXKD */
  335. }
  336. }
  337. break;
  338. case EV_ABS:
  339. switch(events[i].code) {
  340. case ABS_MT_SLOT:
  341. if (!item->is_touchscreen) /* FIXME: temp hack */
  342. break;
  343. item->touchscreen_data->current_slot = events[i].value;
  344. break;
  345. case ABS_MT_TRACKING_ID:
  346. if (!item->is_touchscreen) /* FIXME: temp hack */
  347. break;
  348. if (events[i].value >= 0) {
  349. item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value;
  350. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
  351. } else {
  352. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
  353. }
  354. break;
  355. case ABS_MT_POSITION_X:
  356. if (!item->is_touchscreen) /* FIXME: temp hack */
  357. break;
  358. item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
  359. if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
  360. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
  361. }
  362. break;
  363. case ABS_MT_POSITION_Y:
  364. if (!item->is_touchscreen) /* FIXME: temp hack */
  365. break;
  366. item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
  367. if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
  368. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
  369. }
  370. break;
  371. case ABS_X:
  372. if (item->is_touchscreen) /* FIXME: temp hack */
  373. break;
  374. SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
  375. break;
  376. case ABS_Y:
  377. if (item->is_touchscreen) /* FIXME: temp hack */
  378. break;
  379. SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
  380. break;
  381. default:
  382. break;
  383. }
  384. break;
  385. case EV_REL:
  386. switch(events[i].code) {
  387. case REL_X:
  388. SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
  389. break;
  390. case REL_Y:
  391. SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
  392. break;
  393. case REL_WHEEL:
  394. SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
  395. break;
  396. case REL_HWHEEL:
  397. SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
  398. break;
  399. default:
  400. break;
  401. }
  402. break;
  403. case EV_SYN:
  404. switch (events[i].code) {
  405. case SYN_REPORT:
  406. if (!item->is_touchscreen) /* FIXME: temp hack */
  407. break;
  408. for(j = 0; j < item->touchscreen_data->max_slots; j++) {
  409. norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
  410. (float)item->touchscreen_data->range_x;
  411. norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
  412. (float)item->touchscreen_data->range_y;
  413. switch(item->touchscreen_data->slots[j].delta) {
  414. case EVDEV_TOUCH_SLOTDELTA_DOWN:
  415. SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f);
  416. item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
  417. break;
  418. case EVDEV_TOUCH_SLOTDELTA_UP:
  419. SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f);
  420. item->touchscreen_data->slots[j].tracking_id = -1;
  421. item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
  422. break;
  423. case EVDEV_TOUCH_SLOTDELTA_MOVE:
  424. SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
  425. item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
  426. break;
  427. default:
  428. break;
  429. }
  430. }
  431. if (item->out_of_sync)
  432. item->out_of_sync = 0;
  433. break;
  434. case SYN_DROPPED:
  435. if (item->is_touchscreen)
  436. item->out_of_sync = 1;
  437. SDL_EVDEV_sync_device(item);
  438. break;
  439. default:
  440. break;
  441. }
  442. break;
  443. }
  444. }
  445. }
  446. }
  447. }
  448. static SDL_Scancode
  449. SDL_EVDEV_translate_keycode(int keycode)
  450. {
  451. SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
  452. if (keycode < SDL_arraysize(linux_scancode_table))
  453. scancode = linux_scancode_table[keycode];
  454. if (scancode == SDL_SCANCODE_UNKNOWN) {
  455. SDL_Log("The key you just pressed is not recognized by SDL. To help "
  456. "get this fixed, please report this to the SDL mailing list "
  457. "<[email protected]> EVDEV KeyCode %d\n", keycode);
  458. }
  459. return scancode;
  460. }
  461. #ifdef SDL_USE_LIBUDEV
  462. static int
  463. SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
  464. {
  465. int ret, i;
  466. char name[64];
  467. struct input_absinfo abs_info;
  468. if (!item->is_touchscreen)
  469. return 0;
  470. item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
  471. if (item->touchscreen_data == NULL)
  472. return SDL_OutOfMemory();
  473. ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
  474. if (ret < 0) {
  475. SDL_free(item->touchscreen_data);
  476. return SDL_SetError("Failed to get evdev touchscreen name");
  477. }
  478. item->touchscreen_data->name = SDL_strdup(name);
  479. if (item->touchscreen_data->name == NULL) {
  480. SDL_free(item->touchscreen_data);
  481. return SDL_OutOfMemory();
  482. }
  483. ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
  484. if (ret < 0) {
  485. SDL_free(item->touchscreen_data->name);
  486. SDL_free(item->touchscreen_data);
  487. return SDL_SetError("Failed to get evdev touchscreen limits");
  488. }
  489. item->touchscreen_data->min_x = abs_info.minimum;
  490. item->touchscreen_data->max_x = abs_info.maximum;
  491. item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
  492. ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
  493. if (ret < 0) {
  494. SDL_free(item->touchscreen_data->name);
  495. SDL_free(item->touchscreen_data);
  496. return SDL_SetError("Failed to get evdev touchscreen limits");
  497. }
  498. item->touchscreen_data->min_y = abs_info.minimum;
  499. item->touchscreen_data->max_y = abs_info.maximum;
  500. item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
  501. ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
  502. if (ret < 0) {
  503. SDL_free(item->touchscreen_data->name);
  504. SDL_free(item->touchscreen_data);
  505. return SDL_SetError("Failed to get evdev touchscreen limits");
  506. }
  507. item->touchscreen_data->max_slots = abs_info.maximum + 1;
  508. item->touchscreen_data->slots = SDL_calloc(
  509. item->touchscreen_data->max_slots,
  510. sizeof(*item->touchscreen_data->slots));
  511. if (item->touchscreen_data->slots == NULL) {
  512. SDL_free(item->touchscreen_data->name);
  513. SDL_free(item->touchscreen_data);
  514. return SDL_OutOfMemory();
  515. }
  516. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  517. item->touchscreen_data->slots[i].tracking_id = -1;
  518. }
  519. ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
  520. item->touchscreen_data->name);
  521. if (ret < 0) {
  522. SDL_free(item->touchscreen_data->slots);
  523. SDL_free(item->touchscreen_data->name);
  524. SDL_free(item->touchscreen_data);
  525. return ret;
  526. }
  527. return 0;
  528. }
  529. #endif /* SDL_USE_LIBUDEV */
  530. static void
  531. SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
  532. if (!item->is_touchscreen)
  533. return;
  534. SDL_DelTouch(item->fd);
  535. SDL_free(item->touchscreen_data->slots);
  536. SDL_free(item->touchscreen_data->name);
  537. SDL_free(item->touchscreen_data);
  538. }
  539. static void
  540. SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
  541. {
  542. #ifdef EVIOCGMTSLOTS
  543. int i, ret;
  544. struct input_absinfo abs_info;
  545. /*
  546. * struct input_mt_request_layout {
  547. * __u32 code;
  548. * __s32 values[num_slots];
  549. * };
  550. *
  551. * this is the structure we're trying to emulate
  552. */
  553. __u32* mt_req_code;
  554. __s32* mt_req_values;
  555. size_t mt_req_size;
  556. /* TODO: sync devices other than touchscreen */
  557. if (!item->is_touchscreen)
  558. return;
  559. mt_req_size = sizeof(*mt_req_code) +
  560. sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
  561. mt_req_code = SDL_calloc(1, mt_req_size);
  562. if (mt_req_code == NULL) {
  563. return;
  564. }
  565. mt_req_values = (__s32*)mt_req_code + 1;
  566. *mt_req_code = ABS_MT_TRACKING_ID;
  567. ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
  568. if (ret < 0) {
  569. SDL_free(mt_req_code);
  570. return;
  571. }
  572. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  573. /*
  574. * This doesn't account for the very edge case of the user removing their
  575. * finger and replacing it on the screen during the time we're out of sync,
  576. * which'll mean that we're not going from down -> up or up -> down, we're
  577. * going from down -> down but with a different tracking id, meaning we'd
  578. * have to tell SDL of the two events, but since we wait till SYN_REPORT in
  579. * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
  580. * allow it. Lets just pray to God it doesn't happen.
  581. */
  582. if (item->touchscreen_data->slots[i].tracking_id < 0 &&
  583. mt_req_values[i] >= 0) {
  584. item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
  585. item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
  586. } else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
  587. mt_req_values[i] < 0) {
  588. item->touchscreen_data->slots[i].tracking_id = -1;
  589. item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
  590. }
  591. }
  592. *mt_req_code = ABS_MT_POSITION_X;
  593. ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
  594. if (ret < 0) {
  595. SDL_free(mt_req_code);
  596. return;
  597. }
  598. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  599. if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
  600. item->touchscreen_data->slots[i].x != mt_req_values[i]) {
  601. item->touchscreen_data->slots[i].x = mt_req_values[i];
  602. if (item->touchscreen_data->slots[i].delta ==
  603. EVDEV_TOUCH_SLOTDELTA_NONE) {
  604. item->touchscreen_data->slots[i].delta =
  605. EVDEV_TOUCH_SLOTDELTA_MOVE;
  606. }
  607. }
  608. }
  609. *mt_req_code = ABS_MT_POSITION_Y;
  610. ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
  611. if (ret < 0) {
  612. SDL_free(mt_req_code);
  613. return;
  614. }
  615. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  616. if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
  617. item->touchscreen_data->slots[i].y != mt_req_values[i]) {
  618. item->touchscreen_data->slots[i].y = mt_req_values[i];
  619. if (item->touchscreen_data->slots[i].delta ==
  620. EVDEV_TOUCH_SLOTDELTA_NONE) {
  621. item->touchscreen_data->slots[i].delta =
  622. EVDEV_TOUCH_SLOTDELTA_MOVE;
  623. }
  624. }
  625. }
  626. ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
  627. if (ret < 0) {
  628. SDL_free(mt_req_code);
  629. return;
  630. }
  631. item->touchscreen_data->current_slot = abs_info.value;
  632. SDL_free(mt_req_code);
  633. #endif /* EVIOCGMTSLOTS */
  634. }
  635. #if SDL_USE_LIBUDEV
  636. static int
  637. SDL_EVDEV_device_added(const char *dev_path, int udev_class)
  638. {
  639. int ret;
  640. SDL_evdevlist_item *item;
  641. /* Check to make sure it's not already in list. */
  642. for (item = _this->first; item != NULL; item = item->next) {
  643. if (SDL_strcmp(dev_path, item->path) == 0) {
  644. return -1; /* already have this one */
  645. }
  646. }
  647. item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
  648. if (item == NULL) {
  649. return SDL_OutOfMemory();
  650. }
  651. item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
  652. if (item->fd < 0) {
  653. SDL_free(item);
  654. return SDL_SetError("Unable to open %s", dev_path);
  655. }
  656. item->path = SDL_strdup(dev_path);
  657. if (item->path == NULL) {
  658. close(item->fd);
  659. SDL_free(item);
  660. return SDL_OutOfMemory();
  661. }
  662. if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
  663. item->is_touchscreen = 1;
  664. if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
  665. close(item->fd);
  666. SDL_free(item);
  667. return ret;
  668. }
  669. }
  670. if (_this->last == NULL) {
  671. _this->first = _this->last = item;
  672. } else {
  673. _this->last->next = item;
  674. _this->last = item;
  675. }
  676. SDL_EVDEV_sync_device(item);
  677. return _this->num_devices++;
  678. }
  679. #endif /* SDL_USE_LIBUDEV */
  680. static int
  681. SDL_EVDEV_device_removed(const char *dev_path)
  682. {
  683. SDL_evdevlist_item *item;
  684. SDL_evdevlist_item *prev = NULL;
  685. for (item = _this->first; item != NULL; item = item->next) {
  686. /* found it, remove it. */
  687. if (SDL_strcmp(dev_path, item->path) == 0) {
  688. if (prev != NULL) {
  689. prev->next = item->next;
  690. } else {
  691. SDL_assert(_this->first == item);
  692. _this->first = item->next;
  693. }
  694. if (item == _this->last) {
  695. _this->last = prev;
  696. }
  697. if (item->is_touchscreen) {
  698. SDL_EVDEV_destroy_touchscreen(item);
  699. }
  700. close(item->fd);
  701. SDL_free(item->path);
  702. SDL_free(item);
  703. _this->num_devices--;
  704. return 0;
  705. }
  706. prev = item;
  707. }
  708. return -1;
  709. }
  710. #endif /* SDL_INPUT_LINUXEV */
  711. /* vi: set ts=4 sw=4 expandtab: */