From 6cdf46f857a59bcabbf050b725cbc79cf9dea9f9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 8 Jul 2025 16:39:10 +1000 Subject: [PATCH] plugins: restore the wheel plugin specifically for the MX Master 3 The MX Master 3 is difficult, its wheel events are all over the place and heuristics are tricky to determine. The previous plugin behavior was seemingly sufficient for the MX Master but not for other devices. Restore the old behavior if the quirk is set for a device by adding a fourth state ALWAYS_ACCUMULATE. In this state the min movement is never updated from the original threshold, causing any wheel motion to accumulate. Ref: ca6b82841caf ("plugin/wheel: tighten the wheel debouncing code") Ref: bb05e0d1b562 ("plugin/wheel: don't accumulate for low HID resolution multipliers") Part-of: --- quirks/30-vendor-logitech.quirks | 4 +++ src/libinput-plugin-mouse-wheel.c | 46 +++++++++++++++++++++---------- src/quirks.c | 2 ++ src/quirks.h | 1 + 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/quirks/30-vendor-logitech.quirks b/quirks/30-vendor-logitech.quirks index f2ef5ea3..0c0ceee3 100644 --- a/quirks/30-vendor-logitech.quirks +++ b/quirks/30-vendor-logitech.quirks @@ -93,22 +93,26 @@ ModelInvertHorizontalScrolling=1 MatchVendor=0x046D MatchProduct=0x4082 ModelInvertHorizontalScrolling=1 +ModelLogitechMXMaster3=1 # MX Master 3 has a different PID on bluetooth [Logitech MX Master 3 Bluetooth] MatchVendor=0x046D MatchProduct=0xB023 ModelInvertHorizontalScrolling=1 +ModelLogitechMXMaster3=1 [Logitech MX Master 3S] MatchVendor=0x046D MatchProduct=0xB034 ModelInvertHorizontalScrolling=1 +ModelLogitechMXMaster3=1 [Logitech MX Master 3B] MatchVendor=0x046D MatchProduct=0xB028 ModelInvertHorizontalScrolling=1 +ModelLogitechMXMaster3=1 # Don't add quirks for the Logitech Bolt Receiver: # MatchVendor=0x046D diff --git a/src/libinput-plugin-mouse-wheel.c b/src/libinput-plugin-mouse-wheel.c index 8285cfad..994967d0 100644 --- a/src/libinput-plugin-mouse-wheel.c +++ b/src/libinput-plugin-mouse-wheel.c @@ -62,9 +62,10 @@ enum wheel_event { }; enum ignore_strategy { - MAYBE, /* use heuristics but don't yet accumulate */ - ACCUMULATE, /* accumulate scroll wheel events */ - PASSTHROUGH, /* do not accumulate, pass through */ + MAYBE, /* use heuristics but don't yet accumulate */ + PASSTHROUGH, /* do not accumulate, pass through */ + ACCUMULATE, /* accumulate scroll wheel events */ + ALWAYS_ACCUMULATE, /* always accumulate wheel events */ }; struct plugin_device { @@ -146,9 +147,16 @@ wheel_handle_event_on_state_none(struct plugin_device *pd, { switch (event) { case WHEEL_EVENT_SCROLL: - pd->state = pd->ignore_small_hi_res_movements == ACCUMULATE - ? WHEEL_STATE_ACCUMULATING_SCROLL - : WHEEL_STATE_SCROLLING; + switch (pd->ignore_small_hi_res_movements) { + case ACCUMULATE: + case ALWAYS_ACCUMULATE: + pd->state = WHEEL_STATE_ACCUMULATING_SCROLL; + break; + case PASSTHROUGH: + case MAYBE: + pd->state = WHEEL_STATE_SCROLLING; + break; + } break; case WHEEL_EVENT_SCROLL_DIR_CHANGED: break; @@ -344,14 +352,16 @@ wheel_handle_direction_change(struct plugin_device *pd, static inline void wheel_update_strategy(struct plugin_device *pd, int32_t value) { - pd->min_movement = min(pd->min_movement, abs(value)); + if (pd->ignore_small_hi_res_movements != ALWAYS_ACCUMULATE) { + pd->min_movement = min(pd->min_movement, abs(value)); - /* Only if a wheel sends movements less than the trigger threshold - * activate the accumulation and debouncing of scroll directions, etc. - */ - if (pd->ignore_small_hi_res_movements == MAYBE && - pd->min_movement < ACC_V120_TRIGGER_THRESHOLD) - pd->ignore_small_hi_res_movements = ACCUMULATE; + /* Only if a wheel sends movements less than the trigger threshold + * activate the accumulation and debouncing of scroll directions, etc. + */ + if (pd->ignore_small_hi_res_movements == MAYBE && + pd->min_movement < ACC_V120_TRIGGER_THRESHOLD) + pd->ignore_small_hi_res_movements = ACCUMULATE; + } } static void @@ -434,11 +444,17 @@ wheel_plugin_device_create(struct libinput_plugin *libinput_plugin, pd->device = libinput_device_ref(device); pd->state = WHEEL_STATE_NONE; pd->dir = WHEEL_DIR_UNKNOW; - pd->ignore_small_hi_res_movements = - evdev_device_is_virtual(evdev) ? PASSTHROUGH : MAYBE; pd->min_movement = ACC_V120_THRESHOLD; ratelimit_init(&pd->hires_warning_limit, s2us(24 * 60 * 60), 1); + if (evdev_device_is_virtual(evdev)) + pd->ignore_small_hi_res_movements = PASSTHROUGH; + else if (libinput_device_has_model_quirk(device, + QUIRK_MODEL_LOGITECH_MX_MASTER_3)) + pd->ignore_small_hi_res_movements = ALWAYS_ACCUMULATE; + else + pd->ignore_small_hi_res_movements = MAYBE; + if (pd->ignore_small_hi_res_movements != PASSTHROUGH) { pd->scroll_timer = libinput_plugin_timer_new(libinput_plugin, diff --git a/src/quirks.c b/src/quirks.c index b7f82653..36f4058e 100644 --- a/src/quirks.c +++ b/src/quirks.c @@ -296,6 +296,8 @@ quirk_get_name(enum quirk q) return "ModelWacomTouchpad"; case QUIRK_MODEL_PRESSURE_PAD: return "ModelPressurePad"; + case QUIRK_MODEL_LOGITECH_MX_MASTER_3: + return "ModelLogitechMXMaster3"; case QUIRK_ATTR_SIZE_HINT: return "AttrSizeHint"; diff --git a/src/quirks.h b/src/quirks.h index e52e9357..241986fd 100644 --- a/src/quirks.h +++ b/src/quirks.h @@ -83,6 +83,7 @@ enum quirk { QUIRK_MODEL_LENOVO_T450_TOUCHPAD, QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD, QUIRK_MODEL_LENOVO_X230, + QUIRK_MODEL_LOGITECH_MX_MASTER_3, QUIRK_MODEL_PRESSURE_PAD, QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD, QUIRK_MODEL_SYSTEM76_BONOBO,