SDL  2.0
SDL_evdev.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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  /* FIXME: the touch's window shouldn't be null, but
405  * the coordinate space of touch positions needs to
406  * be window-relative in that case. */
407  switch(item->touchscreen_data->slots[j].delta) {
408  case EVDEV_TOUCH_SLOTDELTA_DOWN:
409  SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_TRUE, norm_x, norm_y, norm_pressure);
410  item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
411  break;
412  case EVDEV_TOUCH_SLOTDELTA_UP:
413  SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_FALSE, norm_x, norm_y, norm_pressure);
414  item->touchscreen_data->slots[j].tracking_id = -1;
415  item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
416  break;
417  case EVDEV_TOUCH_SLOTDELTA_MOVE:
418  SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, norm_x, norm_y, norm_pressure);
419  item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
420  break;
421  default:
422  break;
423  }
424  }
425 
426  if (item->out_of_sync)
427  item->out_of_sync = 0;
428  break;
429  case SYN_DROPPED:
430  if (item->is_touchscreen)
431  item->out_of_sync = 1;
432  SDL_EVDEV_sync_device(item);
433  break;
434  default:
435  break;
436  }
437  break;
438  }
439  }
440  }
441  }
442 }
443 
444 static SDL_Scancode
445 SDL_EVDEV_translate_keycode(int keycode)
446 {
448 
449  if (keycode < SDL_arraysize(linux_scancode_table)) {
450  scancode = linux_scancode_table[keycode];
451 
452  if (scancode == SDL_SCANCODE_UNKNOWN) {
453  /* BTN_TOUCH is handled elsewhere, but we might still end up here if
454  you get an unexpected BTN_TOUCH from something SDL believes is not
455  a touch device. In this case, we'd rather not get a misleading
456  SDL_Log message about an unknown key. */
457  if (keycode != BTN_TOUCH) {
458  SDL_Log("The key you just pressed is not recognized by SDL. To help "
459  "get this fixed, please report this to the SDL forums/mailing list "
460  "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
461  }
462  }
463  }
464 
465  return scancode;
466 }
467 
468 #ifdef SDL_USE_LIBUDEV
469 static int
470 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
471 {
472  int ret, i;
473  unsigned long xreq, yreq;
474  char name[64];
475  struct input_absinfo abs_info;
476 
477  if (!item->is_touchscreen)
478  return 0;
479 
480  item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
481  if (item->touchscreen_data == NULL)
482  return SDL_OutOfMemory();
483 
484  ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
485  if (ret < 0) {
486  SDL_free(item->touchscreen_data);
487  return SDL_SetError("Failed to get evdev touchscreen name");
488  }
489 
490  item->touchscreen_data->name = SDL_strdup(name);
491  if (item->touchscreen_data->name == NULL) {
492  SDL_free(item->touchscreen_data);
493  return SDL_OutOfMemory();
494  }
495 
496  ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
497  if (ret < 0) {
498  SDL_free(item->touchscreen_data->name);
499  SDL_free(item->touchscreen_data);
500  return SDL_SetError("Failed to get evdev touchscreen limits");
501  }
502 
503  if (abs_info.maximum == 0) {
504  item->touchscreen_data->max_slots = 1;
505  xreq = EVIOCGABS(ABS_X);
506  yreq = EVIOCGABS(ABS_Y);
507  } else {
508  item->touchscreen_data->max_slots = abs_info.maximum + 1;
509  xreq = EVIOCGABS(ABS_MT_POSITION_X);
510  yreq = EVIOCGABS(ABS_MT_POSITION_Y);
511  }
512 
513  ret = ioctl(item->fd, xreq, &abs_info);
514  if (ret < 0) {
515  SDL_free(item->touchscreen_data->name);
516  SDL_free(item->touchscreen_data);
517  return SDL_SetError("Failed to get evdev touchscreen limits");
518  }
519  item->touchscreen_data->min_x = abs_info.minimum;
520  item->touchscreen_data->max_x = abs_info.maximum;
521  item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
522 
523  ret = ioctl(item->fd, yreq, &abs_info);
524  if (ret < 0) {
525  SDL_free(item->touchscreen_data->name);
526  SDL_free(item->touchscreen_data);
527  return SDL_SetError("Failed to get evdev touchscreen limits");
528  }
529  item->touchscreen_data->min_y = abs_info.minimum;
530  item->touchscreen_data->max_y = abs_info.maximum;
531  item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
532 
533  ret = ioctl(item->fd, EVIOCGABS(ABS_MT_PRESSURE), &abs_info);
534  if (ret < 0) {
535  SDL_free(item->touchscreen_data->name);
536  SDL_free(item->touchscreen_data);
537  return SDL_SetError("Failed to get evdev touchscreen limits");
538  }
539  item->touchscreen_data->min_pressure = abs_info.minimum;
540  item->touchscreen_data->max_pressure = abs_info.maximum;
541  item->touchscreen_data->range_pressure = abs_info.maximum - abs_info.minimum;
542 
543  item->touchscreen_data->slots = SDL_calloc(
544  item->touchscreen_data->max_slots,
545  sizeof(*item->touchscreen_data->slots));
546  if (item->touchscreen_data->slots == NULL) {
547  SDL_free(item->touchscreen_data->name);
548  SDL_free(item->touchscreen_data);
549  return SDL_OutOfMemory();
550  }
551 
552  for(i = 0; i < item->touchscreen_data->max_slots; i++) {
553  item->touchscreen_data->slots[i].tracking_id = -1;
554  }
555 
556  ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
558  item->touchscreen_data->name);
559  if (ret < 0) {
560  SDL_free(item->touchscreen_data->slots);
561  SDL_free(item->touchscreen_data->name);
562  SDL_free(item->touchscreen_data);
563  return ret;
564  }
565 
566  return 0;
567 }
568 #endif /* SDL_USE_LIBUDEV */
569 
570 static void
571 SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
572  if (!item->is_touchscreen)
573  return;
574 
575  SDL_DelTouch(item->fd);
576  SDL_free(item->touchscreen_data->slots);
577  SDL_free(item->touchscreen_data->name);
578  SDL_free(item->touchscreen_data);
579 }
580 
581 static void
582 SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
583 {
584 #ifdef EVIOCGMTSLOTS
585  int i, ret;
586  struct input_absinfo abs_info;
587  /*
588  * struct input_mt_request_layout {
589  * __u32 code;
590  * __s32 values[num_slots];
591  * };
592  *
593  * this is the structure we're trying to emulate
594  */
595  Uint32* mt_req_code;
596  Sint32* mt_req_values;
597  size_t mt_req_size;
598 
599  /* TODO: sync devices other than touchscreen */
600  if (!item->is_touchscreen)
601  return;
602 
603  mt_req_size = sizeof(*mt_req_code) +
604  sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
605 
606  mt_req_code = SDL_calloc(1, mt_req_size);
607  if (mt_req_code == NULL) {
608  return;
609  }
610 
611  mt_req_values = (Sint32*)mt_req_code + 1;
612 
613  *mt_req_code = ABS_MT_TRACKING_ID;
614  ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
615  if (ret < 0) {
616  SDL_free(mt_req_code);
617  return;
618  }
619  for(i = 0; i < item->touchscreen_data->max_slots; i++) {
620  /*
621  * This doesn't account for the very edge case of the user removing their
622  * finger and replacing it on the screen during the time we're out of sync,
623  * which'll mean that we're not going from down -> up or up -> down, we're
624  * going from down -> down but with a different tracking id, meaning we'd
625  * have to tell SDL of the two events, but since we wait till SYN_REPORT in
626  * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
627  * allow it. Lets just pray to God it doesn't happen.
628  */
629  if (item->touchscreen_data->slots[i].tracking_id < 0 &&
630  mt_req_values[i] >= 0) {
631  item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
632  item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
633  } else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
634  mt_req_values[i] < 0) {
635  item->touchscreen_data->slots[i].tracking_id = -1;
636  item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
637  }
638  }
639 
640  *mt_req_code = ABS_MT_POSITION_X;
641  ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
642  if (ret < 0) {
643  SDL_free(mt_req_code);
644  return;
645  }
646  for(i = 0; i < item->touchscreen_data->max_slots; i++) {
647  if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
648  item->touchscreen_data->slots[i].x != mt_req_values[i]) {
649  item->touchscreen_data->slots[i].x = mt_req_values[i];
650  if (item->touchscreen_data->slots[i].delta ==
651  EVDEV_TOUCH_SLOTDELTA_NONE) {
652  item->touchscreen_data->slots[i].delta =
653  EVDEV_TOUCH_SLOTDELTA_MOVE;
654  }
655  }
656  }
657 
658  *mt_req_code = ABS_MT_POSITION_Y;
659  ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
660  if (ret < 0) {
661  SDL_free(mt_req_code);
662  return;
663  }
664  for(i = 0; i < item->touchscreen_data->max_slots; i++) {
665  if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
666  item->touchscreen_data->slots[i].y != mt_req_values[i]) {
667  item->touchscreen_data->slots[i].y = mt_req_values[i];
668  if (item->touchscreen_data->slots[i].delta ==
669  EVDEV_TOUCH_SLOTDELTA_NONE) {
670  item->touchscreen_data->slots[i].delta =
671  EVDEV_TOUCH_SLOTDELTA_MOVE;
672  }
673  }
674  }
675 
676  *mt_req_code = ABS_MT_PRESSURE;
677  ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
678  if (ret < 0) {
679  SDL_free(mt_req_code);
680  return;
681  }
682  for(i = 0; i < item->touchscreen_data->max_slots; i++) {
683  if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
684  item->touchscreen_data->slots[i].pressure != mt_req_values[i]) {
685  item->touchscreen_data->slots[i].pressure = mt_req_values[i];
686  if (item->touchscreen_data->slots[i].delta ==
687  EVDEV_TOUCH_SLOTDELTA_NONE) {
688  item->touchscreen_data->slots[i].delta =
689  EVDEV_TOUCH_SLOTDELTA_MOVE;
690  }
691  }
692  }
693 
694  ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
695  if (ret < 0) {
696  SDL_free(mt_req_code);
697  return;
698  }
699  item->touchscreen_data->current_slot = abs_info.value;
700 
701  SDL_free(mt_req_code);
702 
703 #endif /* EVIOCGMTSLOTS */
704 }
705 
706 #if SDL_USE_LIBUDEV
707 static int
708 SDL_EVDEV_device_added(const char *dev_path, int udev_class)
709 {
710  int ret;
711  SDL_evdevlist_item *item;
712 
713  /* Check to make sure it's not already in list. */
714  for (item = _this->first; item != NULL; item = item->next) {
715  if (SDL_strcmp(dev_path, item->path) == 0) {
716  return -1; /* already have this one */
717  }
718  }
719 
720  item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
721  if (item == NULL) {
722  return SDL_OutOfMemory();
723  }
724 
725  item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
726  if (item->fd < 0) {
727  SDL_free(item);
728  return SDL_SetError("Unable to open %s", dev_path);
729  }
730 
731  item->path = SDL_strdup(dev_path);
732  if (item->path == NULL) {
733  close(item->fd);
734  SDL_free(item);
735  return SDL_OutOfMemory();
736  }
737 
738  if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
739  item->is_touchscreen = 1;
740 
741  if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
742  close(item->fd);
743  SDL_free(item);
744  return ret;
745  }
746  }
747 
748  if (_this->last == NULL) {
749  _this->first = _this->last = item;
750  } else {
751  _this->last->next = item;
752  _this->last = item;
753  }
754 
755  SDL_EVDEV_sync_device(item);
756 
757  return _this->num_devices++;
758 }
759 #endif /* SDL_USE_LIBUDEV */
760 
761 static int
762 SDL_EVDEV_device_removed(const char *dev_path)
763 {
764  SDL_evdevlist_item *item;
765  SDL_evdevlist_item *prev = NULL;
766 
767  for (item = _this->first; item != NULL; item = item->next) {
768  /* found it, remove it. */
769  if (SDL_strcmp(dev_path, item->path) == 0) {
770  if (prev != NULL) {
771  prev->next = item->next;
772  } else {
773  SDL_assert(_this->first == item);
774  _this->first = item->next;
775  }
776  if (item == _this->last) {
777  _this->last = prev;
778  }
779  if (item->is_touchscreen) {
780  SDL_EVDEV_destroy_touchscreen(item);
781  }
782  close(item->fd);
783  SDL_free(item->path);
784  SDL_free(item);
785  _this->num_devices--;
786  return 0;
787  }
788  prev = item;
789  }
790 
791  return -1;
792 }
793 
794 
795 #endif /* SDL_INPUT_LINUXEV */
796 
797 /* vi: set ts=4 sw=4 expandtab: */
SDL.h
SDL_GetMouse
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:170
SDL_TOUCH_DEVICE_DIRECT
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
SDL_Event::type
Uint32 type
Definition: SDL_events.h:560
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
Sint32
int32_t Sint32
Definition: SDL_stdinc.h:197
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:831
NULL
#define NULL
Definition: begin_code.h:167
SDL_BUTTON_RIGHT
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
SDL_SendTouch
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
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_Mouse::SetRelativeMouseMode
int(* SetRelativeMouseMode)(SDL_bool enabled)
Definition: SDL_mouse_c.h:67
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_endian.h
path
GLsizei const GLchar *const * path
Definition: SDL_opengl_glext.h:3733
SDL_EVDEV_keyboard_state
struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state
Definition: SDL_evdev_kbd.h:26
SDL_RELEASED
#define SDL_RELEASED
Definition: SDL_events.h:49
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:2929
SDL_AddTouch
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
_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:825
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
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:293
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_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_DelTouch
void SDL_DelTouch(SDL_TouchID id)
Definition: SDL_touch.c:441
SDL_EVDEV_kbd_quit
void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
Definition: SDL_evdev_kbd.c:836
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:600
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:371
events
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:39
SDL_Mouse::x
int x
Definition: SDL_mouse_c.h:78
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:701
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_SendTouchMotion
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, float x, float y, float pressure)
Definition: SDL_touch.c:356
SDL_strdup
#define SDL_strdup
Definition: SDL_dynapi_overrides.h:397
SDL_Mouse::mouseID
SDL_MouseID mouseID
Definition: SDL_mouse_c.h:76
enabled
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: SDL_opengl_glext.h:2482
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_MOUSEWHEEL_NORMAL
@ SDL_MOUSEWHEEL_NORMAL
Definition: SDL_mouse.h:68
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_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:594