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) {
258 while ((len = read(item->fd,
events, (
sizeof events))) > 0) {
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;
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;
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;
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;
423 if (item->out_of_sync)
424 item->out_of_sync = 0;
427 if (item->is_touchscreen)
428 item->out_of_sync = 1;
429 SDL_EVDEV_sync_device(item);
442 SDL_EVDEV_translate_keycode(
int keycode)
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);
464 #ifdef SDL_USE_LIBUDEV 466 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
469 unsigned long xreq, yreq;
471 struct input_absinfo abs_info;
473 if (!item->is_touchscreen)
476 item->touchscreen_data =
SDL_calloc(1,
sizeof(*item->touchscreen_data));
477 if (item->touchscreen_data ==
NULL)
480 ret = ioctl(item->fd, EVIOCGNAME(
sizeof(name)), name);
483 return SDL_SetError(
"Failed to get evdev touchscreen name");
486 item->touchscreen_data->name =
SDL_strdup(name);
487 if (item->touchscreen_data->name ==
NULL) {
492 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
494 SDL_free(item->touchscreen_data->name);
496 return SDL_SetError(
"Failed to get evdev touchscreen limits");
499 if (abs_info.maximum == 0) {
500 item->touchscreen_data->max_slots = 1;
501 xreq = EVIOCGABS(ABS_X);
502 yreq = EVIOCGABS(ABS_Y);
504 item->touchscreen_data->max_slots = abs_info.maximum + 1;
505 xreq = EVIOCGABS(ABS_MT_POSITION_X);
506 yreq = EVIOCGABS(ABS_MT_POSITION_Y);
509 ret = ioctl(item->fd, xreq, &abs_info);
511 SDL_free(item->touchscreen_data->name);
513 return SDL_SetError(
"Failed to get evdev touchscreen limits");
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;
519 ret = ioctl(item->fd, yreq, &abs_info);
521 SDL_free(item->touchscreen_data->name);
523 return SDL_SetError(
"Failed to get evdev touchscreen limits");
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;
529 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_PRESSURE), &abs_info);
531 SDL_free(item->touchscreen_data->name);
533 return SDL_SetError(
"Failed to get evdev touchscreen limits");
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;
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);
548 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
549 item->touchscreen_data->slots[
i].tracking_id = -1;
554 item->touchscreen_data->name);
556 SDL_free(item->touchscreen_data->slots);
557 SDL_free(item->touchscreen_data->name);
567 SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
568 if (!item->is_touchscreen)
572 SDL_free(item->touchscreen_data->slots);
573 SDL_free(item->touchscreen_data->name);
578 SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
582 struct input_absinfo abs_info;
596 if (!item->is_touchscreen)
599 mt_req_size =
sizeof(*mt_req_code) +
600 sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
603 if (mt_req_code ==
NULL) {
607 mt_req_values = (
Sint32*)mt_req_code + 1;
609 *mt_req_code = ABS_MT_TRACKING_ID;
610 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
615 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
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;
636 *mt_req_code = ABS_MT_POSITION_X;
637 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
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;
654 *mt_req_code = ABS_MT_POSITION_Y;
655 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
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;
672 *mt_req_code = ABS_MT_PRESSURE;
673 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
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;
690 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
695 item->touchscreen_data->current_slot = abs_info.value;
704 SDL_EVDEV_device_added(
const char *dev_path,
int udev_class)
707 SDL_evdevlist_item *item;
710 for (item =
_this->first; item !=
NULL; item = item->next) {
716 item = (SDL_evdevlist_item *)
SDL_calloc(1,
sizeof (SDL_evdevlist_item));
721 item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
728 if (item->path ==
NULL) {
734 if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
735 item->is_touchscreen = 1;
737 if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
747 _this->last->next = item;
751 SDL_EVDEV_sync_device(item);
753 return _this->num_devices++;
758 SDL_EVDEV_device_removed(
const char *dev_path)
760 SDL_evdevlist_item *item;
761 SDL_evdevlist_item *prev =
NULL;
763 for (item =
_this->first; item !=
NULL; item = item->next) {
767 prev->next = item->next;
770 _this->first = item->next;
772 if (item ==
_this->last) {
775 if (item->is_touchscreen) {
776 SDL_EVDEV_destroy_touchscreen(item);
781 _this->num_devices--;
SDL_Mouse * SDL_GetMouse(void)
GLint GLint GLint GLint GLint x
int(* SetRelativeMouseMode)(SDL_bool enabled)
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)
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
static SDL_VideoDevice * _this
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)
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)
GLsizei const GLfloat * value
void SDL_DelTouch(SDL_TouchID id)
#define SDL_BUTTON_MIDDLE
GLint GLint GLint GLint GLint GLint y
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)
#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.