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