evdev: Batch mouse axis updates until SYN_REPORT This is necessary for consistent position reports with absolute mice and improves application performance with relative mice by cutting the number of reported mouse motion events roughly in half.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c
index 208b3c1..bb940ce 100644
--- a/src/core/linux/SDL_evdev.c
+++ b/src/core/linux/SDL_evdev.c
@@ -96,8 +96,12 @@ typedef struct SDL_evdevlist_item
} * touchscreen_data;
+ /* Mouse state */
SDL_bool high_res_wheel;
SDL_bool high_res_hwheel;
+ SDL_bool relative_mouse;
+ int mouse_x, mouse_y;
+ int mouse_wheel, mouse_hwheel;
struct SDL_evdevlist_item *next;
} SDL_evdevlist_item;
@@ -361,16 +365,20 @@ SDL_EVDEV_Poll(void)
if (item->touchscreen_data->max_slots != 1)
break;
item->touchscreen_data->slots[0].x = events[i].value;
- } else
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
+ } else if (!item->relative_mouse) {
+ /* FIXME: Normalize to input device's reported input range (EVIOCGABS) */
+ item->mouse_x = events[i].value;
+ }
break;
case ABS_Y:
if (item->is_touchscreen) {
if (item->touchscreen_data->max_slots != 1)
break;
item->touchscreen_data->slots[0].y = events[i].value;
- } else
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, 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;
default:
break;
@@ -379,26 +387,28 @@ SDL_EVDEV_Poll(void)
case EV_REL:
switch(events[i].code) {
case REL_X:
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
+ if (item->relative_mouse)
+ item->mouse_x += events[i].value;
break;
case REL_Y:
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
+ if (item->relative_mouse)
+ item->mouse_y += events[i].value;
break;
case REL_WHEEL:
if (!item->high_res_wheel)
- SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
+ item->mouse_wheel += events[i].value;
break;
case REL_WHEEL_HI_RES:
SDL_assert(item->high_res_wheel);
- SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value / 120.0f, SDL_MOUSEWHEEL_NORMAL);
+ item->mouse_wheel += events[i].value;
break;
case REL_HWHEEL:
if (!item->high_res_hwheel)
- SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
+ item->mouse_hwheel += events[i].value;
break;
case REL_HWHEEL_HI_RES:
SDL_assert(item->high_res_hwheel);
- SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value / 120.0f, 0, SDL_MOUSEWHEEL_NORMAL);
+ item->mouse_hwheel += events[i].value;
break;
default:
break;
@@ -407,6 +417,19 @@ SDL_EVDEV_Poll(void)
case EV_SYN:
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, mouse->mouseID, item->relative_mouse, item->mouse_x, item->mouse_y);
+ item->mouse_x = item->mouse_y = 0;
+ }
+ if (item->mouse_wheel != 0 || item->mouse_hwheel != 0) {
+ SDL_SendMouseWheel(mouse->focus, mouse->mouseID,
+ item->mouse_hwheel / (item->high_res_hwheel ? 120.0f : 1.0f),
+ item->mouse_wheel / (item->high_res_wheel ? 120.0f : 1.0f),
+ SDL_MOUSEWHEEL_NORMAL);
+ item->mouse_wheel = item->mouse_hwheel = 0;
+ }
+
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
@@ -760,6 +783,7 @@ SDL_EVDEV_device_added(const char *dev_path, int udev_class)
}
if (ioctl(item->fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) {
+ item->relative_mouse = test_bit(REL_X, relbit) && test_bit(REL_Y, relbit);
item->high_res_wheel = test_bit(REL_WHEEL_HI_RES, relbit);
item->high_res_hwheel = test_bit(REL_HWHEEL_HI_RES, relbit);
}