AprilNEA / AprilNEA/OpenLogi

macOS 27: gestures fail when CGEvent sender ID is zero

Open
#965 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

## Summary

On macOS 27.0, mouse gestures assigned to physical buttons do not start, regardless of which button is configured. Ordinary clicks can still be observed, but holding a configured button and moving the mouse does not create a gesture hold state.

I reproduced this with an MX Master 3S connected through a Logitech USB receiver on arm64. The issue is present in v0.7.10 and current `master` (`c430364`).

## Root cause

The side-button `CGEvent`s are delivered normally (down / dragged / up), but macOS 27 reports:

```text
IOHIDEventGetSenderID(...) == 0
```

The current macOS hook therefore cannot construct an `EventDevice` from the event sender. The event reaches the gesture watcher with `device = None`, and the existing strict device-ownership check correctly declines to intercept an event whose source is unknown. As a result, the button-down transition never creates `HoldState`, so every configured gesture appears inactive.

The physical HID state is still available through `IOHIDManager`. During the same button-down transition, the corresponding Logitech mouse reports the button element as pressed.

## Proposed fix

For button events whose sender ID is zero:

1. Keep a long-lived `IOHIDManager` in the macOS event-tap state.
2. Map CoreGraphics button number `N` to HID button usage `N + 1`.
3. On button down, query the current value of that usage on attached primary mouse devices.
4. Attribute the event only when exactly one device reports the button as pressed and that device is Logitech.
5. Cache the resolved device by button number and reuse it for the matching button-up event.
6. Preserve the existing fail-closed behavior when there is no match, a non-Logitech match, or more than one pressed candidate.

This avoids broadly claiming sender-less events and keeps the normal sender-ID path unchanged on older macOS versions.

## Patch branch

- Branch: https://github.com/wilson0312/OpenLogi/tree/fix/macos-27-senderless-buttons
- Compare: https://github.com/AprilNEA/OpenLogi/compare/master...wilson0312:OpenLogi:fix/macos-27-senderless-buttons
- Commit: `112697271b34db556bab42dd91d870cf33f36163`

The patch adds `SenderlessButtonResolver`, integrates it into the macOS event-tap callback, and includes tests for unique Logitech selection, ambiguous/non-Logitech rejection, and release-source caching.

## Validation

Automated checks:

```text
cargo fmt --check passed
cargo check -p openlogi-hook passed
cargo clippy -p openlogi-hook --all-targets -- -D warnings passed
sender-less resolver tests (3) passed
```

Manual validation on macOS 27.0:

```text
gesture swipe -> button=Forward dir=Left action=Previous Desktop
gesture swipe -> button=Forward dir=Right action=Next Desktop
```

Repeated left/right gestures were recognized and executed. Existing behavior for ordinary buttons remained intact.

One unrelated existing hook test could not create a private `CGEventSource` in this environment; the other 16 hook tests passed.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start at the macOS event-tap callback and review the SenderlessButtonResolver integration described in the issue. Run the listed sender-less resolver tests and the openlogi-hook checks; done means unique Logitech devices are selected safely, ambiguous or non-Logitech matches are rejected, release events use cached sources, and existing sender-ID behavior remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, rust
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.