SDL_evdev.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2022 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 "SDL_evdev_kbd.h"
  28. #include <sys/stat.h>
  29. #include <unistd.h>
  30. #include <fcntl.h>
  31. #include <sys/ioctl.h>
  32. #include <linux/input.h>
  33. #include "SDL.h"
  34. #include "SDL_endian.h"
  35. #include "SDL_scancode.h"
  36. #include "../../events/SDL_events_c.h"
  37. #include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
  38. #include "../../core/linux/SDL_evdev_capabilities.h"
  39. #include "../../core/linux/SDL_udev.h"
  40. /* These are not defined in older Linux kernel headers */
  41. #ifndef SYN_DROPPED
  42. #define SYN_DROPPED 3
  43. #endif
  44. #ifndef ABS_MT_SLOT
  45. #define ABS_MT_SLOT 0x2f
  46. #define ABS_MT_POSITION_X 0x35
  47. #define ABS_MT_POSITION_Y 0x36
  48. #define ABS_MT_TRACKING_ID 0x39
  49. #define ABS_MT_PRESSURE 0x3a
  50. #endif
  51. #ifndef REL_WHEEL_HI_RES
  52. #define REL_WHEEL_HI_RES 0x0b
  53. #define REL_HWHEEL_HI_RES 0x0c
  54. #endif
  55. typedef struct SDL_evdevlist_item
  56. {
  57. char *path;
  58. int fd;
  59. /* TODO: use this for every device, not just touchscreen */
  60. int out_of_sync;
  61. /* TODO: expand on this to have data for every possible class (mouse,
  62. keyboard, touchpad, etc.). Also there's probably some things in here we
  63. can pull out to the SDL_evdevlist_item i.e. name */
  64. int is_touchscreen;
  65. struct {
  66. char* name;
  67. int min_x, max_x, range_x;
  68. int min_y, max_y, range_y;
  69. int min_pressure, max_pressure, range_pressure;
  70. int max_slots;
  71. int current_slot;
  72. struct {
  73. enum {
  74. EVDEV_TOUCH_SLOTDELTA_NONE = 0,
  75. EVDEV_TOUCH_SLOTDELTA_DOWN,
  76. EVDEV_TOUCH_SLOTDELTA_UP,
  77. EVDEV_TOUCH_SLOTDELTA_MOVE
  78. } delta;
  79. int tracking_id;
  80. int x, y, pressure;
  81. } * slots;
  82. } * touchscreen_data;
  83. /* Mouse state */
  84. SDL_bool high_res_wheel;
  85. SDL_bool high_res_hwheel;
  86. SDL_bool relative_mouse;
  87. int mouse_x, mouse_y;
  88. int mouse_wheel, mouse_hwheel;
  89. struct SDL_evdevlist_item *next;
  90. } SDL_evdevlist_item;
  91. typedef struct SDL_EVDEV_PrivateData
  92. {
  93. int ref_count;
  94. int num_devices;
  95. SDL_evdevlist_item *first;
  96. SDL_evdevlist_item *last;
  97. SDL_EVDEV_keyboard_state *kbd;
  98. } SDL_EVDEV_PrivateData;
  99. #undef _THIS
  100. #define _THIS SDL_EVDEV_PrivateData *_this
  101. static _THIS = NULL;
  102. static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
  103. static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
  104. static int SDL_EVDEV_device_removed(const char *dev_path);
  105. #if SDL_USE_LIBUDEV
  106. static int SDL_EVDEV_device_added(const char *dev_path, int udev_class);
  107. static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
  108. const char *dev_path);
  109. #endif /* SDL_USE_LIBUDEV */
  110. static Uint8 EVDEV_MouseButtons[] = {
  111. SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */
  112. SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */
  113. SDL_BUTTON_MIDDLE, /* BTN_MIDDLE 0x112 */
  114. SDL_BUTTON_X1, /* BTN_SIDE 0x113 */
  115. SDL_BUTTON_X2, /* BTN_EXTRA 0x114 */
  116. SDL_BUTTON_X2 + 1, /* BTN_FORWARD 0x115 */
  117. SDL_BUTTON_X2 + 2, /* BTN_BACK 0x116 */
  118. SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
  119. };
  120. static int
  121. SDL_EVDEV_SetRelativeMouseMode(SDL_bool enabled)
  122. {
  123. /* Mice already send relative events through this interface */
  124. return 0;
  125. }
  126. int
  127. SDL_EVDEV_Init(void)
  128. {
  129. if (_this == NULL) {
  130. _this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
  131. if (_this == NULL) {
  132. return SDL_OutOfMemory();
  133. }
  134. #if SDL_USE_LIBUDEV
  135. if (SDL_UDEV_Init() < 0) {
  136. SDL_free(_this);
  137. _this = NULL;
  138. return -1;
  139. }
  140. /* Set up the udev callback */
  141. if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
  142. SDL_UDEV_Quit();
  143. SDL_free(_this);
  144. _this = NULL;
  145. return -1;
  146. }
  147. /* Force a scan to build the initial device list */
  148. SDL_UDEV_Scan();
  149. #else
  150. /* TODO: Scan the devices manually, like a caveman */
  151. #endif /* SDL_USE_LIBUDEV */
  152. _this->kbd = SDL_EVDEV_kbd_init();
  153. }
  154. SDL_GetMouse()->SetRelativeMouseMode = SDL_EVDEV_SetRelativeMouseMode;
  155. _this->ref_count += 1;
  156. return 0;
  157. }
  158. void
  159. SDL_EVDEV_Quit(void)
  160. {
  161. if (_this == NULL) {
  162. return;
  163. }
  164. _this->ref_count -= 1;
  165. if (_this->ref_count < 1) {
  166. #if SDL_USE_LIBUDEV
  167. SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
  168. SDL_UDEV_Quit();
  169. #endif /* SDL_USE_LIBUDEV */
  170. SDL_EVDEV_kbd_quit(_this->kbd);
  171. /* Remove existing devices */
  172. while(_this->first != NULL) {
  173. SDL_EVDEV_device_removed(_this->first->path);
  174. }
  175. SDL_assert(_this->first == NULL);
  176. SDL_assert(_this->last == NULL);
  177. SDL_assert(_this->num_devices == 0);
  178. SDL_free(_this);
  179. _this = NULL;
  180. }
  181. }
  182. #if SDL_USE_LIBUDEV
  183. static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
  184. const char* dev_path)
  185. {
  186. if (dev_path == NULL) {
  187. return;
  188. }
  189. switch(udev_event) {
  190. case SDL_UDEV_DEVICEADDED:
  191. if (udev_class & SDL_UDEV_DEVICE_TOUCHPAD) {
  192. udev_class |= SDL_UDEV_DEVICE_TOUCHSCREEN;
  193. }
  194. if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD | SDL_UDEV_DEVICE_TOUCHSCREEN)))
  195. return;
  196. if ((udev_class & SDL_UDEV_DEVICE_JOYSTICK))
  197. return;
  198. SDL_EVDEV_device_added(dev_path, udev_class);
  199. break;
  200. case SDL_UDEV_DEVICEREMOVED:
  201. SDL_EVDEV_device_removed(dev_path);
  202. break;
  203. default:
  204. break;
  205. }
  206. }
  207. #endif /* SDL_USE_LIBUDEV */
  208. void
  209. SDL_EVDEV_Poll(void)
  210. {
  211. struct input_event events[32];
  212. int i, j, len;
  213. SDL_evdevlist_item *item;
  214. SDL_Scancode scan_code;
  215. int mouse_button;
  216. SDL_Mouse *mouse;
  217. float norm_x, norm_y, norm_pressure;
  218. if (!_this) {
  219. return;
  220. }
  221. #if SDL_USE_LIBUDEV
  222. SDL_UDEV_Poll();
  223. #endif
  224. mouse = SDL_GetMouse();
  225. for (item = _this->first; item != NULL; item = item->next) {
  226. while ((len = read(item->fd, events, (sizeof events))) > 0) {
  227. len /= sizeof(events[0]);
  228. for (i = 0; i < len; ++i) {
  229. /* special handling for touchscreen, that should eventually be
  230. used for all devices */
  231. if (item->out_of_sync && item->is_touchscreen &&
  232. events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
  233. break;
  234. }
  235. switch (events[i].type) {
  236. case EV_KEY:
  237. if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
  238. mouse_button = events[i].code - BTN_MOUSE;
  239. if (events[i].value == 0) {
  240. SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
  241. } else if (events[i].value == 1) {
  242. SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
  243. }
  244. break;
  245. }
  246. /* BTH_TOUCH event value 1 indicates there is contact with
  247. a touchscreen or trackpad (earlist finger's current
  248. position is sent in EV_ABS ABS_X/ABS_Y, switching to
  249. next finger after earlist is released) */
  250. if (item->is_touchscreen && events[i].code == BTN_TOUCH) {
  251. if (item->touchscreen_data->max_slots == 1) {
  252. if (events[i].value)
  253. item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
  254. else
  255. item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_UP;
  256. }
  257. break;
  258. }
  259. /* Probably keyboard */
  260. scan_code = SDL_EVDEV_translate_keycode(events[i].code);
  261. if (scan_code != SDL_SCANCODE_UNKNOWN) {
  262. if (events[i].value == 0) {
  263. SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
  264. } else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) {
  265. SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
  266. }
  267. }
  268. SDL_EVDEV_kbd_keycode(_this->kbd, events[i].code, events[i].value);
  269. break;
  270. case EV_ABS:
  271. switch(events[i].code) {
  272. case ABS_MT_SLOT:
  273. if (!item->is_touchscreen) /* FIXME: temp hack */
  274. break;
  275. item->touchscreen_data->current_slot = events[i].value;
  276. break;
  277. case ABS_MT_TRACKING_ID:
  278. if (!item->is_touchscreen) /* FIXME: temp hack */
  279. break;
  280. if (events[i].value >= 0) {
  281. item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value;
  282. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
  283. } else {
  284. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
  285. }
  286. break;
  287. case ABS_MT_POSITION_X:
  288. if (!item->is_touchscreen) /* FIXME: temp hack */
  289. break;
  290. item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
  291. if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
  292. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
  293. }
  294. break;
  295. case ABS_MT_POSITION_Y:
  296. if (!item->is_touchscreen) /* FIXME: temp hack */
  297. break;
  298. item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
  299. if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
  300. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
  301. }
  302. break;
  303. case ABS_MT_PRESSURE:
  304. if (!item->is_touchscreen) /* FIXME: temp hack */
  305. break;
  306. item->touchscreen_data->slots[item->touchscreen_data->current_slot].pressure = events[i].value;
  307. if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
  308. item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
  309. }
  310. break;
  311. case ABS_X:
  312. if (item->is_touchscreen) {
  313. if (item->touchscreen_data->max_slots != 1)
  314. break;
  315. item->touchscreen_data->slots[0].x = events[i].value;
  316. } else if (!item->relative_mouse) {
  317. /* FIXME: Normalize to input device's reported input range (EVIOCGABS) */
  318. item->mouse_x = events[i].value;
  319. }
  320. break;
  321. case ABS_Y:
  322. if (item->is_touchscreen) {
  323. if (item->touchscreen_data->max_slots != 1)
  324. break;
  325. item->touchscreen_data->slots[0].y = events[i].value;
  326. } else if (!item->relative_mouse) {
  327. /* FIXME: Normalize to input device's reported input range (EVIOCGABS) */
  328. item->mouse_y = events[i].value;
  329. }
  330. break;
  331. default:
  332. break;
  333. }
  334. break;
  335. case EV_REL:
  336. switch(events[i].code) {
  337. case REL_X:
  338. if (item->relative_mouse)
  339. item->mouse_x += events[i].value;
  340. break;
  341. case REL_Y:
  342. if (item->relative_mouse)
  343. item->mouse_y += events[i].value;
  344. break;
  345. case REL_WHEEL:
  346. if (!item->high_res_wheel)
  347. item->mouse_wheel += events[i].value;
  348. break;
  349. case REL_WHEEL_HI_RES:
  350. SDL_assert(item->high_res_wheel);
  351. item->mouse_wheel += events[i].value;
  352. break;
  353. case REL_HWHEEL:
  354. if (!item->high_res_hwheel)
  355. item->mouse_hwheel += events[i].value;
  356. break;
  357. case REL_HWHEEL_HI_RES:
  358. SDL_assert(item->high_res_hwheel);
  359. item->mouse_hwheel += events[i].value;
  360. break;
  361. default:
  362. break;
  363. }
  364. break;
  365. case EV_SYN:
  366. switch (events[i].code) {
  367. case SYN_REPORT:
  368. /* Send mouse axis changes together to ensure consistency and reduce event processing overhead */
  369. if (item->mouse_x != 0 || item->mouse_y != 0) {
  370. SDL_SendMouseMotion(mouse->focus, mouse->mouseID, item->relative_mouse, item->mouse_x, item->mouse_y);
  371. item->mouse_x = item->mouse_y = 0;
  372. }
  373. if (item->mouse_wheel != 0 || item->mouse_hwheel != 0) {
  374. SDL_SendMouseWheel(mouse->focus, mouse->mouseID,
  375. item->mouse_hwheel / (item->high_res_hwheel ? 120.0f : 1.0f),
  376. item->mouse_wheel / (item->high_res_wheel ? 120.0f : 1.0f),
  377. SDL_MOUSEWHEEL_NORMAL);
  378. item->mouse_wheel = item->mouse_hwheel = 0;
  379. }
  380. if (!item->is_touchscreen) /* FIXME: temp hack */
  381. break;
  382. for(j = 0; j < item->touchscreen_data->max_slots; j++) {
  383. norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
  384. (float)item->touchscreen_data->range_x;
  385. norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
  386. (float)item->touchscreen_data->range_y;
  387. if (item->touchscreen_data->range_pressure > 0) {
  388. norm_pressure = (float)(item->touchscreen_data->slots[j].pressure - item->touchscreen_data->min_pressure) /
  389. (float)item->touchscreen_data->range_pressure;
  390. } else {
  391. /* This touchscreen does not support pressure */
  392. norm_pressure = 1.0f;
  393. }
  394. /* FIXME: the touch's window shouldn't be null, but
  395. * the coordinate space of touch positions needs to
  396. * be window-relative in that case. */
  397. switch(item->touchscreen_data->slots[j].delta) {
  398. case EVDEV_TOUCH_SLOTDELTA_DOWN:
  399. SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_TRUE, norm_x, norm_y, norm_pressure);
  400. item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
  401. break;
  402. case EVDEV_TOUCH_SLOTDELTA_UP:
  403. SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_FALSE, norm_x, norm_y, norm_pressure);
  404. item->touchscreen_data->slots[j].tracking_id = -1;
  405. item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
  406. break;
  407. case EVDEV_TOUCH_SLOTDELTA_MOVE:
  408. SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, norm_x, norm_y, norm_pressure);
  409. item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
  410. break;
  411. default:
  412. break;
  413. }
  414. }
  415. if (item->out_of_sync)
  416. item->out_of_sync = 0;
  417. break;
  418. case SYN_DROPPED:
  419. if (item->is_touchscreen)
  420. item->out_of_sync = 1;
  421. SDL_EVDEV_sync_device(item);
  422. break;
  423. default:
  424. break;
  425. }
  426. break;
  427. }
  428. }
  429. }
  430. }
  431. }
  432. static SDL_Scancode
  433. SDL_EVDEV_translate_keycode(int keycode)
  434. {
  435. SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
  436. if (keycode < SDL_arraysize(linux_scancode_table)) {
  437. scancode = linux_scancode_table[keycode];
  438. if (scancode == SDL_SCANCODE_UNKNOWN) {
  439. /* BTN_TOUCH is handled elsewhere, but we might still end up here if
  440. you get an unexpected BTN_TOUCH from something SDL believes is not
  441. a touch device. In this case, we'd rather not get a misleading
  442. SDL_Log message about an unknown key. */
  443. if (keycode != BTN_TOUCH) {
  444. SDL_Log("The key you just pressed is not recognized by SDL. To help "
  445. "get this fixed, please report this to the SDL forums/mailing list "
  446. "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
  447. }
  448. }
  449. }
  450. return scancode;
  451. }
  452. #ifdef SDL_USE_LIBUDEV
  453. static int
  454. SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
  455. {
  456. int ret, i;
  457. unsigned long xreq, yreq;
  458. char name[64];
  459. struct input_absinfo abs_info;
  460. if (!item->is_touchscreen)
  461. return 0;
  462. item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
  463. if (item->touchscreen_data == NULL)
  464. return SDL_OutOfMemory();
  465. ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
  466. if (ret < 0) {
  467. SDL_free(item->touchscreen_data);
  468. return SDL_SetError("Failed to get evdev touchscreen name");
  469. }
  470. item->touchscreen_data->name = SDL_strdup(name);
  471. if (item->touchscreen_data->name == NULL) {
  472. SDL_free(item->touchscreen_data);
  473. return SDL_OutOfMemory();
  474. }
  475. ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
  476. if (ret < 0) {
  477. SDL_free(item->touchscreen_data->name);
  478. SDL_free(item->touchscreen_data);
  479. return SDL_SetError("Failed to get evdev touchscreen limits");
  480. }
  481. if (abs_info.maximum == 0) {
  482. item->touchscreen_data->max_slots = 1;
  483. xreq = EVIOCGABS(ABS_X);
  484. yreq = EVIOCGABS(ABS_Y);
  485. } else {
  486. item->touchscreen_data->max_slots = abs_info.maximum + 1;
  487. xreq = EVIOCGABS(ABS_MT_POSITION_X);
  488. yreq = EVIOCGABS(ABS_MT_POSITION_Y);
  489. }
  490. ret = ioctl(item->fd, xreq, &abs_info);
  491. if (ret < 0) {
  492. SDL_free(item->touchscreen_data->name);
  493. SDL_free(item->touchscreen_data);
  494. return SDL_SetError("Failed to get evdev touchscreen limits");
  495. }
  496. item->touchscreen_data->min_x = abs_info.minimum;
  497. item->touchscreen_data->max_x = abs_info.maximum;
  498. item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
  499. ret = ioctl(item->fd, yreq, &abs_info);
  500. if (ret < 0) {
  501. SDL_free(item->touchscreen_data->name);
  502. SDL_free(item->touchscreen_data);
  503. return SDL_SetError("Failed to get evdev touchscreen limits");
  504. }
  505. item->touchscreen_data->min_y = abs_info.minimum;
  506. item->touchscreen_data->max_y = abs_info.maximum;
  507. item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
  508. ret = ioctl(item->fd, EVIOCGABS(ABS_MT_PRESSURE), &abs_info);
  509. if (ret < 0) {
  510. SDL_free(item->touchscreen_data->name);
  511. SDL_free(item->touchscreen_data);
  512. return SDL_SetError("Failed to get evdev touchscreen limits");
  513. }
  514. item->touchscreen_data->min_pressure = abs_info.minimum;
  515. item->touchscreen_data->max_pressure = abs_info.maximum;
  516. item->touchscreen_data->range_pressure = abs_info.maximum - abs_info.minimum;
  517. item->touchscreen_data->slots = SDL_calloc(
  518. item->touchscreen_data->max_slots,
  519. sizeof(*item->touchscreen_data->slots));
  520. if (item->touchscreen_data->slots == NULL) {
  521. SDL_free(item->touchscreen_data->name);
  522. SDL_free(item->touchscreen_data);
  523. return SDL_OutOfMemory();
  524. }
  525. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  526. item->touchscreen_data->slots[i].tracking_id = -1;
  527. }
  528. ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
  529. SDL_TOUCH_DEVICE_DIRECT,
  530. item->touchscreen_data->name);
  531. if (ret < 0) {
  532. SDL_free(item->touchscreen_data->slots);
  533. SDL_free(item->touchscreen_data->name);
  534. SDL_free(item->touchscreen_data);
  535. return ret;
  536. }
  537. return 0;
  538. }
  539. #endif /* SDL_USE_LIBUDEV */
  540. static void
  541. SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
  542. if (!item->is_touchscreen)
  543. return;
  544. SDL_DelTouch(item->fd);
  545. SDL_free(item->touchscreen_data->slots);
  546. SDL_free(item->touchscreen_data->name);
  547. SDL_free(item->touchscreen_data);
  548. }
  549. static void
  550. SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
  551. {
  552. #ifdef EVIOCGMTSLOTS
  553. int i, ret;
  554. struct input_absinfo abs_info;
  555. /*
  556. * struct input_mt_request_layout {
  557. * __u32 code;
  558. * __s32 values[num_slots];
  559. * };
  560. *
  561. * this is the structure we're trying to emulate
  562. */
  563. Uint32* mt_req_code;
  564. Sint32* mt_req_values;
  565. size_t mt_req_size;
  566. /* TODO: sync devices other than touchscreen */
  567. if (!item->is_touchscreen)
  568. return;
  569. mt_req_size = sizeof(*mt_req_code) +
  570. sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
  571. mt_req_code = SDL_calloc(1, mt_req_size);
  572. if (mt_req_code == NULL) {
  573. return;
  574. }
  575. mt_req_values = (Sint32*)mt_req_code + 1;
  576. *mt_req_code = ABS_MT_TRACKING_ID;
  577. ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
  578. if (ret < 0) {
  579. SDL_free(mt_req_code);
  580. return;
  581. }
  582. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  583. /*
  584. * This doesn't account for the very edge case of the user removing their
  585. * finger and replacing it on the screen during the time we're out of sync,
  586. * which'll mean that we're not going from down -> up or up -> down, we're
  587. * going from down -> down but with a different tracking id, meaning we'd
  588. * have to tell SDL of the two events, but since we wait till SYN_REPORT in
  589. * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
  590. * allow it. Lets just pray to God it doesn't happen.
  591. */
  592. if (item->touchscreen_data->slots[i].tracking_id < 0 &&
  593. mt_req_values[i] >= 0) {
  594. item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
  595. item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
  596. } else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
  597. mt_req_values[i] < 0) {
  598. item->touchscreen_data->slots[i].tracking_id = -1;
  599. item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
  600. }
  601. }
  602. *mt_req_code = ABS_MT_POSITION_X;
  603. ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
  604. if (ret < 0) {
  605. SDL_free(mt_req_code);
  606. return;
  607. }
  608. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  609. if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
  610. item->touchscreen_data->slots[i].x != mt_req_values[i]) {
  611. item->touchscreen_data->slots[i].x = mt_req_values[i];
  612. if (item->touchscreen_data->slots[i].delta ==
  613. EVDEV_TOUCH_SLOTDELTA_NONE) {
  614. item->touchscreen_data->slots[i].delta =
  615. EVDEV_TOUCH_SLOTDELTA_MOVE;
  616. }
  617. }
  618. }
  619. *mt_req_code = ABS_MT_POSITION_Y;
  620. ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
  621. if (ret < 0) {
  622. SDL_free(mt_req_code);
  623. return;
  624. }
  625. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  626. if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
  627. item->touchscreen_data->slots[i].y != mt_req_values[i]) {
  628. item->touchscreen_data->slots[i].y = mt_req_values[i];
  629. if (item->touchscreen_data->slots[i].delta ==
  630. EVDEV_TOUCH_SLOTDELTA_NONE) {
  631. item->touchscreen_data->slots[i].delta =
  632. EVDEV_TOUCH_SLOTDELTA_MOVE;
  633. }
  634. }
  635. }
  636. *mt_req_code = ABS_MT_PRESSURE;
  637. ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
  638. if (ret < 0) {
  639. SDL_free(mt_req_code);
  640. return;
  641. }
  642. for(i = 0; i < item->touchscreen_data->max_slots; i++) {
  643. if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
  644. item->touchscreen_data->slots[i].pressure != mt_req_values[i]) {
  645. item->touchscreen_data->slots[i].pressure = mt_req_values[i];
  646. if (item->touchscreen_data->slots[i].delta ==
  647. EVDEV_TOUCH_SLOTDELTA_NONE) {
  648. item->touchscreen_data->slots[i].delta =
  649. EVDEV_TOUCH_SLOTDELTA_MOVE;
  650. }
  651. }
  652. }
  653. ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
  654. if (ret < 0) {
  655. SDL_free(mt_req_code);
  656. return;
  657. }
  658. item->touchscreen_data->current_slot = abs_info.value;
  659. SDL_free(mt_req_code);
  660. #endif /* EVIOCGMTSLOTS */
  661. }
  662. #if SDL_USE_LIBUDEV
  663. static int
  664. SDL_EVDEV_device_added(const char *dev_path, int udev_class)
  665. {
  666. int ret;
  667. SDL_evdevlist_item *item;
  668. unsigned long relbit[NBITS(REL_MAX)] = { 0 };
  669. /* Check to make sure it's not already in list. */
  670. for (item = _this->first; item != NULL; item = item->next) {
  671. if (SDL_strcmp(dev_path, item->path) == 0) {
  672. return -1; /* already have this one */
  673. }
  674. }
  675. item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
  676. if (item == NULL) {
  677. return SDL_OutOfMemory();
  678. }
  679. item->fd = open(dev_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
  680. if (item->fd < 0) {
  681. SDL_free(item);
  682. return SDL_SetError("Unable to open %s", dev_path);
  683. }
  684. item->path = SDL_strdup(dev_path);
  685. if (item->path == NULL) {
  686. close(item->fd);
  687. SDL_free(item);
  688. return SDL_OutOfMemory();
  689. }
  690. if (ioctl(item->fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) {
  691. item->relative_mouse = test_bit(REL_X, relbit) && test_bit(REL_Y, relbit);
  692. item->high_res_wheel = test_bit(REL_WHEEL_HI_RES, relbit);
  693. item->high_res_hwheel = test_bit(REL_HWHEEL_HI_RES, relbit);
  694. }
  695. if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
  696. item->is_touchscreen = 1;
  697. if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
  698. close(item->fd);
  699. SDL_free(item->path);
  700. SDL_free(item);
  701. return ret;
  702. }
  703. }
  704. if (_this->last == NULL) {
  705. _this->first = _this->last = item;
  706. } else {
  707. _this->last->next = item;
  708. _this->last = item;
  709. }
  710. SDL_EVDEV_sync_device(item);
  711. return _this->num_devices++;
  712. }
  713. #endif /* SDL_USE_LIBUDEV */
  714. static int
  715. SDL_EVDEV_device_removed(const char *dev_path)
  716. {
  717. SDL_evdevlist_item *item;
  718. SDL_evdevlist_item *prev = NULL;
  719. for (item = _this->first; item != NULL; item = item->next) {
  720. /* found it, remove it. */
  721. if (SDL_strcmp(dev_path, item->path) == 0) {
  722. if (prev != NULL) {
  723. prev->next = item->next;
  724. } else {
  725. SDL_assert(_this->first == item);
  726. _this->first = item->next;
  727. }
  728. if (item == _this->last) {
  729. _this->last = prev;
  730. }
  731. if (item->is_touchscreen) {
  732. SDL_EVDEV_destroy_touchscreen(item);
  733. }
  734. close(item->fd);
  735. SDL_free(item->path);
  736. SDL_free(item);
  737. _this->num_devices--;
  738. return 0;
  739. }
  740. prev = item;
  741. }
  742. return -1;
  743. }
  744. #endif /* SDL_INPUT_LINUXEV */
  745. /* vi: set ts=4 sw=4 expandtab: */