Add remappable support for horizontal scroll wheel tilt actions - #359
Add remappable support for horizontal scroll wheel tilt actions#359srako wants to merge 3 commits into
Conversation
Greptile SummaryThis PR makes horizontal main-wheel tilt remappable like other mouse buttons. The main changes are:
Confidence Score: 4/5This is close, but the horizontal-scroll capture should be fixed before merging.
Files Needing Attention: crates/openlogi-agent-core/src/hook_runtime.rs
|
| Filename | Overview |
|---|---|
| crates/openlogi-agent-core/src/hook_runtime.rs | Adds horizontal scroll interception for wheel tilt, including default pass-through and cooldown handling. |
| crates/openlogi-core/src/binding.rs | Adds the new tilt button IDs, labels, ordering, and default bindings. |
| crates/openlogi-gui/src/data/mouse_buttons.rs | Adds fallback hotspots for remapping left and right wheel tilt. |
| crates/openlogi-gui/src/mouse_model/geometry.rs | Derives tilt hotspots from the middle-click geometry and updates fallback label positions. |
Reviews (4): Last reviewed commit: "fix(wheel): suppress entire tilt burst t..." | Re-trigger Greptile
|
Any progress on this? |
…buttons Add WheelLeft and WheelRight to the ButtonId enum so the main scroll wheel's horizontal tilt — which arrives as a horizontal scroll event at the OS hook, not as a button press — can be intercepted and remapped to any Action, just like a physical button. Core changes: - binding.rs: WheelLeft/WheelRight variants, ALL array, labels, and default bindings (native horizontal scroll, pass-through) - hook_runtime.rs: intercept MouseEvent::Scroll with non-zero delta_x from a non-trackpad source; look up the bound action and dispatch it with a 250ms per-direction cooldown so one deliberate tilt fires once - mouse_buttons.rs: GUI hotspots flanking the middle-click area - geometry.rs: with_wheel_tilt() auto-derives tilt hotspots from the MiddleClick position; default_labels() updated for the new buttons Default behavior is unchanged: unbound or default-bound tilt events pass through as native horizontal scroll. Only when the user maps WheelLeft/WheelRight to a non-default action does the hook suppress the scroll event and fire the bound action instead.
…mbwheel Two bugs found in code review (PR AprilNEA#359): 1. (P1) Horizontal scroll from a thumbwheel (or any non-tilt source) was suppressed whenever WheelLeft/WheelRight had a custom binding, breaking native thumbwheel scrolling. Fix: only suppress when we actually fire the action; pass through when the cooldown blocks the fire so continuous horizontal wheels keep scrolling. 2. (P2) Action::None suppressed native horizontal scroll instead of passing it through. Fix: treat None the same as the default binding — pass through so the user keeps native scrolling.
Greptile review (PR AprilNEA#359, comment 3) found that the previous fix for thumbwheel compatibility (passing through when the cooldown blocks) introduced a scroll leak: the remaining events in a wheel-tilt burst pass through as native horizontal scroll, so a tilt mapped to e.g. Mission Control also nudges the page sideways. Fix: always Suppress when a custom action is bound, regardless of whether the cooldown allows a fire. The cooldown still prevents repeated dispatches, and the entire burst is consumed so no native scroll leaks. Document the known limitation: on devices with both a tilt wheel and a thumbwheel (e.g. MX Master 3S), mapping WheelLeft/WheelRight will also intercept the thumbwheel's native scroll. Users who need native thumbwheel scroll should not remap these buttons.
| return EventDisposition::PassThrough; | ||
| } | ||
|
|
||
| let (button, is_left) = if delta_x < 0.0 { |
There was a problem hiding this comment.
Horizontal wheels still captured
This condition still treats every non-trackpad horizontal scroll event as WheelLeft or WheelRight. A mouse thumbwheel or dedicated horizontal wheel can also arrive with from_trackpad == false and nonzero delta_x, so mapping either tilt direction to a custom action suppresses that native horizontal scroll and runs the remapped action instead. The comment below documents this case, but the runtime behavior is unchanged for users with both tilt and horizontal-wheel input.
|
Data relevant to the layer choice, since this and #357 intercept the same two controls at different points. Source: an MX Ergo's Tilt is a pair of discrete divertable controls on this device, with the same flags as the already-bindable The Two consequences for the hook approach:
A hook path still covers devices whose tilt exposes no CID, so both layers may be wanted, preferring diversion when |
…buttons
Add WheelLeft and WheelRight to the ButtonId enum so the main scroll wheel's horizontal tilt — which arrives as a horizontal scroll event at the OS hook, not as a button press — can be intercepted and remapped to any Action, just like a physical button.
Core changes:
Default behavior is unchanged: unbound or default-bound tilt events pass through as native horizontal scroll. Only when the user maps WheelLeft/WheelRight to a non-default action does the hook suppress the scroll event and fire the bound action instead.