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;
104 #define _THIS SDL_EVDEV_PrivateData *_this 107 static SDL_Scancode SDL_EVDEV_translate_keycode(
int keycode);
108 static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
109 static int SDL_EVDEV_device_removed(
const char *dev_path);
112 static int SDL_EVDEV_device_added(
const char *dev_path,
int udev_class);
113 static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
114 const char *dev_path);
117 static Uint8 EVDEV_MouseButtons[] = {
138 if (SDL_UDEV_Init() < 0) {
145 if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
161 _this->ref_count += 1;
173 _this->ref_count -= 1;
175 if (
_this->ref_count < 1) {
177 SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
185 SDL_EVDEV_device_removed(
_this->first->path);
198 static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event,
int udev_class,
199 const char* dev_path)
201 if (dev_path ==
NULL) {
206 case SDL_UDEV_DEVICEADDED:
207 if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
208 SDL_UDEV_DEVICE_TOUCHSCREEN)))
211 SDL_EVDEV_device_added(dev_path, udev_class);
213 case SDL_UDEV_DEVICEREMOVED:
214 SDL_EVDEV_device_removed(dev_path);
225 struct input_event
events[32];
227 SDL_evdevlist_item *item;
231 float norm_x, norm_y;
243 for (item =
_this->first; item !=
NULL; item = item->next) {
244 while ((len = read(item->fd,
events, (
sizeof events))) > 0) {
246 for (i = 0; i <
len; ++
i) {
249 if (item->out_of_sync && item->is_touchscreen &&
257 mouse_button =
events[
i].code - BTN_MOUSE;
267 scan_code = SDL_EVDEV_translate_keycode(
events[i].code);
280 if (!item->is_touchscreen)
282 item->touchscreen_data->current_slot =
events[
i].value;
284 case ABS_MT_TRACKING_ID:
285 if (!item->is_touchscreen)
288 item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id =
events[
i].value;
289 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
291 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
294 case ABS_MT_POSITION_X:
295 if (!item->is_touchscreen)
297 item->touchscreen_data->slots[item->touchscreen_data->current_slot].x =
events[
i].value;
298 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
299 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
302 case ABS_MT_POSITION_Y:
303 if (!item->is_touchscreen)
305 item->touchscreen_data->slots[item->touchscreen_data->current_slot].y =
events[
i].value;
306 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
307 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
311 if (item->is_touchscreen)
316 if (item->is_touchscreen)
345 if (!item->is_touchscreen)
348 for(j = 0; j < item->touchscreen_data->max_slots; j++) {
349 norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
350 (float)item->touchscreen_data->range_x;
351 norm_y = (
float)(item->touchscreen_data->slots[
j].y - item->touchscreen_data->min_y) /
352 (
float)item->touchscreen_data->range_y;
354 switch(item->touchscreen_data->slots[j].delta) {
355 case EVDEV_TOUCH_SLOTDELTA_DOWN:
356 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id,
SDL_TRUE, norm_x, norm_y, 1.0f);
357 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
359 case EVDEV_TOUCH_SLOTDELTA_UP:
361 item->touchscreen_data->slots[
j].tracking_id = -1;
362 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
364 case EVDEV_TOUCH_SLOTDELTA_MOVE:
365 SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
366 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
373 if (item->out_of_sync)
374 item->out_of_sync = 0;
377 if (item->is_touchscreen)
378 item->out_of_sync = 1;
379 SDL_EVDEV_sync_device(item);
392 SDL_EVDEV_translate_keycode(
int keycode)
400 SDL_Log(
"The key you just pressed is not recognized by SDL. To help " 401 "get this fixed, please report this to the SDL forums/mailing list " 402 "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
408 #ifdef SDL_USE_LIBUDEV 410 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
414 struct input_absinfo abs_info;
416 if (!item->is_touchscreen)
419 item->touchscreen_data =
SDL_calloc(1,
sizeof(*item->touchscreen_data));
420 if (item->touchscreen_data ==
NULL)
423 ret = ioctl(item->fd, EVIOCGNAME(
sizeof(name)), name);
426 return SDL_SetError(
"Failed to get evdev touchscreen name");
429 item->touchscreen_data->name =
SDL_strdup(name);
430 if (item->touchscreen_data->name ==
NULL) {
435 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
437 SDL_free(item->touchscreen_data->name);
439 return SDL_SetError(
"Failed to get evdev touchscreen limits");
441 item->touchscreen_data->min_x = abs_info.minimum;
442 item->touchscreen_data->max_x = abs_info.maximum;
443 item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
445 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
447 SDL_free(item->touchscreen_data->name);
449 return SDL_SetError(
"Failed to get evdev touchscreen limits");
451 item->touchscreen_data->min_y = abs_info.minimum;
452 item->touchscreen_data->max_y = abs_info.maximum;
453 item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
455 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
457 SDL_free(item->touchscreen_data->name);
459 return SDL_SetError(
"Failed to get evdev touchscreen limits");
461 item->touchscreen_data->max_slots = abs_info.maximum + 1;
464 item->touchscreen_data->max_slots,
465 sizeof(*item->touchscreen_data->slots));
466 if (item->touchscreen_data->slots ==
NULL) {
467 SDL_free(item->touchscreen_data->name);
472 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
473 item->touchscreen_data->slots[
i].tracking_id = -1;
477 item->touchscreen_data->name);
479 SDL_free(item->touchscreen_data->slots);
480 SDL_free(item->touchscreen_data->name);
490 SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
491 if (!item->is_touchscreen)
495 SDL_free(item->touchscreen_data->slots);
496 SDL_free(item->touchscreen_data->name);
501 SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
505 struct input_absinfo abs_info;
515 __s32* mt_req_values;
519 if (!item->is_touchscreen)
522 mt_req_size =
sizeof(*mt_req_code) +
523 sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
526 if (mt_req_code ==
NULL) {
530 mt_req_values = (__s32*)mt_req_code + 1;
532 *mt_req_code = ABS_MT_TRACKING_ID;
533 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
538 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
548 if (item->touchscreen_data->slots[i].tracking_id < 0 &&
549 mt_req_values[i] >= 0) {
550 item->touchscreen_data->slots[
i].tracking_id = mt_req_values[
i];
551 item->touchscreen_data->slots[
i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
552 }
else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
553 mt_req_values[i] < 0) {
554 item->touchscreen_data->slots[
i].tracking_id = -1;
555 item->touchscreen_data->slots[
i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
559 *mt_req_code = ABS_MT_POSITION_X;
560 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
565 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
566 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
567 item->touchscreen_data->slots[i].x != mt_req_values[i]) {
568 item->touchscreen_data->slots[
i].x = mt_req_values[
i];
569 if (item->touchscreen_data->slots[i].delta ==
570 EVDEV_TOUCH_SLOTDELTA_NONE) {
571 item->touchscreen_data->slots[
i].delta =
572 EVDEV_TOUCH_SLOTDELTA_MOVE;
577 *mt_req_code = ABS_MT_POSITION_Y;
578 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
583 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
584 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
585 item->touchscreen_data->slots[i].y != mt_req_values[i]) {
586 item->touchscreen_data->slots[
i].y = mt_req_values[
i];
587 if (item->touchscreen_data->slots[i].delta ==
588 EVDEV_TOUCH_SLOTDELTA_NONE) {
589 item->touchscreen_data->slots[
i].delta =
590 EVDEV_TOUCH_SLOTDELTA_MOVE;
595 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
600 item->touchscreen_data->current_slot = abs_info.value;
609 SDL_EVDEV_device_added(
const char *dev_path,
int udev_class)
612 SDL_evdevlist_item *item;
615 for (item =
_this->first; item !=
NULL; item = item->next) {
621 item = (SDL_evdevlist_item *)
SDL_calloc(1,
sizeof (SDL_evdevlist_item));
626 item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
633 if (item->path ==
NULL) {
639 if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
640 item->is_touchscreen = 1;
642 if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
652 _this->last->next = item;
656 SDL_EVDEV_sync_device(item);
658 return _this->num_devices++;
663 SDL_EVDEV_device_removed(
const char *dev_path)
665 SDL_evdevlist_item *item;
666 SDL_evdevlist_item *prev =
NULL;
668 for (item =
_this->first; item !=
NULL; item = item->next) {
672 prev->next = item->next;
675 _this->first = item->next;
677 if (item ==
_this->last) {
680 if (item->is_touchscreen) {
681 SDL_EVDEV_destroy_touchscreen(item);
686 _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
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
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
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.