[Bug]: macOS: wheel-button (MiddleClick) gesture mode never fires on a Bluetooth-direct MX Master 3S — it still goes through the global hook that #722 moved Back/Forward off
- Dominant language
- Rust
- Stars
- 21k
- Forks
- 675
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 172
Description
### Pre-flight checklist
- [x] I searched existing issues and this is not a duplicate. Closest: #560 (same symptom, MX Master 3S over Bluetooth, pre-#722), #920 (unattributed middle-button CGEvents on a Bolt receiver), #917, #946, #465 (comment). None of them tracks the state *after* #722 landed in 0.8.2, which is what this report is about.
- [x] I am on the latest release: 0.8.3 (first hit on 0.8.1, re-tested on 0.8.3 today — identical).
- [x] Logi Options+ is not installed (no Options+ app, no `com.logitech.manager` process running). Logi Tune is running, but it does not touch the mouse.
### Which part of OpenLogi?
Both — the agent's capture plan is the fault; the GUI shows the binding as configured.
### OpenLogi version
0.8.3 (Homebrew cask)
### Operating system
macOS
### OS version & architecture
macOS 26.5.2 (25F84), Apple Silicon (arm64)
### Device model
MX Master 3S for Business (`046d:b035`), no receiver
### How is the device connected?
Bluetooth (direct, no receiver)
### Affected area(s)
- [x] Button remapping
### What happened?
I put the wheel button (**MiddleClick**) into gesture mode with all five slots bound:
```toml
[devices."serial:REDACTED".bindings.MiddleClick]
Up = "MissionControl"
Down = "ShowDesktop"
Left = "PreviousDesktop"
Right = "NextDesktop"
Click = "MissionControl"
```
- Holding the wheel button and moving the mouse in any direction never fires a direction action.
- A plain press does not fire the configured `Click` action either (Mission Control never opens). Where I tested, the press had no visible effect at all.
Everything else on the same mouse works:
- **MiddleClick as a single action** (`MiddleClick = "MissionControl"`) fires immediately — that path is HID++-diverted.
- **Back/Forward in gesture mode** work since 0.8.2 (#722).
- GestureButton, DpiToggle and thumbwheel bindings all work.
Expected: hold-and-swipe on the wheel button fires the bound direction and a plain press fires `Click`, the same way Back/Forward gesture mode behaves after #722.
### Steps to reproduce
1. MX Master 3S (3S for Business here) paired directly over Bluetooth, no receiver.
2. GUI → mouse → Buttons: switch **Middle Click** to gesture mode and bind Up/Down/Left/Right/Click to any visible action (Mission Control, Show Desktop, ...).
3. Hold the wheel button, move the mouse a few centimetres in any direction, release → nothing.
4. Press the wheel button without moving → the configured `Click` action does not fire.
5. Switch Middle Click back to a single action (e.g. Mission Control) → fires immediately.
### Why (code reading against v0.8.3)
The gesture-mode wheel button is the one OS-hook control that #722 left on the global CGEventTap:
- `capture_plan.rs` → [`hidpp_side_gesture_maps_for`](https://github.com/AprilNEA/OpenLogi/blob/v0.8.3/crates/openlogi-agent-core/src/capture_plan.rs#L83-L95) keeps only `ButtonId::Back | ButtonId::Forward`. A gesture-mode `MiddleClick` therefore stays in the `oshook` map, is filtered out of `divert_buttons`, and is left native so that "the hook sees the press".
- The hook then refuses it: [`button_source_may_remap`](https://github.com/AprilNEA/OpenLogi/blob/v0.8.3/crates/openlogi-agent-core/src/runtime/hook.rs#L202-L209) fails closed on macOS when the CGEvent carries no sender, and [`handle_button`](https://github.com/AprilNEA/OpenLogi/blob/v0.8.3/crates/openlogi-agent-core/src/runtime/hook.rs#L254-L256) returns `PassThrough` before the gesture map is ever consulted. The hold never begins, so neither `Click` nor any direction can fire.
- That is exactly what #722 diagnosed for the Forward button on an MX Master 3 ("every Forward press and release arrived with `device=None`"), and what #920 measured for MiddleClick on a Bolt receiver (`CGEventCopyIOHIDEvent` returns null for the auxiliary buttons). The fix in #722 moved the button lifecycle *and* the swipe motion to the device's own HID++ raw-XY channel — but only for CIDs `0x0053`/`0x0056`.
From the outside I cannot tell whether a native middle click leaks through (the pass-through above) or the button is fully dead because the single-action session I had on the same button before left a stale `0x1b04` diversion behind (#917). Both end in the same place — the swipe never starts — and both are fixed by owning the control over HID++. Happy to check with Karabiner-EventViewer if that distinction matters.
The wheel button advertises the same capabilities as the two side buttons, so the #722 path is available to it as-is:
```text
$ openlogi diag controls
device: MX Master 3S For Business (direct 046d:b035)
cid task flags capabilities
0x0052 0x003a 0x0531 divertable, raw-xy, analytics-events ← MiddleClick
0x0053 0x003c 0x0531 divertable, raw-xy, analytics-events ← Back (handled by #722)
0x0056 0x003e 0x0531 divertable, raw-xy, analytics-events ← Forward (handled by #722)
0x00c3 0x00a9 0x0531 divertable, raw-xy, analytics-events
0x00c4 0x009d 0x0531 divertable, raw-xy, analytics-events
0x00d7 0x00b4 0x03a0 divertable, raw-xy, force-raw-xy
```
### Proposed fix
Extend #722 to the wheel button: let `hidpp_side_gesture_maps_for` (or a renamed `hidpp_oshook_gesture_maps_for`) include `ButtonId::MiddleClick`, so a gesture-mode `0x0052` gets the raw-XY divert and its clicks/swipes resolve through the existing HID++ gesture accumulator. The plain-click case should synthesise a middle click (`Effect::Click(MouseButton::Middle)`) when `Click` is left at its default, the same way Back/Forward clicks resolve today. I'm happy to test a build on this hardware.
### Diagnostics report
Collected from the CLI and the agent log (I can paste the About → Copy Diagnostics block on request):
- OpenLogi (GUI/agent): 0.8.3, Homebrew cask; agent running from `OpenLogi.app/Contents/Library/LoginItems/OpenLogi Agent.app`
- OS: macOS 26.5.2 (arm64)
- Accessibility: granted (`accessibility granted — installing OS mouse hook` / `OS input hook installed` in the log) · Input Monitoring: granted (the agent opens the HID++ channel; the single-action remaps work)
- Config: schema 6 · `capture_mouse_events = true` · `smooth_scroll = false`
### `openlogi list` output
```text
(inventory read from the running agent)
MX Master 3S B (—, vid=046d pid=b035)
└─ slot 255 ● MX Master 3S For Business (mouse, wpid=?, battery=85% full (discharging))
model_ids=[b035,0000,0000] ext=00 serial=REDACTED unit_id=REDACTED transports=btle
```
### Logs
0.8.3 agent start and the capture summary with the wheel button in gesture mode. `buttons=1` is the GestureButton's single binding; `0x0052` is deliberately not in the divert set while MiddleClick is in gesture mode, and `gesture_buttons=0` because Back/Forward are single actions:
```shell
2026-09-04T05:34:46.474875Z INFO openlogi_agent::lifecycle: accessibility granted — installing OS mouse hook
2026-09-04T05:34:46.476540Z INFO openlogi_agent_core::runtime::hook: OS input hook installed
2026-09-04T05:35:41.173344Z INFO openlogi_device::session::gesture: control capture active index=255 gesture_sources=0 gesture_buttons=0 dpi_buttons=1 buttons=1 thumbwheel=true wake_rearm=true
```
Across all retained agent logs (2026-08-28 → 2026-09-04, `~/.local/state/openlogi/agent.*.log`) there is not a single `gesture click → executing bound action` / `gesture swipe → executing bound action` line for the wheel button, although gesture mode was configured and used for several days on 0.8.1 and again today on 0.8.3. No WARN/ERROR is emitted for the dropped presses — the failure is silent, as #920 also noted.
### macOS permissions (if applicable)
- [x] OpenLogi has **Accessibility** permission
- [x] OpenLogi has **Input Monitoring** permission
Refs #722, #560, #920, #917, #946, #465
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in crates/openlogi-agent-core/src/capture_plan.rs at hidpp_side_gesture_maps_for, then compare the Back/Forward path with crates/openlogi-agent-core/src/runtime/hook.rs, especially button_source_may_remap and handle_button. Verify that MiddleClick control 0x0052 uses the existing HID++ raw-XY gesture path, with direction actions and the configured or default Click behavior working on the reported Bluetooth MX Master 3S.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, rust
- Domain
- embedded-iot, operating-systems
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100