Skip to content

Feat/linked host switching - #479

Draft
LCozatl wants to merge 4 commits into
AprilNEA:masterfrom
LCozatl:feat/linked-host-switching
Draft

Feat/linked host switching#479
LCozatl wants to merge 4 commits into
AprilNEA:masterfrom
LCozatl:feat/linked-host-switching

Conversation

@LCozatl

@LCozatl LCozatl commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Add keyboard-initiated Easy-Switch synchronization for linked Logitech pointing devices.

When an Easy-Switch key is pressed on a compatible keyboard, OpenLogi switches every configured pointing device to the corresponding host channel before switching the keyboard. This allows the
configured devices to move together between hosts.

Implementing this feature also exposed a HID++ capture lifecycle issue: a device returning after an Easy-Switch transition retained its route but did not restart capture. The capture target now
follows the device's online state without resetting its DPI-cycle position.

Changes

  • openlogi-core

    • Add host_switch_targets to the per-device TOML configuration.
    • Support serialization and deserialization of physical target device keys.
  • openlogi-hid

    • Detect host-switch controls exposed through HID++ reprogrammable controls.
    • Support diverted-control and analytics-event reporting modes.
    • Switch configured pointing devices before switching the initiating keyboard.
    • Reuse the receiver channel when linked devices share a Bolt or Unifying receiver.
    • Restore temporarily modified control reporting when the session ends.
  • openlogi-agent-core

    • Resolve configured host-switch links against the current device inventory.
    • Rebuild links when the configuration or device availability changes.
    • Require the initiating keyboard to be online while preserving routes for sleeping target devices.
    • Restart HID++ capture when a device returns without resetting its DPI-cycle position.
    • Ignore missing targets and empty link configurations.
    • Add coverage for host-switch links and capture lifecycle transitions.
  • Documentation

    • Document host_switch_targets and provide a TOML configuration example.

Testing

Automated verification:

  • devenv tasks run openlogi:check

OpenLogi hardware testing was performed on Linux using the OpenLogi 0.6.22 RPM package with:

  • MX Master 3S, firmware 22.1.6, linked to an MX Mechanical, firmware 71.3.21.
  • MX Master 3S, firmware 22.1.6, linked to an MX Mechanical Mini, firmware 72.3.14.

Both combinations were tested with the new host-switch synchronization functionality.

Cross-agent behavior was additionally checked using the official Logi Options+ 2.5 client:

  • Windows with a Bolt receiver.
  • macOS over Bluetooth.

These checks confirmed that the devices can switch between corresponding host channels regardless of which agent manages them. OpenLogi itself was not runtime-tested on Windows or macOS as part
of this change.

Known limitations

  • Older keyboard firmware may not expose the HID++ controls or events required by this feature.
  • Every linked device must already be paired with the corresponding channel on each host.
  • The host-switch link must be configured on every computer from which the keyboard can initiate a switch.

LCozatl added 4 commits July 28, 2026 16:03
  - add keyboard-initiated host-switch session handling
  - switch configured pointing devices before the keyboard leaves the host
  - resolve configured host-switch targets through the agent inventory
  - keep sessions synchronized with device availability changes
  - add TOML configuration and tests for host-switch targets
  - add shared runtime storage for resolved host-switch links
  - rebuild links when configuration or device inventory changes
  - require the initiating keyboard to be online
  - preserve routes for sleeping linked target devices
  - ignore missing targets and empty link configurations
  - add coverage for online keyboard and sleeping target behavior
Handle poisoned DPI cycle locks explicitly in the online-state test so the
workspace passes Clippy with unwrap_used denied.
Comment on lines +152 to +154
.get_ctrl_id_info(index)
.await
.map_err(hidpp_error)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Partial arming leaks diversion

When a later HID++ query or reporting write fails after an earlier host control was armed, the error exits run_host_switch_session before restore_host_controls runs, leaving that host key diverted and its native Easy-Switch behavior disabled until the keyboard reconnects or resets.

Knowledge Base Used: openlogi-hid: device inventory, pairing, and HID++ feature control

Fix in Codex Fix in Claude Code

shared.thumbwheel_sensitivity.clone(),
shared.receiver_access.clone(),
);
watchers::host_switch::spawn(shared.host_switch_links.clone());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Receiver access bypasses arbitration

When a configured Bolt or Unifying receiver is already used by gesture capture or pairing, this watcher opens another channel without participating in ReceiverAccess, causing HID++ responses or unsolicited events to reach the wrong channel and breaking host switching, capture, or pairing.

Knowledge Base Used:

Fix in Codex Fix in Claude Code

{
debug!(%error, route = %keyboard, "host switch session ended");
}
let _ = done.send(());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Stale completions cancel replacements

When a link change stops existing sessions and starts replacements, the stopped tasks later send indistinguishable () completions; the receive branch then stops the replacement sessions and clears their state, repeatedly leaving host keys unmonitored between re-arm attempts.

Knowledge Base Used: openlogi-agent-core

Fix in Codex Fix in Claude Code

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown

Greptile Summary

Adds configured keyboard-to-pointing-device Easy-Switch synchronization and repairs capture routing across online-state transitions.

  • Persists and resolves host_switch_targets from per-device TOML configuration.
  • Adds HID++ host-control discovery, reporting-mode management, linked-device switching, and session restoration.
  • Adds an agent watcher that maintains resolved host-switch sessions as inventory and configuration change.
  • Updates capture targets when the selected device goes offline or returns without resetting the DPI-cycle position.
  • Documents the new configuration field and adds focused unit coverage.

Confidence Score: 2/5

This PR should not merge until host-control cleanup, receiver-channel arbitration, and stale session-completion handling are corrected.

Partial setup failures can strand native keyboard controls in diverted mode, host-switch sessions can conflict with pairing or capture on the same receiver, and stale completion notifications can repeatedly cancel newly armed links.

Files Needing Attention: crates/openlogi-hid/src/host_switch.rs, crates/openlogi-agent-core/src/watchers/host_switch.rs, crates/openlogi-agent/src/main.rs

Important Files Changed

Filename Overview
crates/openlogi-hid/src/host_switch.rs Implements HID++ host-switch sessions, but partial arming failures can leave keyboard controls diverted and channel opens bypass receiver arbitration.
crates/openlogi-agent-core/src/watchers/host_switch.rs Maintains host-switch sessions, but untagged stale completion messages can cancel replacement sessions.
crates/openlogi-agent-core/src/orchestrator.rs Resolves configured links and synchronizes capture targets with device online state while retaining DPI-cycle position.
crates/openlogi-core/src/config/device.rs Adds backward-compatible TOML persistence for physical host-switch target keys.
crates/openlogi-agent/src/main.rs Starts the new watcher without the receiver-access dependency required to coordinate receiver HID channels.

Sequence Diagram

sequenceDiagram
  participant Keyboard
  participant Watcher as Host-switch watcher
  participant HID as HID++ session
  participant Targets as Linked pointing devices
  Watcher->>HID: Arm keyboard host controls
  Keyboard->>HID: Host-channel key event
  loop Each configured target
    HID->>Targets: Set corresponding host
  end
  HID->>Keyboard: Set corresponding host last
  HID-->>Watcher: Session completed
  Watcher->>HID: Re-arm when keyboard returns
Loading

Fix All in Codex Fix All in Claude Code

Reviews (1): Last reviewed commit: "test(agent): avoid unwraps in capture li..." | Re-trigger Greptile

@LCozatl
LCozatl marked this pull request as draft July 29, 2026 04:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant