Thumb wheel horizontal scroll can't be reversed: default binding pair is inverted vs. native scroll direction
Device: MX Master 4 (Bolt receiver) · OS: macOS 15.7.9 · Version: v0.6.27 (official cask)
Summary
On the MX Master 4, the thumb wheel's native (undiverted) scroll direction is up-rotation → scroll left, down-rotation → scroll right. OpenLogi's default binding pair says the opposite:
https://github.com/AprilNEA/OpenLogi/blob/v0.6.27/crates/openlogi-core/src/binding/defaults.rs#L36-L37
ButtonId::ThumbwheelScrollUp => Action::HorizontalScrollRight,
ButtonId::ThumbwheelScrollDown => Action::HorizontalScrollLeft,
Because the wheel is only diverted when something differs from defaults (thumbwheel_armed, watchers/gesture.rs#L100: sensitivity ≠ DEFAULT_THUMBWHEEL_SENSITIVITY or a thumbwheel binding ≠ default, computed in capture_plan.rs#L96), this inversion is invisible in the default state — native scroll is what users feel, and it's fine. But it surfaces as two real bugs:
1. Scroll direction cannot be reversed at all
Swapping the two bindings (ThumbwheelScrollUp = "HorizontalScrollLeft", ThumbwheelScrollDown = "HorizontalScrollRight") is non-default → the wheel is diverted → advance() injects sign from the action (gesture.rs#L474-L484) → up injects Left, down injects Right — which is exactly the native direction. Verified on hardware: the swapped config feels identical to the default config. Meanwhile the mapping that would reverse it (up→Right/down→Left, injected) equals the defaults, so it never diverts and never takes effect. Net: no combination of scroll bindings changes the felt direction, and the GUI (correctly, given the model) exposes no reverse option.
2. Moving the sensitivity slider silently flips scroll direction
Changing thumbwheel_sensitivity off 14 — with untouched default bindings — arms the divert by itself, switching the user from native (up→left) to injected defaults (up→right). A user who only wanted faster/slower scrolling gets their horizontal scroll direction reversed as a side effect.
Repro
- MX Master 4, default config: rotate thumb wheel up → content scrolls left (native).
- Set only
thumbwheel_sensitivity = 15, restart agent: rotate up → content scrolls right (bug 2).
- Set bindings Up→
HorizontalScrollLeft / Down→HorizontalScrollRight (the "swap"): rotate up → content scrolls left — same as step 1, no reversal possible (bug 1).
Proposed fix
Swap the two defaults in defaults.rs:
ButtonId::ThumbwheelScrollUp => Action::HorizontalScrollLeft,
ButtonId::ThumbwheelScrollDown => Action::HorizontalScrollRight,
(+ the GUI's default pair and affected tests, + the doc comment above the defaults.) Then:
- injected-default matches native → sensitivity changes no longer flip direction;
- the binding swap becomes non-default → diverts → genuinely reverses, giving users a working (if TOML-only) reverse today;
- a GUI "reverse direction" toggle becomes a trivial follow-up (it just writes the swapped pair).
Caveats worth a maintainer call: I've verified the native direction on one device (MX Master 4 via Bolt, macOS — the injected CGEvent and native scroll both pass through the same system scroll-inversion handling, so macOS "natural scrolling" doesn't affect the relative comparison). If other thumb-wheel devices share the firmware convention this is universal; and existing configs that explicitly wrote the old default pair would start diverting after the swap (behavior-preserving direction-wise, but they lose native-scroll latency — may warrant a migration touch).
Happy to send the PR if the direction (pun intended) looks right to you.
Workaround for anyone hitting this now: keep the default bindings and set thumbwheel_sensitivity to 15 (forces the diverted path, whose defaults are the reverse of native; ~5% faster than 14, imperceptible).
Thumb wheel horizontal scroll can't be reversed: default binding pair is inverted vs. native scroll direction
Device: MX Master 4 (Bolt receiver) · OS: macOS 15.7.9 · Version: v0.6.27 (official cask)
Summary
On the MX Master 4, the thumb wheel's native (undiverted) scroll direction is up-rotation → scroll left, down-rotation → scroll right. OpenLogi's default binding pair says the opposite:
https://github.com/AprilNEA/OpenLogi/blob/v0.6.27/crates/openlogi-core/src/binding/defaults.rs#L36-L37
Because the wheel is only diverted when something differs from defaults (
thumbwheel_armed,watchers/gesture.rs#L100: sensitivity ≠DEFAULT_THUMBWHEEL_SENSITIVITYor a thumbwheel binding ≠ default, computed incapture_plan.rs#L96), this inversion is invisible in the default state — native scroll is what users feel, and it's fine. But it surfaces as two real bugs:1. Scroll direction cannot be reversed at all
Swapping the two bindings (
ThumbwheelScrollUp = "HorizontalScrollLeft",ThumbwheelScrollDown = "HorizontalScrollRight") is non-default → the wheel is diverted →advance()injects sign from the action (gesture.rs#L474-L484) → up injects Left, down injects Right — which is exactly the native direction. Verified on hardware: the swapped config feels identical to the default config. Meanwhile the mapping that would reverse it (up→Right/down→Left, injected) equals the defaults, so it never diverts and never takes effect. Net: no combination of scroll bindings changes the felt direction, and the GUI (correctly, given the model) exposes no reverse option.2. Moving the sensitivity slider silently flips scroll direction
Changing
thumbwheel_sensitivityoff 14 — with untouched default bindings — arms the divert by itself, switching the user from native (up→left) to injected defaults (up→right). A user who only wanted faster/slower scrolling gets their horizontal scroll direction reversed as a side effect.Repro
thumbwheel_sensitivity = 15, restart agent: rotate up → content scrolls right (bug 2).HorizontalScrollLeft/ Down→HorizontalScrollRight(the "swap"): rotate up → content scrolls left — same as step 1, no reversal possible (bug 1).Proposed fix
Swap the two defaults in
defaults.rs:(+ the GUI's default pair and affected tests, + the doc comment above the defaults.) Then:
Caveats worth a maintainer call: I've verified the native direction on one device (MX Master 4 via Bolt, macOS — the injected CGEvent and native scroll both pass through the same system scroll-inversion handling, so macOS "natural scrolling" doesn't affect the relative comparison). If other thumb-wheel devices share the firmware convention this is universal; and existing configs that explicitly wrote the old default pair would start diverting after the swap (behavior-preserving direction-wise, but they lose native-scroll latency — may warrant a migration touch).
Happy to send the PR if the direction (pun intended) looks right to you.
Workaround for anyone hitting this now: keep the default bindings and set
thumbwheel_sensitivityto 15 (forces the diverted path, whose defaults are the reverse of native; ~5% faster than 14, imperceptible).