Parcourir la source

Added support for absolute mice with evdev

(cherry picked from commit 9cd7cbe13464d9f0f80ef205e84e62f6da849aa1)
Andre Barata il y a 1 an
Parent
commit
47fd07bde6
1 fichiers modifiés avec 63 ajouts et 5 suppressions
  1. 63 5
      src/core/linux/SDL_evdev.c

+ 63 - 5
src/core/linux/SDL_evdev.c

@@ -112,6 +112,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;
@@ -398,7 +400,6 @@ void SDL_EVDEV_Poll(void)
                             }
                             item->touchscreen_data->slots[0].x = event->value;
                         } else if (!item->relative_mouse) {
-                            /* FIXME: Normalize to input device's reported input range (EVIOCGABS) */
                             item->mouse_x = event->value;
                         }
                         break;
@@ -409,7 +410,6 @@ void SDL_EVDEV_Poll(void)
                             }
                             item->touchscreen_data->slots[0].y = event->value;
                         } else if (!item->relative_mouse) {
-                            /* FIXME: Normalize to input device's reported input range (EVIOCGABS) */
                             item->mouse_y = event->value;
                         }
                         break;
@@ -455,10 +455,30 @@ void SDL_EVDEV_Poll(void)
                     switch (event->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(SDL_EVDEV_GetEventTimestamp(event), mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse, (float)item->mouse_x, (float)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(SDL_EVDEV_GetEventTimestamp(event), mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse, (float)item->mouse_x, (float)item->mouse_y);
+                                item->mouse_x = item->mouse_y = 0;
+                            }
+                        } else if (item->range_x > 0 && item->range_y > 0) {
+                            int screen_w = 0, screen_h = 0;
+                            const SDL_DisplayMode *mode = NULL;
+
+                            if (mouse->focus) {
+                                mode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(mouse->focus));
+                            }
+                            if (!mode) {
+                                mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
+                            }
+                            if (mode) {
+                                screen_w = mode->w;
+                                screen_h = mode->h;
+                            }
+                            SDL_SendMouseMotion(SDL_EVDEV_GetEventTimestamp(event), mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse,
+                                (float)(item->mouse_x - item->min_x) * screen_w / item->range_x,
+                                (float)(item->mouse_y - item->min_y) * screen_h / item->range_y);
                         }
+
                         if (item->mouse_wheel != 0 || item->mouse_hwheel != 0) {
                             SDL_SendMouseWheel(SDL_EVDEV_GetEventTimestamp(event),
                                                mouse->focus, (SDL_MouseID)item->fd,
@@ -651,6 +671,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) {
@@ -835,6 +885,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) {