fix(wayland): forward whole scroll ticks from hi-res wheels

Fixes #9120

Hi-res mouse wheels (like my logitech G502) send scrolls as fractional clicks. On a mac client, fractional events are truncated to zero lines. This fix accumulates those fractional events then emits the entire click 120 units at a time
This commit is contained in:
David Sawick 2026-07-21 14:05:17 +10:00 committed by Chris Rizzitello
parent a074de1b7c
commit 4fc72eda23

View file

@ -28,7 +28,8 @@
#include <unistd.h> #include <unistd.h>
#include <vector> #include <vector>
// Values are in fractional wheel-click units (1.0 == one full 120-unit click) // Values are in fractional wheel-click units (1.0 == one full 120-unit click) for trackpad
// and pixels in scroll wheel events.
struct ScrollRemainder struct ScrollRemainder
{ {
double x; double x;
@ -813,8 +814,7 @@ void EiScreen::onPointerScrollEvent(ei_event *event)
void EiScreen::onPointerScrollDiscreteEvent(ei_event *event) void EiScreen::onPointerScrollDiscreteEvent(ei_event *event)
{ {
// both libei and deskflow use multiples of 120 to represent // both libei and deskflow use multiples of 120 to represent
// one scroll wheel click event so we can just forward things // one scroll wheel click event
// as-is.
assert(m_isPrimary); assert(m_isPrimary);
@ -823,10 +823,26 @@ void EiScreen::onPointerScrollDiscreteEvent(ei_event *event)
LOG_VERBOSE("event: scroll discrete (%d, %d)", dx, dy); LOG_VERBOSE("event: scroll discrete (%d, %d)", dx, dy);
// accumulate fractional ticks, then emit 120 units at a time
struct ei_device *device = ei_event_get_device(event);
auto *remainder = static_cast<struct ScrollRemainder *>(ei_device_get_user_data(device));
if (!remainder) {
remainder = new ScrollRemainder();
ei_device_set_user_data(device, remainder);
}
double ax = remainder->x + dx;
double ay = remainder->y + dy;
auto cx = static_cast<int32_t>(ax / s_scrollDelta) * s_scrollDelta;
auto cy = static_cast<int32_t>(ay / s_scrollDelta) * s_scrollDelta;
remainder->x = ax - cx;
remainder->y = ay - cy;
// libei and deskflow seem to use opposite directions, so we have // libei and deskflow seem to use opposite directions, so we have
// to send the opposite of the value reported by EI if we want to // to send the opposite of the value reported by EI if we want to
// remain compatible with other platforms (including X11). // remain compatible with other platforms (including X11).
sendEvent(EventTypes::PrimaryScreenWheel, WheelInfo::alloc(-dx, -dy)); if (cx != 0 || cy != 0)
sendEvent(EventTypes::PrimaryScreenWheel, WheelInfo::alloc(-cx, -cy));
} }
void EiScreen::onMotionEvent(ei_event *event) void EiScreen::onMotionEvent(ei_event *event)