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
60 typedef struct SDL_evdevlist_item
75 int min_x, max_x, range_x;
76 int min_y, max_y, range_y;
82 EVDEV_TOUCH_SLOTDELTA_NONE = 0,
83 EVDEV_TOUCH_SLOTDELTA_DOWN,
84 EVDEV_TOUCH_SLOTDELTA_UP,
85 EVDEV_TOUCH_SLOTDELTA_MOVE
92 struct SDL_evdevlist_item *next;
95 typedef struct SDL_EVDEV_PrivateData
99 SDL_evdevlist_item *
first;
100 SDL_evdevlist_item *last;
102 } SDL_EVDEV_PrivateData;
105 #define _THIS SDL_EVDEV_PrivateData *_this
108 static SDL_Scancode SDL_EVDEV_translate_keycode(
int keycode);
109 static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
110 static int SDL_EVDEV_device_removed(
const char *dev_path);
113 static int SDL_EVDEV_device_added(
const char *dev_path,
int udev_class);
114 static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
115 const char *dev_path);
118 static Uint8 EVDEV_MouseButtons[] = {
139 if (SDL_UDEV_Init() < 0) {
146 if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
162 _this->ref_count += 1;
174 _this->ref_count -= 1;
176 if (
_this->ref_count < 1) {
178 SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
186 SDL_EVDEV_device_removed(
_this->first->path);
199 static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event,
int udev_class,
200 const char* dev_path)
202 if (dev_path ==
NULL) {
207 case SDL_UDEV_DEVICEADDED:
208 if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
209 SDL_UDEV_DEVICE_TOUCHSCREEN)))
212 SDL_EVDEV_device_added(dev_path, udev_class);
214 case SDL_UDEV_DEVICEREMOVED:
215 SDL_EVDEV_device_removed(dev_path);
226 struct input_event
events[32];
228 SDL_evdevlist_item *item;
232 float norm_x, norm_y;
244 for (item =
_this->first; item !=
NULL; item = item->next) {
245 while ((len = read(item->fd,
events, (
sizeof events))) > 0) {
247 for (i = 0; i <
len; ++
i) {
250 if (item->out_of_sync && item->is_touchscreen &&
258 mouse_button =
events[
i].code - BTN_MOUSE;
268 scan_code = SDL_EVDEV_translate_keycode(
events[i].code);
281 if (!item->is_touchscreen)
283 item->touchscreen_data->current_slot =
events[
i].value;
285 case ABS_MT_TRACKING_ID:
286 if (!item->is_touchscreen)
289 item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id =
events[
i].value;
290 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
292 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
295 case ABS_MT_POSITION_X:
296 if (!item->is_touchscreen)
298 item->touchscreen_data->slots[item->touchscreen_data->current_slot].x =
events[
i].value;
299 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
300 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
303 case ABS_MT_POSITION_Y:
304 if (!item->is_touchscreen)
306 item->touchscreen_data->slots[item->touchscreen_data->current_slot].y =
events[
i].value;
307 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
308 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
312 if (item->is_touchscreen)
317 if (item->is_touchscreen)
346 if (!item->is_touchscreen)
349 for(j = 0; j < item->touchscreen_data->max_slots; j++) {
350 norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
351 (float)item->touchscreen_data->range_x;
352 norm_y = (
float)(item->touchscreen_data->slots[
j].y - item->touchscreen_data->min_y) /
353 (
float)item->touchscreen_data->range_y;
355 switch(item->touchscreen_data->slots[j].delta) {
356 case EVDEV_TOUCH_SLOTDELTA_DOWN:
357 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id,
SDL_TRUE, norm_x, norm_y, 1.0f);
358 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
360 case EVDEV_TOUCH_SLOTDELTA_UP:
362 item->touchscreen_data->slots[
j].tracking_id = -1;
363 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
365 case EVDEV_TOUCH_SLOTDELTA_MOVE:
366 SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
367 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
374 if (item->out_of_sync)
375 item->out_of_sync = 0;
378 if (item->is_touchscreen)
379 item->out_of_sync = 1;
380 SDL_EVDEV_sync_device(item);
393 SDL_EVDEV_translate_keycode(
int keycode)
401 SDL_Log(
"The key you just pressed is not recognized by SDL. To help "
402 "get this fixed, please report this to the SDL forums/mailing list "
403 "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
409 #ifdef SDL_USE_LIBUDEV
411 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
415 struct input_absinfo abs_info;
417 if (!item->is_touchscreen)
420 item->touchscreen_data =
SDL_calloc(1,
sizeof(*item->touchscreen_data));
421 if (item->touchscreen_data ==
NULL)
424 ret = ioctl(item->fd, EVIOCGNAME(
sizeof(name)), name);
427 return SDL_SetError(
"Failed to get evdev touchscreen name");
430 item->touchscreen_data->name =
SDL_strdup(name);
431 if (item->touchscreen_data->name ==
NULL) {
436 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
438 SDL_free(item->touchscreen_data->name);
440 return SDL_SetError(
"Failed to get evdev touchscreen limits");
442 item->touchscreen_data->min_x = abs_info.minimum;
443 item->touchscreen_data->max_x = abs_info.maximum;
444 item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
446 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
448 SDL_free(item->touchscreen_data->name);
450 return SDL_SetError(
"Failed to get evdev touchscreen limits");
452 item->touchscreen_data->min_y = abs_info.minimum;
453 item->touchscreen_data->max_y = abs_info.maximum;
454 item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
456 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
458 SDL_free(item->touchscreen_data->name);
460 return SDL_SetError(
"Failed to get evdev touchscreen limits");
462 item->touchscreen_data->max_slots = abs_info.maximum + 1;
465 item->touchscreen_data->max_slots,
466 sizeof(*item->touchscreen_data->slots));
467 if (item->touchscreen_data->slots ==
NULL) {
468 SDL_free(item->touchscreen_data->name);
473 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
474 item->touchscreen_data->slots[
i].tracking_id = -1;
478 item->touchscreen_data->name);
480 SDL_free(item->touchscreen_data->slots);
481 SDL_free(item->touchscreen_data->name);
491 SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
492 if (!item->is_touchscreen)
496 SDL_free(item->touchscreen_data->slots);
497 SDL_free(item->touchscreen_data->name);
502 SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
506 struct input_absinfo abs_info;
516 __s32* mt_req_values;
520 if (!item->is_touchscreen)
523 mt_req_size =
sizeof(*mt_req_code) +
524 sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
527 if (mt_req_code ==
NULL) {
531 mt_req_values = (__s32*)mt_req_code + 1;
533 *mt_req_code = ABS_MT_TRACKING_ID;
534 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
539 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
549 if (item->touchscreen_data->slots[i].tracking_id < 0 &&
550 mt_req_values[i] >= 0) {
551 item->touchscreen_data->slots[
i].tracking_id = mt_req_values[
i];
552 item->touchscreen_data->slots[
i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
553 }
else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
554 mt_req_values[i] < 0) {
555 item->touchscreen_data->slots[
i].tracking_id = -1;
556 item->touchscreen_data->slots[
i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
560 *mt_req_code = ABS_MT_POSITION_X;
561 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
566 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
567 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
568 item->touchscreen_data->slots[i].x != mt_req_values[i]) {
569 item->touchscreen_data->slots[
i].x = mt_req_values[
i];
570 if (item->touchscreen_data->slots[i].delta ==
571 EVDEV_TOUCH_SLOTDELTA_NONE) {
572 item->touchscreen_data->slots[
i].delta =
573 EVDEV_TOUCH_SLOTDELTA_MOVE;
578 *mt_req_code = ABS_MT_POSITION_Y;
579 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
584 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
585 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
586 item->touchscreen_data->slots[i].y != mt_req_values[i]) {
587 item->touchscreen_data->slots[
i].y = mt_req_values[
i];
588 if (item->touchscreen_data->slots[i].delta ==
589 EVDEV_TOUCH_SLOTDELTA_NONE) {
590 item->touchscreen_data->slots[
i].delta =
591 EVDEV_TOUCH_SLOTDELTA_MOVE;
596 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
601 item->touchscreen_data->current_slot = abs_info.value;
610 SDL_EVDEV_device_added(
const char *dev_path,
int udev_class)
613 SDL_evdevlist_item *item;
616 for (item =
_this->first; item !=
NULL; item = item->next) {
622 item = (SDL_evdevlist_item *)
SDL_calloc(1,
sizeof (SDL_evdevlist_item));
627 item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
634 if (item->path ==
NULL) {
640 if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
641 item->is_touchscreen = 1;
643 if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
653 _this->last->next = item;
657 SDL_EVDEV_sync_device(item);
659 return _this->num_devices++;
664 SDL_EVDEV_device_removed(
const char *dev_path)
666 SDL_evdevlist_item *item;
667 SDL_evdevlist_item *prev =
NULL;
669 for (item =
_this->first; item !=
NULL; item = item->next) {
673 prev->next = item->next;
676 _this->first = item->next;
678 if (item ==
_this->last) {
681 if (item->is_touchscreen) {
682 SDL_EVDEV_destroy_touchscreen(item);
687 _this->num_devices--;
SDL_Mouse * SDL_GetMouse(void)
GLint GLint GLint GLint GLint x
static SDL_Event events[EVENT_BUF_SIZE]
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
GLuint const GLchar * name
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
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)
EGLDeviceEXT EGLint * num_devices
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
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)
GLsizei const GLfloat * value
void SDL_DelTouch(SDL_TouchID id)
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)
#define SDL_BUTTON_MIDDLE
GLint GLint GLint GLint GLint GLint y
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
#define SDL_assert(condition)
#define SDL_OutOfMemory()
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
SDL_EVDEV_keyboard_state * SDL_EVDEV_kbd_init(void)
static SDL_Scancode const linux_scancode_table[]
GLuint GLuint GLsizei GLenum type
#define SDL_arraysize(array)
GLsizei const GLchar *const * path
struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
SDL_Scancode
The SDL keyboard scancode representation.