Skip to content

fix(hid): capture a middle button the device declares as its gesture button - #1472

Open
f-o-s-s-b-i-t-e wants to merge 1 commit into
AprilNEA:masterfrom
f-o-s-s-b-i-t-e:fix/device-declared-middle-gesture-button
Open

f-o-s-s-b-i-t-e wants to merge 1 commit into
AprilNEA:masterfrom
f-o-s-s-b-i-t-e:fix/device-declared-middle-gesture-button

Conversation

@f-o-s-s-b-i-t-e

Copy link
Copy Markdown

Summary

On the MX Anywhere 2S the physical button behind the wheel is HID++ CID 0x0052 with the Gesture Button Navigation task — not an ordinary middle click. v0.8.5 preserves existing Middle Click gesture maps and keeps them editable, but the runtime never captured 0x0052: the capture plan only plain-diverted it as ButtonId::MiddleClick when the hook did not own it, and macOS routed gesture-mode Middle Click to the OS hook, which passes unattributed Bluetooth-direct presses through. The button therefore kept running its firmware gesture task (Mission Control) while the configured direction map could never dispatch.

This routes 0x0052 through the same device-owned raw-XY capture path as Back/Forward, armed only when the device's own control table declares a gesture-button task — an ordinary middle button never becomes a gesture source.

Changes

  • openlogi-device
    • GESTURE_BUTTON_TASK_IDS (0x00a9 Gesture Button Navigation, 0x00ad Multi Platform Gesture Button) and CtrlIdInfo::is_gesture_button().
    • CaptureSpec::divert_gesture_navigation: raw-XY requests armed only when the control is divertable, raw-XY capable, and carries one of those tasks. The decision is logged (gesture-navigation capture request cid=… task=… flags=… confirmed=…) so a mis-gated model is diagnosable from the agent log.
  • openlogi-agent-core
    • hidpp_middle_gesture_maps_for: on macOS, a preserved Middle Click map requests (0x0052, MiddleClick); the plan routes it to the task-gated list and merges the map into side_gesture_bindings so captured swipes dispatch like Back/Forward.
    • The OS hook keeps Middle Click as the fail-open owner, so a device whose 0x0052 task is 0x003a (MX Master 3S, MX Vertical, …) keeps exactly its current behavior.
  • Tests: device-layer task gate (arms on 0x00a9/0x00ad, refuses 0x003a), capture-plan request / no-request cases, hook-fallback pin.

Testing

Repository validation (Linux container, Rust 1.98; this branch changes no workspace-wide build input):

  • cargo fmt --all -- --check
  • RUSTFLAGS=-D warnings cargo clippy -p openlogi-device -p openlogi-hid -p openlogi-cli -p openlogi-agent -p openlogi-agent-core -p openlogi --all-targets -- -D warnings
  • the same clippy for --target aarch64-apple-darwin, plus cargo check for x86_64-apple-darwin on the changed crates
  • RUSTDOCFLAGS=-D warnings cargo doc -p openlogi-device -p openlogi-agent-core --no-deps --document-private-items
  • cargo test -p openlogi-device -p openlogi-hid -p openlogi-cli -p openlogi-agent -p openlogi-agent-core -p openlogi
  • typos with the repo config

The GUI crates were not built locally (no graphics toolchain in the container); CI covers them. Not runtime-tested on Linux, Windows, or a receiver-attached device.

Hardware verification (reporter's device, not a maintainer test): MX Anywhere 2S, Bluetooth-direct, unit:e6c912de, macOS 15.7.9 x86_64.

  • Before: control capture active … gesture_buttons=0, no gesture dispatch lines at all.
  • After:
    DEBUG gesture-navigation capture request cid=0x0052 task=0x00a9 flags=0x0131 button=Middle Click confirmed=true
    INFO  control capture active index=255 gesture_sources=0 gesture_buttons=1 dpi_buttons=0 buttons=3 thumbwheel=false
    DEBUG gesture click button=Middle Click
    DEBUG gesture → action key="unit:e6c912de" button=Middle Click direction=Click action=Close Tab
    DEBUG gesture committed direction=Up button=Middle Click
    DEBUG gesture → action … direction=Up action=Mission Control
    

How to test:

  1. macOS + a device exposing 0x0052 with a gesture task (openlogi diag controls), with a preserved bindings.MiddleClick map.
  2. Run the agent with OPENLOGI_LOG=openlogi_device=debug,openlogi_agent_core=debug.
  3. Expect confirmed=true and gesture_buttons=1; click and hold+direction now run the map, and the factory action is gone.
  4. Regression: on a device whose 0x0052 task is 0x003a, the same config must log confirmed=false and leave the middle button on the OS-hook path.

Related to #946, #1356; sibling of #1385 (M720, 0x00d0/task 0x00ad) — the predicate added here could later replace that PR's model-key gate, but this PR does not change the M720 path, nor the GUI's Middle Click eligibility policy (#1410), nor ordinary middle buttons (#560/#1262).

Fixes #1471

…button

The MX Anywhere 2S reports its physical Middle Button (0x1b04 CID 0x0052)
with the `Gesture Button Navigation` task instead of an ordinary middle
click. OpenLogi only ever plain-diverted 0x0052, and macOS side gestures
excluded Middle Click from HID++ capture, so the control was never
diverted and its factory gesture behavior stayed active: pressing the
button leaked the firmware action while the preserved
`bindings.MiddleClick` direction map never ran.

Request CID 0x0052 as a raw-XY gesture source when a preserved Middle
Click map exists on macOS, and arm it only when the device's own control
row carries a gesture-button task (0x00a9 `Gesture Button Navigation` or
0x00ad `Multi Platform Gesture Button`). Ordinary middle buttons keep the
flags-based plain divert and the OS hook keeps dispatching the map as the
fail-open owner, so a normal mouse is unaffected.
@greptile-apps

greptile-apps Bot commented Sep 17, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the new capture path is narrowly gated and preserves the existing fallback for ordinary middle buttons.

Summary

This PR enables macOS HID++ capture of a preserved Middle Click gesture map when CID 0x0052 is confirmed by device metadata to be a gesture button.

  • Adds task-based gesture-button classification for HID++ controls.
  • Introduces a separately gated raw-XY capture request for gesture-navigation controls.
  • Preserves OS-hook ownership as the fallback for ordinary middle buttons.
  • Adds capture-plan, lifecycle, task-gating, and diversion tests.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Preserved Middle Click gesture map] --> B{macOS mouse hook available?}
    B -- No --> C[Keep OS-hook behavior]
    B -- Yes --> D[Request CID 0x0052 gesture-navigation capture]
    D --> E{Control is divertable, raw-XY capable, and has task 0x00a9 or 0x00ad?}
    E -- No --> C
    E -- Yes --> F[Arm HID++ raw-XY diversion]
    F --> G[Dispatch click or swipe through side gesture bindings]
Loading

Reviews (1) · Last reviewed commit: "fix(hid): capture a middle button the de..."

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

Labels

None yet

Projects

None yet

1 participant