Skip to content

feat(gui): expose host_switch_targets in the device Device tab - #1449

Open
4ni1ak wants to merge 2 commits into
AprilNEA:masterfrom
4ni1ak:feat/host-switch-targets-gui
Open

4ni1ak wants to merge 2 commits into
AprilNEA:masterfrom
4ni1ak:feat/host-switch-targets-gui

Conversation

@4ni1ak

@4ni1ak 4ni1ak commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Easy-Switch mouse-follow-keyboard (HID++ 0x1814/0x1815) is fully implemented agent-side (crates/openlogi-agent-core/src/watchers/host_switch.rs, crates/openlogi-device/src/session/host_switch.rs), driven by DeviceConfig::host_switch_targets: Vec<String> — but there was no GUI to set that field. The only way to link a mouse to a keyboard's host-switch channel was hand-editing config.toml, which isn't documented anywhere. See [Bug]: Mouse does not follow keyboard on Easy-Switch host change #1145.

Changes

  • crates/openlogi-core/src/config.rs: Config::host_switch_targets/set_host_switch_targets accessors, mirroring the existing dpi_presets pair.
  • crates/openlogi-desktop/src/state/host_switch.rs (new): AppState::host_switch_candidates() lists other configured, persistent keyboards for the active pointing device, each with whether it's already following; AppState::set_host_switch_follow() adds/removes the active device from a given keyboard's host_switch_targets and persists.
  • crates/openlogi-desktop/src/app/detail.rs: a "Follow host switches from" card in the Device tab, shown only when the active device is a persistent mouse/trackball with at least one other configured keyboard. One plain Switch per keyboard — no new UI chrome, matching the existing settings-row style.
  • crates/openlogi-ui/locales/*.toml: one new key (device.host_switch_targets), added at the same position in every catalog. Non-English catalogs currently carry the English string pending a real translation via Crowdin, per this repo's stated policy for that case.

The card reads/writes the other device's (the keyboard's) config entry rather than the currently-selected device's, since that's where host_switch_targets actually lives — the relationship is keyboard-initiated.

Testing

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace (all green, including two new tests in state::host_switch::tests covering candidate filtering and the follow/unfollow toggle)
  • cargo test -p openlogi-ui locale (catalog parity) and cargo test -p openlogi-desktop i18n (key resolution)
  • cargo doc --workspace --no-deps --document-private-items (excluding the GPUI crates)
  • Compiled and ran openlogi-desktop against openlogi-agent-mock with the openlogi-canonical-synthetic-001 fixture to confirm the binary starts correctly with these changes present.
  • Not visually verified — no safe display available in this environment to screenshot the new card rendering (the only display here is the operator's own real desktop session). A maintainer/reviewer should confirm the panel lays out correctly and the toggle round-trips through config.toml as expected before merging.

Fixes #1145

Easy-Switch mouse-follow-keyboard support (HID++ 0x1814/0x1815) has been
fully implemented in the agent since host_switch_targets was added to
DeviceConfig, but nothing in the GUI ever let a user configure it — the
only way to link a mouse to a keyboard's host-switch channel was hand-
editing config.toml, undocumented anywhere.

Add a "Follow host switches from" card to the Device tab, shown only for
a persistent mouse/trackball with at least one other configured keyboard.
Each keyboard gets a plain toggle; checking it adds the active pointing
device's config key to that keyboard's host_switch_targets, unchecking
removes it. The card reads and writes the other device's config entry
rather than the current one, since that's where the field actually lives.

No wire/schema change: host_switch_targets already round-trips through
config.toml. New Config::host_switch_targets/set_host_switch_targets
accessors mirror the existing dpi_presets pair. Reused existing locale
keys where possible; the one new string (device.host_switch_targets) is
added at the same position in every locale catalog, English text pending
translation via Crowdin.

Fixes AprilNEA#1145
@4ni1ak
4ni1ak requested a review from AprilNEA as a code owner September 17, 2026 03:12
@greptile-apps

greptile-apps Bot commented Sep 17, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

The PR is not yet safe to merge because its capability gates can both expose a target that runtime switching cannot use and hide a keyboard that the runtime does support.

Fix All in CodexFindings

  1. P1 HostsInfo Falsely Enables Switching
  2. P1 Task-Based Controls Stay Hidden

Summary

This PR exposes host-switch relationships in the Device tab, persists links on the source keyboard, and extends inventory capabilities and IPC serialization so the GUI can gate the feature using measured hardware support.

  • Adds host-switch target configuration accessors and desktop state/UI controls.
  • Publishes source and target host-switch capabilities from HID++ feature/control probes.
  • Bumps the IPC protocol and updates its golden wire-format test.
  • Adds locale entries and capability-filtering tests.
  • Two capability definitions remain inconsistent with the runtime’s actual feature and control matching.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
    UI[Device tab switch] --> State[Desktop host-switch state]
    State --> Config[Keyboard host_switch_targets]
    Config --> Reload[Agent config reload]
    Inventory[HID++ capability probe] --> Gate[Source and target capability gates]
    Gate --> UI
    Reload --> Session[Host-switch session]
    Session --> Keyboard[Observe keyboard channel]
    Session --> Pointer[Change pointing-device host]
Loading

Reviews (2) · Last reviewed commit: "fix(gui,core,device,ipc): gate host-swit..."

Comment thread crates/openlogi-desktop/src/state/host_switch.rs
host_switch_candidates() gated the active pointing device and its
candidate keyboards on DeviceKind alone, so an unsupported pairing
(a mouse without ChangeHost, or a keyboard with no armable host-switch
control) could still be toggled on with no way for the agent to ever
act on it.

Adds two feature-derived capabilities: Capabilities::host_switch_target
(HID++ 0x1814/0x1815 ChangeHost — required on the device being switched
to) and Capabilities::host_switch_source (an armable host-switch-channel
control in the 0x1b04 control table — required on the keyboard sending
the switch), computed the same way as every other capability flag.
Gates host_switch_candidates() on both instead of kind.

Capabilities rides the IPC wire, so this bumps PROTOCOL_VERSION 31->32
and regenerates the wire_format golden.

Addresses the Greptile P1 finding on AprilNEA#1449.
Comment on lines 158 to +170
@@ -155,6 +167,8 @@ impl Capabilities {
haptic_feedback: ids.contains(&0x19b0),
haptic_panel: false,
dpi_gestures: false,
host_switch_target: has(&CHANGE_HOST),

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 HostsInfo falsely enables switching

A device is marked as a host-switch target when it exposes either 0x1814 or 0x1815, but the runtime requires 0x1814 (ChangeHost) to perform the switch. A pointing device that exposes only 0x1815 (HostsInfo) will therefore appear in the GUI and can be saved as a target, but every attempted host change will fail as unsupported.

Knowledge Base Used: Device integration stack

Fix in Codex Fix in Claude Code

Comment on lines +353 to +354
host_switch_source |= HOST_SWITCH_CIDS.contains(&info.cid.0)
&& (info.flags.is_divertable() || info.flags.supports_analytics_key_events());

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 Task-based controls stay hidden

This probe recognizes host-switch controls only by CID, while the runtime recognizes them by either CID or host-switch task ID. A keyboard that uses task IDs 0xAE0xB0 with a different CID can be armed by the runtime but receives host_switch_source = false, so the GUI hides a supported keyboard and the user cannot configure the link.

Knowledge Base Used: Device integration stack

Fix in Codex Fix in Claude Code

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.

[Bug]: Mouse does not follow keyboard on Easy-Switch host change

1 participant