Skip to content

feat: wheel tilt-left/right as bindable buttons (verified on MX Ergo) - #357

Open
g30r93g wants to merge 6 commits into
AprilNEA:masterfrom
g30r93g:feat/mx-ergo-tilt-buttons
Open

feat: wheel tilt-left/right as bindable buttons (verified on MX Ergo)#357
g30r93g wants to merge 6 commits into
AprilNEA:masterfrom
g30r93g:feat/mx-ergo-tilt-buttons

Conversation

@g30r93g

@g30r93g g30r93g commented Jul 5, 2026

Copy link
Copy Markdown

What

Adds the scroll-wheel tilt-left / tilt-right controls as first-class bindable buttons. These horizontal-tilt controls (HID++ 0x1b04 reprogrammable controls, CIDs 0x5b/0x5d) weren't detected or configurable before; they now appear on the mouse diagram with an action picker and default to horizontal scroll.

Addresses #100 (wheel tilt not detected / not configurable). That issue is filed against the M500S; this implements the general mechanism and is verified end-to-end on an MX Ergo (same standard Logitech tilt CIDs). I don't have an M500S to confirm, but the capture path and slot-name mapping are device-agnostic.

How (mirrors existing patterns)

  • ButtonId::TiltLeft / TiltRight (appended, TOML-stable), default-bound to HorizontalScrollLeft / HorizontalScrollRight.
  • Captured over HID++ via the same diverted-button rising-edge path as the DPI button; diverted only when a tilt is rebound (mirrors thumbwheel_armed), so native horizontal scrolling is untouched otherwise.
  • GUI hotspots come from the existing asset markers by mapping SLOT_NAME_SCROLL_LEFT / SLOT_NAME_SCROLL_RIGHT — no asset-registry change.
  • Localized across all 20 locales.

Verification

  • cargo fmt --check, cargo clippy --workspace -D warnings, and cargo test --workspace (417 passed, 0 failed) all green.
  • New unit tests: the capture rising-edge for both tilt CIDs, tilt_armed gating, and the slot-name mapping.
  • On-device (MX Ergo, Bluetooth): diag controls reports 0x5b/0x5d as divertable, and a live capture session recorded 142 physical tilt events correctly mapped to TiltLeft / TiltRight (not swapped).

Not in scope

  • The MX Ergo's Virtual Gesture Button (0xd7).
  • Label-layout changes — the right gutter is intentionally reserved for the DPI/gesture column per existing code comments, so the tilt labels stay in the left column.

@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds wheel tilt-left and tilt-right as bindable mouse controls.

  • New TiltLeft and TiltRight button IDs with horizontal-scroll defaults.
  • HID++ capture support for tilt CIDs when a tilt control is rebound.
  • GUI hotspot mapping for existing scroll-left and scroll-right asset slots.
  • Locale labels and tests for tilt defaults, arming, slot mapping, and capture events.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
crates/openlogi-hid/src/gesture.rs Adds tilt CID diversion, restoration, and rising-edge capture for tilt button presses.
crates/openlogi-agent-core/src/watchers/gesture.rs Adds tilt arming based on non-default tilt bindings and passes that state into capture sessions.
crates/openlogi-core/src/binding.rs Adds tilt button IDs, labels, ordering, and default horizontal-scroll actions.
crates/openlogi-gui/src/mouse_model/geometry.rs Maps scroll-left and scroll-right asset slots to the new tilt controls.

Reviews (2): Last reviewed commit: "docs(tilt): note wheel-tilt buttons in c..." | Re-trigger Greptile

Comment thread crates/openlogi-hid/src/gesture.rs
Comment thread crates/openlogi-agent-core/src/watchers/gesture.rs
g30r93g added 6 commits July 29, 2026 11:51
Address code-review: the module docs mentioned wheel tilt but the
CapturedInput::ButtonPressed variant doc, the agent-core watcher module
doc, and the ButtonId doc still described the pre-tilt set. Also clarify
that ButtonId variants are appended (TOML-stable) while ButtonId::ALL
carries the physical layout order.
@g30r93g
g30r93g force-pushed the feat/mx-ergo-tilt-buttons branch from a8d9ff4 to d58ddbb Compare July 29, 2026 10:54
@davidbudnick davidbudnick added type: feature New feature request platform: all Cross-platform issue labels Aug 2, 2026
@kdeldycke

Copy link
Copy Markdown

Confirming the premise from an MX Ergo's own 0x1B04 table. Source: Logi Options' HID++ response cache, decoded from 0x1B04 getCidInfo.

idx  CID   TID   flags  decoded
6    0x5B  0x3F  0x71   mouse|reprog|divertable|persist
7    0x5D  0x40  0x71   mouse|reprog|divertable|persist

0x71 is identical to what 0x52 (middle), 0x53 (back), 0x56 (forward) and 0xED (DPI switch) report on this device, and those are already bindable. So no device-specific quirk is needed: these are ordinary divertable controls with no ButtonId in crates/openlogi-core/src/binding/button.rs.

PreviousDesktop / NextDesktop already exist in crates/openlogi-core/src/binding/action.rs, so this PR is sufficient to bind tilt to space switching.

Cross-reference: #359 targets the same two controls from the OS hook side by intercepting horizontal scroll rather than diverting the CID.

Can test against two MX Ergo units, Unifying and Bluetooth, once #367 is unblocked.

@ghjkllasdf-fake

Copy link
Copy Markdown

Thanks for working on this. I am testing wheel-tilt remapping with an MX Anywhere 2S on Windows and wanted to share some device-specific follow-up.

For this device:

  • The wheel tilt controls are exposed through HID++ 0x1b04 as CIDs 0x5B and 0x5D.
  • The asset metadata uses SLOT_NAME_LEFT_SCROLL_BUTTON and SLOT_NAME_RIGHT_SCROLL_BUTTON.
  • Native horizontal scrolling should remain unchanged until a tilt binding is customized.
  • When mapped to Volume Up/Down, holding the tilt should continue changing the volume, matching Logitech Options+. A single rising-edge event only changes the volume once.

This looks like a good fit for this PR's HID++ diversion approach, rather than generic horizontal-scroll interception, because the HID++ controls provide the exact tilt direction and avoid confusing tilt with thumbwheel input.

Could this PR be rebased onto the current master and extended with the MX Anywhere 2S metadata names and held-volume behavior?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform: all Cross-platform issue type: feature New feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants