21#include "../../SDL_internal.h"
23#ifdef SDL_INPUT_LINUXEV
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
61typedef 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;
98typedef 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
111static SDL_Scancode SDL_EVDEV_translate_keycode(
int keycode);
112static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
113static int SDL_EVDEV_device_removed(
const char *dev_path);
116static int SDL_EVDEV_device_added(
const char *dev_path,
int udev_class);
117static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
118 const char *dev_path);
121static 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);
212static 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;
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);
442SDL_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
466SDL_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");
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);
567SDL_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);
578SDL_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;
704SDL_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++;
758SDL_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--;
#define SDL_assert(condition)
#define SDL_OutOfMemory()
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)
SDL_EVDEV_keyboard_state * SDL_EVDEV_kbd_init(void)
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)
void SDL_DelTouch(SDL_TouchID id)
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
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)
@ 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 int in 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 in i)
EGLDeviceEXT EGLint * num_devices
static SDL_Scancode const linux_scancode_table[]
int(* SetRelativeMouseMode)(SDL_bool enabled)
static SDL_Event events[EVENT_BUF_SIZE]