From 9cd7cbe13464d9f0f80ef205e84e62f6da849aa1 Mon Sep 17 00:00:00 2001
From: Andre Barata <[EMAIL REDACTED]>
Date: Fri, 30 Jun 2023 16:23:01 +0100
Subject: [PATCH] Added support for absolute mice with evdev
---
src/core/linux/SDL_evdev.c | 58 ++++++++++++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 5 deletions(-)
diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c
index e997aae4923a..4822ece844d0 100644
--- a/src/core/linux/SDL_evdev.c
+++ b/src/core/linux/SDL_evdev.c
@@ -105,6 +105,8 @@ typedef struct SDL_evdevlist_item
SDL_bool relative_mouse;
int mouse_x, mouse_y;
int mouse_wheel, mouse_hwheel;
+ int min_x, max_x, range_x;
+ int min_y, max_y, range_y;
struct SDL_evdevlist_item *next;
} SDL_evdevlist_item;
@@ -391,7 +393,6 @@ void SDL_EVDEV_Poll(void)
}
item->touchscreen_data->slots[0].x = events[i].value;
} else if (!item->relative_mouse) {
- /* FIXME: Normalize to input device's reported input range (EVIOCGABS) */
item->mouse_x = events[i].value;
}
break;
@@ -402,7 +403,6 @@ void SDL_EVDEV_Poll(void)
}
item->touchscreen_data->slots[0].y = events[i].value;
} else if (!item->relative_mouse) {
- /* FIXME: Normalize to input device's reported input range (EVIOCGABS) */
item->mouse_y = events[i].value;
}
break;
@@ -448,10 +448,20 @@ void SDL_EVDEV_Poll(void)
switch (events[i].code) {
case SYN_REPORT:
/* Send mouse axis changes together to ensure consistency and reduce event processing overhead */
- if (item->mouse_x != 0 || item->mouse_y != 0) {
- SDL_SendMouseMotion(mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse, item->mouse_x, item->mouse_y);
- item->mouse_x = item->mouse_y = 0;
+ if (item->relative_mouse) {
+ if (item->mouse_x != 0 || item->mouse_y != 0) {
+ SDL_SendMouseMotion(mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse, item->mouse_x, item->mouse_y);
+ item->mouse_x = item->mouse_y = 0;
+ }
+ } else if (item->range_x > 0 && item->range_y > 0) {
+ /* TODO: test with multiple display scenarios */
+ SDL_DisplayMode mode;
+ SDL_GetCurrentDisplayMode(0, &mode);
+ SDL_SendMouseMotion(mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse,
+ (item->mouse_x - item->min_x) * mode.w / item->range_x,
+ (item->mouse_y - item->min_y) * mode.h / item->range_y);
}
+
if (item->mouse_wheel != 0 || item->mouse_hwheel != 0) {
SDL_SendMouseWheel(mouse->focus, (SDL_MouseID)item->fd,
item->mouse_hwheel / (item->high_res_hwheel ? 120.0f : 1.0f),
@@ -643,6 +653,36 @@ static int SDL_EVDEV_init_touchscreen(SDL_evdevlist_item *item, int udev_class)
return 0;
}
+static int SDL_EVDEV_init_mouse(SDL_evdevlist_item *item, int udev_class)
+{
+ int ret;
+ struct input_absinfo abs_info;
+
+ if (item->is_touchscreen) {
+ return 0;
+ }
+
+ ret = ioctl(item->fd, EVIOCGABS(ABS_X), &abs_info);
+ if (ret < 0) {
+ // no absolute mode info, continue
+ return 0;
+ }
+ item->min_x = abs_info.minimum;
+ item->max_x = abs_info.maximum;
+ item->range_x = abs_info.maximum - abs_info.minimum;
+
+ ret = ioctl(item->fd, EVIOCGABS(ABS_Y), &abs_info);
+ if (ret < 0) {
+ // no absolute mode info, continue
+ return 0;
+ }
+ item->min_y = abs_info.minimum;
+ item->max_y = abs_info.maximum;
+ item->range_y = abs_info.maximum - abs_info.minimum;
+
+ return 0;
+}
+
static void SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item *item)
{
if (!item->is_touchscreen) {
@@ -827,6 +867,14 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
SDL_free(item);
return ret;
}
+ } else if (udev_class & SDL_UDEV_DEVICE_MOUSE) {
+ ret = SDL_EVDEV_init_mouse(item, udev_class);
+ if (ret < 0) {
+ close(item->fd);
+ SDL_free(item->path);
+ SDL_free(item);
+ return ret;
+ }
}
if (_this->last == NULL) {