[Bug]: Middle/Back/Forward bindings are silently dead when the CGEvent carries no IOHIDEvent (macOS)
- Dominant language
- Rust
- Stars
- 21k
- Forks
- 675
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 172
Description
### Pre-flight
- Searched existing issues. #917 is the other half of the same symptom but a different bug (a stale `0x1b04` diversion). This one survives after that is fixed.
- Reproduced on 0.7.10 and on `master` @ 013ab99.
- Logi Options+ is not installed on this machine.
### Which part of OpenLogi?
Both — the fault is in the agent's OS hook.
### OpenLogi version
0.7.10, and `master` @ 013ab99.
### Operating system
macOS
### OS version & architecture
macOS 26.5 (build 25F71), Apple Silicon
### Device model
MX Anywhere 3S
### How is the device connected?
Logi Bolt receiver (`btle = true`).
### Affected area(s)
`area: hook`, `platform: macos`.
### What happened?
Every Middle/Back/Forward binding on this mouse is dead, and gesture mode on those buttons never fires — while the primary buttons remap normally on the same device.
`handle_button` gives up before it ever reads the binding:
```rust
if !id.is_os_hook_button() || !button_source_may_remap(device) {
return EventDisposition::PassThrough;
}
```
`button_source_may_remap` fails closed when attribution is missing:
```rust
None => {
// On macOS fail closed — an unattributed event is more likely a
// trackpad/system source than a Logi mouse.
!cfg!(target_os = "macos")
}
```
On this mouse the middle button's CGEvent carries **no IOHIDEvent at all** — `CGEventCopyIOHIDEvent` returns null, so `event_sender_id` returns `None` and `button_source` yields `None`. Probing `handle_button` on an instrumented `master` build, same mouse, same session:
```
XXPROBE entry id=LeftClick pressed=true device=Some(EventDevice { vendor_id: Some(1133),
product_id: Some(50504), product_name: Some("USB Receiver") })
oshook=false may_remap=true
XXPROBE entry id=MiddleClick pressed=true device=None oshook=true may_remap=false
```
110 `MiddleClick` events, every one unattributed; 140 `LeftClick` events, every one attributed. So it is not a transient — this mouse simply delivers its auxiliary buttons through a collection that carries no sender.
The failure is completely silent. The events reach the tap, `handle_button` runs, the config is right, the plan is right, and the hook maps are right (`gkeys=[MiddleClick]`) — the event is just handed back before any of that is consulted. Gesture mode is the worst case: the hook never claims the press, so hold-and-swipe never fires and the button looks broken.
### Steps to reproduce
1. On a mouse whose auxiliary buttons arrive unattributed, bind Middle Click to anything (single action or gesture mode).
2. Press it.
Whether a given mouse is affected can be read straight off `button_source(event)` returning `None` for `OtherMouseDown` while `LeftMouseDown` resolves.
### Expected
The bound action fires.
### Actual
Nothing fires, on any of Middle/Back/Forward. Primary buttons are unaffected.
### Suggested fix
Nothing the closed rule protects can be the source here: no trackpad emits button 2/3/4, and `handle_button` has already narrowed to the OS-hook buttons before the check runs. So the conservative rule buys nothing on those three while costing every binding on them.
Give Middle/Back/Forward the benefit of the doubt when attribution is absent — exactly as Linux and Windows already do — and keep the primary buttons failing closed, where an unattributed left/right click really could be a trackpad.
PR follows, together with #917. With both applied, hold-and-swipe on the middle button works on this hardware.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the handle_button, button_source_may_remap, and event_sender_id entry points described in the issue. Reproduce with an unattributed OtherMouseDown and an attributed LeftMouseDown, then verify that auxiliary-button bindings and gesture mode fire while primary-button fail-closed behavior remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100