[Bug]: Two simultaneously connected direct-Bluetooth Lift mice lose button actions on macOS
- Dominant language
- Rust
- Stars
- 21k
- Forks
- 675
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 172
Description
# Issue: Two simultaneously connected direct-Bluetooth Lift mice lose button actions on macOS
## Summary
When two Logitech Lift Vertical Ergonomic Mouse devices are connected directly over Bluetooth at the same time, OpenLogi can no longer deliver button actions reliably from either device. For example, pressing the center button configured as Mission Control only produces a brief visual flash; Mission Control does not open. The other configured buttons are unavailable as well.
This report is based on a deterministic code-path reproduction of the device-route collision that occurs when two identical direct-Bluetooth devices are online. The final physical two-device interaction could not be completed during this run because the host currently had one Lift connected and the second Lift paired but not connected; the collision itself was reproduced with the current source and matches the reported symptom.
## Environment
- OpenLogi source: `upstream/master` at `46c227cc9` (`fix(hid): keep pairing phase after device selection (#1181)`)
- Installed OpenLogi observed on the host: `0.8.3`
- macOS: `15.7 (24G222)`
- Hardware: two Logitech Lift Vertical Ergonomic Mouse devices, connected directly over Bluetooth (not through a Bolt/Unifying receiver)
- USB vendor/product identity: `046d:b031`
- HID++ collection observed: `ff43:0202`
- OpenLogi Input Monitoring permission: granted; the agent successfully installed its mouse hook
- Both devices have separate serial-backed profiles in the local configuration. Both profiles use the same direct route identity (`direct:046d:b031`). Serial numbers are intentionally omitted from this public report.
## Steps to reproduce
1. Pair two Logitech Lift mice with macOS and connect both at the same time using direct Bluetooth.
2. OpenLogi should discover both devices as separate physical devices.
3. Configure separate profiles for the two Lifts. For example:
- Center button: `MissionControl`
- Back button: `BrowserBack`
- Forward button: `BrowserForward`
4. Restart OpenLogi, or wait for the agent to finish device discovery and capture-session startup.
5. Press the center button on either Lift, then try the Back and Forward buttons on both devices.
## Expected behavior
Each physical Lift has its own capture session and profile. Pressing a button on either device invokes that device's configured action. In particular, the center button opens Mission Control reliably for both Lifts.
## Actual behavior
- Button actions from both Lifts become unavailable or unreliable.
- Pressing the center button may cause a brief flash, but Mission Control does not open.
- The same failure affects the other configured buttons, not only Mission Control.
- The problem is specific to having two identical direct-Bluetooth Lift devices online; a single connected Lift works normally.
## Reproduction evidence
The host state during this investigation was:
- One Lift (`LIFT-W`) connected and visible to the running agent.
- A second Lift (`LIFT`) paired but not connected, plus another paired device entry (`LIFT-B`).
- The local OpenLogi configuration contained two distinct Lift profiles backed by different device identities, confirming the two-device configuration that triggered the report exists on this machine.
A temporary focused diagnostic test was added to the current source and intentionally removed after the test run. It constructed two `NodeInfo` values with different stable identities but the same Lift VID/PID and asserted that a direct route for the first device must not match the second. The test failed:
```text
direct_routes_must_distinguish_identical_devices_by_serial ... FAILED
a direct route must not match a second identical-product device
test result: FAILED. 0 passed; 1 failed
```
This demonstrates that the direct route currently cannot distinguish the two identical devices. The live two-device button press remains to be confirmed by a maintainer with both Lifts connected simultaneously.
## Technical diagnosis
The direct route is defined only by vendor/product ID:
- `crates/openlogi-core/src/hid/route.rs:53-62` defines `DeviceRoute::Direct { vendor_id, product_id }` and documents that identical direct devices are indistinguishable and that the first match wins.
- `crates/openlogi-device/src/channel/route.rs:41-80` opens a direct route by enumerating HID++ nodes, filtering by VID/PID, and returning the first matching channel.
- `crates/openlogi-device/src/channel/route.rs:124-130` treats a direct route as matching a node when only VID/PID match; the node's stable identity/serial is not part of the decision.
- `crates/openlogi-device/src/channel/registry.rs:81-86` and `:209-213` preserve the oldest live publication as the winner when identical direct devices publish the same route.
- The agent correctly creates separate plans/sessions keyed by physical device identity, but `crates/openlogi-device/src/session/gesture.rs:256-280` resolves each session through the same route-only registry lookup. Therefore, two physically distinct Lifts can resolve to one shared/oldest HID channel and compete for the same input reports.
The existing duplicate-identity orchestration test passes, which indicates that device identity discovery and profile selection are not the failing layer. The collision occurs later at the route/channel ownership boundary.
## Suggested fix direction
Please make direct-device channel ownership unambiguous. Possible approaches include carrying a stable HID-node identity/serial in the direct route, or introducing a channel lookup keyed by the physical/node identity rather than VID/PID alone. The solution should preserve configuration and IPC compatibility as appropriate, and must ensure that two identical direct devices never share one capture channel.
## Acceptance criteria
- Two direct-Bluetooth Lift mice can remain connected simultaneously.
- Each Lift's center, Back, and Forward buttons invoke the configured actions.
- Mission Control opens reliably from the center button on either Lift.
- Disconnecting one Lift leaves the other Lift functional.
- Reconnecting either Lift binds it back to the correct physical profile.
- Single-device direct Bluetooth behavior remains unchanged.
- Bolt/Unifying receiver devices and other device families do not regress.
## Additional validation
The following existing tests passed after removing the temporary diagnostic harness:
```text
cargo test -p openlogi-device --lib
204 passed, 0 failed
cargo test -p openlogi-agent-core --lib orchestrator::tests::reapply_targets_disambiguates_same_model_duplicates -- --exact --nocapture
1 passed, 0 failed
```
No product source was changed for this report. Runtime verification on two simultaneously connected Lifts is still required once both devices are available online.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with DeviceRoute in crates/openlogi-core/src/hid/route.rs and the direct-route handling in crates/openlogi-device/src/channel/route.rs, then inspect registry.rs and session/gesture.rs. Run the focused route distinction test described in the issue and the existing openlogi-device and orchestrator tests. Done means identical direct-Bluetooth devices use separate channels without regressing single-device or receiver behavior.
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
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 66/100