AprilNEA / AprilNEA/OpenLogi

[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

Closed
#1,262 0 comments 0 reactions 0 assignees View on GitHub
platform: macos type: bug
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.