21 #include "../../SDL_internal.h"
23 #ifdef SDL_INPUT_LINUXEV
38 #include <sys/ioctl.h>
39 #include <linux/input.h>
44 #include "../../events/SDL_events_c.h"
45 #include "../../events/scancodes_linux.h"
46 #include "../../core/linux/SDL_evdev_capabilities.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--;
#define SDL_assert(condition)
#define SDL_OutOfMemory()
SDL_EVDEV_keyboard_state * SDL_EVDEV_kbd_init(void)
void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
SDL_Mouse * SDL_GetMouse(void)
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
#define SDL_BUTTON_MIDDLE
GLint GLint GLint GLint GLint GLint y
GLint GLint GLint GLint GLint x
GLuint GLuint GLsizei GLenum type
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLuint const GLchar * name
GLsizei const GLchar *const * path
GLsizei const GLfloat * value
SDL_Scancode
The SDL keyboard scancode representation.
#define SDL_arraysize(array)
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_bool down, float x, float y, float pressure)
void SDL_DelTouch(SDL_TouchID id)
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, float x, float y, float pressure)
@ SDL_TOUCH_DEVICE_DIRECT
static SDL_VideoDevice * _this
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)
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)
EGLDeviceEXT EGLint * num_devices
static SDL_Scancode const linux_scancode_table[]
int(* SetRelativeMouseMode)(SDL_bool enabled)
static SDL_Event events[EVENT_BUF_SIZE]