21 #include "../../SDL_internal.h"
23 #ifdef SDL_INPUT_LINUXEV
38 #include <sys/ioctl.h>
39 #include <linux/input.h>
45 #include "../../events/SDL_events_c.h"
46 #include "../../events/scancodes_linux.h"
47 #include "../../core/linux/SDL_udev.h"
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
61 typedef struct SDL_evdevlist_item
76 int min_x, max_x, range_x;
77 int min_y, max_y, range_y;
78 int min_pressure, max_pressure, range_pressure;
84 EVDEV_TOUCH_SLOTDELTA_NONE = 0,
85 EVDEV_TOUCH_SLOTDELTA_DOWN,
86 EVDEV_TOUCH_SLOTDELTA_UP,
87 EVDEV_TOUCH_SLOTDELTA_MOVE
95 struct SDL_evdevlist_item *next;
98 typedef struct SDL_EVDEV_PrivateData
102 SDL_evdevlist_item *
first;
103 SDL_evdevlist_item *last;
105 } SDL_EVDEV_PrivateData;
108 #define _THIS SDL_EVDEV_PrivateData *_this
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);
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);
121 static Uint8 EVDEV_MouseButtons[] = {
150 if (SDL_UDEV_Init() < 0) {
157 if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
175 _this->ref_count += 1;
187 _this->ref_count -= 1;
189 if (
_this->ref_count < 1) {
191 SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
199 SDL_EVDEV_device_removed(
_this->first->path);
212 static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event,
int udev_class,
213 const char* dev_path)
215 if (dev_path ==
NULL) {
220 case SDL_UDEV_DEVICEADDED:
221 if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
222 SDL_UDEV_DEVICE_TOUCHSCREEN)))
225 SDL_EVDEV_device_added(dev_path, udev_class);
227 case SDL_UDEV_DEVICEREMOVED:
228 SDL_EVDEV_device_removed(dev_path);
239 struct input_event
events[32];
241 SDL_evdevlist_item *item;
245 float norm_x, norm_y, norm_pressure;
257 for (item =
_this->first; item !=
NULL; item = item->next) {
260 for (
i = 0;
i <
len; ++
i) {
263 if (item->out_of_sync && item->is_touchscreen &&
271 mouse_button =
events[
i].code - BTN_MOUSE;
284 if (item->is_touchscreen &&
events[
i].code == BTN_TOUCH) {
285 if (item->touchscreen_data->max_slots == 1) {
287 item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
289 item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_UP;
295 scan_code = SDL_EVDEV_translate_keycode(
events[
i].code);
308 if (!item->is_touchscreen)
310 item->touchscreen_data->current_slot =
events[
i].value;
312 case ABS_MT_TRACKING_ID:
313 if (!item->is_touchscreen)
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;
319 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
322 case ABS_MT_POSITION_X:
323 if (!item->is_touchscreen)
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;
330 case ABS_MT_POSITION_Y:
331 if (!item->is_touchscreen)
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;
338 case ABS_MT_PRESSURE:
339 if (!item->is_touchscreen)
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;
347 if (item->is_touchscreen) {
348 if (item->touchscreen_data->max_slots != 1)
350 item->touchscreen_data->slots[0].x =
events[
i].value;
355 if (item->is_touchscreen) {
356 if (item->touchscreen_data->max_slots != 1)
358 item->touchscreen_data->slots[0].y =
events[
i].value;
387 if (!item->is_touchscreen)
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;
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;
401 norm_pressure = 1.0f;
407 switch(item->touchscreen_data->slots[
j].delta) {
408 case EVDEV_TOUCH_SLOTDELTA_DOWN:
410 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
412 case EVDEV_TOUCH_SLOTDELTA_UP:
414 item->touchscreen_data->slots[
j].tracking_id = -1;
415 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
417 case EVDEV_TOUCH_SLOTDELTA_MOVE:
419 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
426 if (item->out_of_sync)
427 item->out_of_sync = 0;
430 if (item->is_touchscreen)
431 item->out_of_sync = 1;
432 SDL_EVDEV_sync_device(item);
445 SDL_EVDEV_translate_keycode(
int keycode)
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);
468 #ifdef SDL_USE_LIBUDEV
470 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
473 unsigned long xreq, yreq;
475 struct input_absinfo abs_info;
477 if (!item->is_touchscreen)
480 item->touchscreen_data =
SDL_calloc(1,
sizeof(*item->touchscreen_data));
481 if (item->touchscreen_data ==
NULL)
484 ret = ioctl(item->fd, EVIOCGNAME(
sizeof(
name)),
name);
487 return SDL_SetError(
"Failed to get evdev touchscreen name");
491 if (item->touchscreen_data->name ==
NULL) {
496 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
498 SDL_free(item->touchscreen_data->name);
500 return SDL_SetError(
"Failed to get evdev touchscreen limits");
503 if (abs_info.maximum == 0) {
504 item->touchscreen_data->max_slots = 1;
505 xreq = EVIOCGABS(ABS_X);
506 yreq = EVIOCGABS(ABS_Y);
508 item->touchscreen_data->max_slots = abs_info.maximum + 1;
509 xreq = EVIOCGABS(ABS_MT_POSITION_X);
510 yreq = EVIOCGABS(ABS_MT_POSITION_Y);
513 ret = ioctl(item->fd, xreq, &abs_info);
515 SDL_free(item->touchscreen_data->name);
517 return SDL_SetError(
"Failed to get evdev touchscreen limits");
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;
523 ret = ioctl(item->fd, yreq, &abs_info);
525 SDL_free(item->touchscreen_data->name);
527 return SDL_SetError(
"Failed to get evdev touchscreen limits");
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;
533 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_PRESSURE), &abs_info);
535 SDL_free(item->touchscreen_data->name);
537 return SDL_SetError(
"Failed to get evdev touchscreen limits");
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;
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);
552 for(
i = 0;
i < item->touchscreen_data->max_slots;
i++) {
553 item->touchscreen_data->slots[
i].tracking_id = -1;
558 item->touchscreen_data->name);
560 SDL_free(item->touchscreen_data->slots);
561 SDL_free(item->touchscreen_data->name);
571 SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
572 if (!item->is_touchscreen)
576 SDL_free(item->touchscreen_data->slots);
577 SDL_free(item->touchscreen_data->name);
582 SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
586 struct input_absinfo abs_info;
600 if (!item->is_touchscreen)
603 mt_req_size =
sizeof(*mt_req_code) +
604 sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
607 if (mt_req_code ==
NULL) {
611 mt_req_values = (
Sint32*)mt_req_code + 1;
613 *mt_req_code = ABS_MT_TRACKING_ID;
614 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
619 for(
i = 0;
i < item->touchscreen_data->max_slots;
i++) {
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;
640 *mt_req_code = ABS_MT_POSITION_X;
641 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
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;
658 *mt_req_code = ABS_MT_POSITION_Y;
659 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
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;
676 *mt_req_code = ABS_MT_PRESSURE;
677 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
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;
694 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
699 item->touchscreen_data->current_slot = abs_info.value;
708 SDL_EVDEV_device_added(
const char *dev_path,
int udev_class)
711 SDL_evdevlist_item *item;
714 for (item =
_this->first; item !=
NULL; item = item->next) {
720 item = (SDL_evdevlist_item *)
SDL_calloc(1,
sizeof (SDL_evdevlist_item));
725 item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
732 if (item->path ==
NULL) {
738 if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
739 item->is_touchscreen = 1;
741 if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
751 _this->last->next = item;
755 SDL_EVDEV_sync_device(item);
757 return _this->num_devices++;
762 SDL_EVDEV_device_removed(
const char *dev_path)
764 SDL_evdevlist_item *item;
765 SDL_evdevlist_item *prev =
NULL;
767 for (item =
_this->first; item !=
NULL; item = item->next) {
771 prev->next = item->next;
774 _this->first = item->next;
776 if (item ==
_this->last) {
779 if (item->is_touchscreen) {
780 SDL_EVDEV_destroy_touchscreen(item);
785 _this->num_devices--;