From dbb8ba352efec94599618db1483465dcbf435ed6 Mon Sep 17 00:00:00 2001 From: Alexander Barker Date: Tue, 11 Jul 2023 17:57:24 -0700 Subject: [PATCH] Mouse Wheel Bug Fixes --- include/uiohook.h | 1 + src/darwin/post_event.c | 2 +- src/windows/dispatch_event.c | 2 ++ src/windows/post_event.c | 4 ++- src/x11/dispatch_event.c | 5 ++-- src/x11/input_helper.h | 3 +++ src/x11/post_event.c | 51 +++++++++++++++++++----------------- 7 files changed, 40 insertions(+), 28 deletions(-) diff --git a/include/uiohook.h b/include/uiohook.h index 49856805..2c4c61c2 100644 --- a/include/uiohook.h +++ b/include/uiohook.h @@ -109,6 +109,7 @@ typedef struct _mouse_wheel_event_data { int16_t x; int16_t y; uint8_t type; + uint8_t amount; int16_t rotation; uint16_t delta; uint8_t direction; diff --git a/src/darwin/post_event.c b/src/darwin/post_event.c index 65f02b2f..7cffb720 100644 --- a/src/darwin/post_event.c +++ b/src/darwin/post_event.c @@ -238,7 +238,7 @@ static int post_mouse_wheel_event(uiohook_event * const event, CGEventSourceRef CGEventRef cg_event = CGEventCreateScrollWheelEvent( src, - kCGScrollEventUnitLine, + scroll_unit, // TODO Currently only support 1 wheel axis. (CGWheelCount) 1, // 1 for Y-only, 2 for Y-X, 3 for Y-X-Z event->data.wheel.rotation // TODO Is this value correct? Do we need PPL? diff --git a/src/windows/dispatch_event.c b/src/windows/dispatch_event.c index 399dfecc..a965e9a3 100644 --- a/src/windows/dispatch_event.c +++ b/src/windows/dispatch_event.c @@ -412,6 +412,7 @@ bool dispatch_mouse_wheel(uint64_t timestamp, MSLLHOOKSTRUCT *mshook, uint8_t di uio_event.data.wheel.type = WHEEL_BLOCK_SCROLL; uio_event.data.wheel.rotation *= 1; + uio_event.data.wheel.amount = 1; } else { /* If this number is 0, no scrolling should occur. * If the number of lines to scroll is greater than the number of lines viewable, the scroll operation @@ -419,6 +420,7 @@ bool dispatch_mouse_wheel(uint64_t timestamp, MSLLHOOKSTRUCT *mshook, uint8_t di uio_event.data.wheel.type = WHEEL_UNIT_SCROLL; uio_event.data.wheel.rotation *= wheel_amount; + uio_event.data.wheel.amount = wheel_amount; } // Set the direction based on what event was received. diff --git a/src/windows/post_event.c b/src/windows/post_event.c index 437d9b72..359a99d8 100644 --- a/src/windows/post_event.c +++ b/src/windows/post_event.c @@ -166,7 +166,9 @@ static int map_mouse_event(uiohook_event * const event, INPUT * const input) { case EVENT_MOUSE_WHEEL: input->mi.dwFlags = MOUSEEVENTF_WHEEL; - // type, amount and rotation? + // TODO What are we going to do about delta=? We could normalize with rotation *= (120 / delta) + // TODO What are we going to do about type=WHEEL_BLOCK_SCROLL? + // TODO What are we going to do about amount=? Is this really a setting, not event property? input->mi.mouseData = event->data.wheel.rotation; break; diff --git a/src/x11/dispatch_event.c b/src/x11/dispatch_event.c index 7ff49313..bca7cc71 100644 --- a/src/x11/dispatch_event.c +++ b/src/x11/dispatch_event.c @@ -251,13 +251,14 @@ static bool dispatch_mouse_wheel_rotated(XButtonEvent * const x_event) { /* Some scroll wheel properties are available via the new XInput2 (XI2) extension. Unfortunately the extension is * not available on my development platform at this time. For the time being we will just use the Windows default * value of 3. */ + uio_event.data.wheel.amount = WHEEL_AMOUNT; uio_event.data.wheel.delta = 100; if (x_event->button == WheelDown || x_event->button == WheelLeft) { // Wheel Rotated Up and Away. - uio_event.data.wheel.rotation = -3 * uio_event.data.wheel.delta; + uio_event.data.wheel.rotation = -1 * uio_event.data.wheel.delta; } else { // event.button == WheelUp || event.button == WheelRight // Wheel Rotated Down and Towards. - uio_event.data.wheel.rotation = 3 * uio_event.data.wheel.delta; + uio_event.data.wheel.rotation = uio_event.data.wheel.delta; } if (x_event->button == WheelUp || x_event->button == WheelDown) { diff --git a/src/x11/input_helper.h b/src/x11/input_helper.h index 1a676096..90931506 100644 --- a/src/x11/input_helper.h +++ b/src/x11/input_helper.h @@ -35,6 +35,9 @@ #define XButton1 8 #define XButton2 9 +// The static number of clicks for X11 because it is a non-configurable amount. +#define WHEEL_AMOUNT 3 + // For this struct, refer to libxnee, requires Xlibint.h typedef union { unsigned char type; diff --git a/src/x11/post_event.c b/src/x11/post_event.c index a062ea5e..4c5267db 100644 --- a/src/x11/post_event.c +++ b/src/x11/post_event.c @@ -119,40 +119,43 @@ static int post_mouse_button_event(uiohook_event * const event) { static int post_mouse_wheel_event(uiohook_event * const event) { int status = UIOHOOK_FAILURE; - XButtonEvent btn_event = { - .serial = 0, - .send_event = False, - .display = helper_disp, + if (event->data.wheel.delta > 0) { + XButtonEvent btn_event = { + .serial = 0, + .send_event = False, + .display = helper_disp, - .window = None, /* “event” window it is reported relative to */ - .root = None, /* root window that the event occurred on */ - .subwindow = XDefaultRootWindow(helper_disp), /* child window */ + .window = None, /* “event” window it is reported relative to */ + .root = None, /* root window that the event occurred on */ + .subwindow = XDefaultRootWindow(helper_disp), /* child window */ - .time = CurrentTime, + .time = CurrentTime, - .x = event->data.wheel.x, /* pointer x, y coordinates in event window */ - .y = event->data.wheel.y, + .x = event->data.wheel.x, /* pointer x, y coordinates in event window */ + .y = event->data.wheel.y, - .x_root = 0, /* coordinates relative to root */ - .y_root = 0, + .x_root = 0, /* coordinates relative to root */ + .y_root = 0, - .state = 0x00, /* key or button mask */ - .same_screen = True - }; + .state = 0x00, /* key or button mask */ + .same_screen = True + }; - // Wheel events should be the same as click events on X11. - // type, amount and rotation - unsigned int button = button_map_lookup(event->data.wheel.rotation < 0 ? WheelUp : WheelDown); + unsigned int button = button_map_lookup(event->data.wheel.rotation < 0 ? WheelUp : WheelDown); - if (XTestFakeButtonEvent(helper_disp, button, True, 0) != 0) { + // X11 does not support a rotation amount so we will emulate the number of rotations based on the static wheel amount. + // TODO What are we going to do about type=WHEEL_BLOCK_SCROLL? + // TODO What are we going to do about amount=? Is this really a setting, not event property? status = UIOHOOK_SUCCESS; + for (int i = abs(event->data.wheel.rotation) / (event->data.wheel.delta * event->data.wheel.amount); i > 0 && status == UIOHOOK_SUCCESS; i--) { + // Wheel events are be the same as click events on X11. + if (!XTestFakeButtonEvent(helper_disp, button, True, 0) || !XTestFakeButtonEvent(helper_disp, button, False, 0)) { + status = UIOHOOK_FAILURE; + } + } } - if (status == UIOHOOK_SUCCESS && XTestFakeButtonEvent(helper_disp, button, False, 0) == 0) { - status = UIOHOOK_FAILURE; - } - - return UIOHOOK_SUCCESS; + return status; } static int post_mouse_motion_event(uiohook_event * const event) {