From 9e2d33ce11d658f455ba801a8df9f141f329137f Mon Sep 17 00:00:00 2001 From: Alexander Barker Date: Tue, 11 Jul 2023 17:57:24 -0700 Subject: [PATCH 1/2] 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 669e5f6e..ad6d0dbe 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 a91648cc..ec72a668 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 a41c24d7..398d11fa 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 f037ce32..01d9341d 100644 --- a/src/windows/post_event.c +++ b/src/windows/post_event.c @@ -182,7 +182,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 bf6147b2..29652a8d 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 6eca1e10..ed1af55c 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 39b5e32c..0964b551 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) { From 6f71f93250d112e156903bf5005f4a1b985140d3 Mon Sep 17 00:00:00 2001 From: Alexander Barker Date: Thu, 18 Apr 2024 22:43:16 -0700 Subject: [PATCH 2/2] Adding missing amount to OSX. --- src/darwin/dispatch_event.c | 35 +++++++++++++++++++++++------------ src/windows/dispatch_event.c | 10 +++++----- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/darwin/dispatch_event.c b/src/darwin/dispatch_event.c index 123f0124..b38b459a 100644 --- a/src/darwin/dispatch_event.c +++ b/src/darwin/dispatch_event.c @@ -623,32 +623,46 @@ bool dispatch_mouse_wheel(uint64_t timestamp, CGEventRef event_ref) { CGEventSourceRef source = CGEventCreateSourceFromEvent(event_ref); double ppl = CGEventSourceGetPixelsPerLine(source); + unsigned int wheel_amount = 10; if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventIsContinuous) != 0) { // continuous device (trackpad) - ppl *= 1; + wheel_amount = 1; + + ppl *= wheel_amount; uio_event.data.wheel.type = WHEEL_BLOCK_SCROLL; if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis1) != 0) { uio_event.data.wheel.direction = WHEEL_VERTICAL_DIRECTION; - uio_event.data.wheel.rotation = (int16_t) (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventPointDeltaAxis1) * ppl * 1); + uio_event.data.wheel.rotation = (int16_t) ( + CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventPointDeltaAxis1) * ppl * wheel_amount + ); } else if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis2) != 0) { uio_event.data.wheel.direction = WHEEL_HORIZONTAL_DIRECTION; - uio_event.data.wheel.rotation = (int16_t) (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventPointDeltaAxis2) * ppl * 1); + uio_event.data.wheel.rotation = (int16_t) ( + CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventPointDeltaAxis2) * ppl * wheel_amount + ); } } else { // non-continuous device (wheel mice) - ppl *= 10; + wheel_amount = 10; + + ppl *= wheel_amount; uio_event.data.wheel.type = WHEEL_UNIT_SCROLL; if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis1) != 0) { uio_event.data.wheel.direction = WHEEL_VERTICAL_DIRECTION; - uio_event.data.wheel.rotation = (int16_t) (CGEventGetDoubleValueField(event_ref, kCGScrollWheelEventFixedPtDeltaAxis1) * ppl * 10); + uio_event.data.wheel.rotation = (int16_t) ( + CGEventGetDoubleValueField(event_ref, kCGScrollWheelEventFixedPtDeltaAxis1) * ppl * wheel_amount + ); } else if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis2) != 0) { uio_event.data.wheel.direction = WHEEL_HORIZONTAL_DIRECTION; - uio_event.data.wheel.rotation = (int16_t) (CGEventGetDoubleValueField(event_ref, kCGScrollWheelEventFixedPtDeltaAxis2) * ppl * 10); + uio_event.data.wheel.rotation = (int16_t) ( + CGEventGetDoubleValueField(event_ref, kCGScrollWheelEventFixedPtDeltaAxis2) * ppl * wheel_amount + ); } } + uio_event.data.wheel.amount = (uint8_t) wheel_amount; uio_event.data.wheel.delta = (uint16_t) ppl; if (source) { @@ -657,12 +671,9 @@ bool dispatch_mouse_wheel(uint64_t timestamp, CGEventRef event_ref) { logger(LOG_LEVEL_DEBUG, "%s [%u]: Mouse wheel %i / %u of type %u in the %u direction at %u, %u.\n", __FUNCTION__, __LINE__, - uio_event.data.wheel.rotation, - uio_event.data.wheel.delta, - uio_event.data.wheel.type, - uio_event.data.wheel.direction, - uio_event.data.wheel.x, - uio_event.data.wheel.y); + uio_event.data.wheel.rotation, uio_event.data.wheel.delta, + uio_event.data.wheel.type, uio_event.data.wheel.direction, + uio_event.data.wheel.x, uio_event.data.wheel.y); // Fire mouse wheel event. dispatch_event(&uio_event); diff --git a/src/windows/dispatch_event.c b/src/windows/dispatch_event.c index 398d11fa..0da244ee 100644 --- a/src/windows/dispatch_event.c +++ b/src/windows/dispatch_event.c @@ -391,11 +391,11 @@ bool dispatch_mouse_wheel(uint64_t timestamp, MSLLHOOKSTRUCT *mshook, uint8_t di uio_event.data.wheel.x = (int16_t) mshook->pt.x; uio_event.data.wheel.y = (int16_t) mshook->pt.y; - /* Delta GET_WHEEL_DELTA_WPARAM(mshook->mouseData) - * A positive value indicates that the wheel was rotated - * forward, away from the user; a negative value indicates that - * the wheel was rotated backward, toward the user. One wheel - * click is defined as WHEEL_DELTA, which is 120. */ + /* The GET_WHEEL_DELTA_WPARAM(mshook->mouseData) macro returns the high-order word of mouseData which represents + * the wheel delta. + * A positive value indicates that the wheel was rotated forward, away from the user. + * A negative value indicates that the wheel was rotated backward, toward the user. + * One wheel click is defined as WHEEL_DELTA, which is 120. */ uio_event.data.wheel.rotation = (int16_t) GET_WHEEL_DELTA_WPARAM(mshook->mouseData); uio_event.data.wheel.delta = WHEEL_DELTA;