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