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