Skip to content

feat(gui): configure Easy-Switch followers - #1123

Open
noobydp wants to merge 11 commits into
AprilNEA:masterfrom
noobydp:feat/easy-switch-followers
Open

noobydp wants to merge 11 commits into
AprilNEA:masterfrom
noobydp:feat/easy-switch-followers

Conversation

@noobydp

@noobydp noobydp commented Aug 28, 2026 •

Copy link
Copy Markdown

Summary

Add a capability-gated Easy-Switch panel for keyboards with reportable host
controls. Users can select locally known ChangeHost-capable followers without
editing TOML, using the existing physical device identities and
host_switch_targets configuration.

Follower links assume that each linked device uses the same Easy-Switch slot
number for the same computer. OpenLogi does not currently detect or remap
mismatched follower associations.

This branch is stacked on the Easy-Switch reliability PR #1122 and #970.

Changes

  • openlogi-core - append measured host_switching and
    host_switch_controls flags to device capabilities.
  • openlogi-device - probe 0x1814 ChangeHost and the reportable 0x1b04
    host-control table through one named capability plan, preserve the upstream
    event-index inventory data, and bump the probe cache schema to v4 so older
    inventories without the new capability fields are reprobed.
  • openlogi-ipc / openlogi-agent - carry the two appended capability flags
    in inventory protocol v30 and update the mock inventory. Follower settings
    do not gain a new IPC mutation.
  • openlogi-desktop / openlogi-ui - render the follower selector, persist
    the pre-existing host_switch_targets field directly, request the existing
    agent config reload only after a successful save, repaint failed rollbacks,
    reject self-links, and provide locale-complete semantic TOML copy.

Screenshot

Pending a final GUI smoke test and screenshot. This PR is ready for code review;
the remaining runtime verification is disclosed below.

Testing

  • cargo fmt --all -- --check
  • RUSTFLAGS="-D warnings" cargo clippy --workspace --all-targets -- -D warnings
  • RUSTFLAGS="-D warnings" cargo test --workspace
  • RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --document-private-items --exclude openlogi-ui --exclude openlogi-desktop --exclude openlogi-overlay --exclude openlogi-agent
  • cargo xtask ci wasm
  • cargo test -p openlogi-device inventory --no-fail-fast
  • cargo test -p openlogi-ipc --test wire_format
  • cargo test -p openlogi-ui locale
  • cargo test -p openlogi-desktop i18n
  • cargo test -p openlogi-desktop easy_switch
  • typos was not run locally because typos-cli is unavailable.
  • Not manually smoke-tested at this final rebased head. Before merging, confirm
    the keyboard and follower slots map to the same computers, select and clear a
    follower, restart the app, confirm the selection persists, and attach a
    screenshot of the Easy-Switch tab.

Depends on #1122 and #970

Related to #650

@noobydp
noobydp marked this pull request as ready for review August 29, 2026 06:32
@noobydp
noobydp requested a review from AprilNEA as a code owner August 29, 2026 06:32
@greptile-apps

greptile-apps Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Adds Easy-Switch follower configuration UI and device inventory tracking.

The PR does not appear safe to merge while a linked keyboard can be moved before its pending firmware restoration completes.

Fix All in CodexFindings

  1. P1 Follower moves before restoration ▶

Summary

The PR adds capability-gated Easy-Switch follower selection, inventory and IPC capability reporting, and host-transition recovery changes.

  • Saved followers that disappear or lose capability can now be removed; the previously reported issue was manually resolved.
  • The new transition rule permits a follower to move while its own firmware restoration remains pending.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Keyboard A has Ready restoration] --> B[Keyboard B requests host switch]
  B --> C[Transition starts despite A's pending cleanup]
  C --> D[A moves as B's follower]
  D --> E[A's restoration waits for reconnection]
Loading

Reviews (5) · Last reviewed commit: "fix(gui): keep saved followers removable..."

@noobydp
noobydp force-pushed the feat/easy-switch-followers branch from 082ef2f to 5d97d6b Compare August 29, 2026 07:25
@noobydp
noobydp marked this pull request as draft August 29, 2026 07:25
@noobydp
noobydp force-pushed the feat/easy-switch-followers branch 10 times, most recently from bbcf430 to bea2268 Compare August 30, 2026 08:56
yuzi-co and others added 7 commits August 31, 2026 16:39
`workflow_commands` joined line continuations by replacing a backslash
followed by LF. Git hands Windows checkouts CRLF unless a `.gitattributes`
overrides it, and no rule covers `.github/`, so the continuation is a
backslash followed by CRLF there and the join misses it — leaving a stray
backslash mid-command.

Every wrapped command in `ci_yml_runs_what_this_runner_runs` therefore failed
on Windows and only on Windows, so `cargo test --workspace` could not pass on
a Windows checkout of an unmodified master. CI never saw it: that job runs on
Linux and macOS.

Normalizing CRLF before the join fixes the parser rather than the checkout, so
it holds however a contributor's git is configured. A test asserts the two
line endings parse identically.
The module docs name `PermissionStatus::Unknown` while the type was
`cfg(any(macos, linux))`, so on Windows the link had no target, `lib.rs`
denies `rustdoc::broken_intra_doc_links`, and the whole crate's docs failed
to build. The rustdoc gate in AGENTS.md was therefore unrunnable on a Windows
checkout of an unmodified master; CI never saw it because that job is Linux.

Declaring the enum everywhere rather than escaping the link keeps the
documentation intact, which is how the same bug in `openlogi-hid` was settled
(PR AprilNEA#661). It also matches `Permission::Accessibility` immediately below,
which is already declared on every platform despite documenting a macOS-only
capability — the crate's vocabulary is uniform, only the platform code that
answers with it is gated.

Windows has no permission to report, so nothing there constructs one; the
type is inert rather than wrong.
The two defects this PR fixes were both Windows-only, and both reached
master for the same structural reason: `rustdoc (non-GUI crates)` runs
on ubuntu-latest, so a `cfg`-gated doc target that exists on Linux and
macOS but not on Windows leaves an intra-doc link that resolves
everywhere CI looks. `PermissionStatus::Unknown` was exactly that.

A broken intra-doc link is neither a compile error nor a clippy lint,
so the existing Windows job could not catch it either. Running the
rustdoc job's own command there closes the gap: the toolchain and cache
are already set up, so it costs one doc build and no new runner.

Fixing the two instances without this leaves the third to be found by
hand by whoever next runs the gate on Windows — the failure mode this
PR exists to remove.
The Windows job's default shell is pwsh, where a trailing backslash is
not a line continuation. It parsed --exclude as a unary operator and the
step failed before cargo ran, which is how the job this PR adds the step
to went red.

bash rather than folding the command onto one line, so it stays
byte-identical to the Linux rustdoc job it exists to mirror.
Co-authored-by: Samuel Phinizy <none@none.com>
@noobydp
noobydp force-pushed the feat/easy-switch-followers branch from bea2268 to 835a869 Compare August 31, 2026 08:54
@noobydp
noobydp marked this pull request as ready for review August 31, 2026 08:54
@davidbudnick davidbudnick added type: feature New feature request area: gui Graphical user interface platform: all Cross-platform issue labels Sep 3, 2026
…ecycle

Merge upstream master, retain pending restoration until a fresh keyboard channel, and forward genuine departure announcements through follower channels. Preserve physical inventory tracking and reject stale session completions.

Keep source-specific validation, exact control reporting modes, and regression coverage for retirement, reconnect cleanup, and bounded event-time slot reads.
… state

Merge updated forwarding and current master, preserve dpi_gestures before appending host capabilities in IPC v32, and use the StateEvents mutation boundary. Probe reportable host controls during the existing all-or-nothing table walk and retain persistence rollback coverage.

Validated with workspace tests, Clippy, rustdoc, WebAssembly and repository hooks. Mock-agent GUI checks cover selecting a follower, persistence across restart, clearing the link, and connected/offline rows.
Comment thread crates/openlogi-desktop/src/state/host_switch.rs Outdated
Only active restoration writes block a waiting transition. Ready restoration tokens retain ownership and prevent their own keyboard from rearming without blocking another keyboard indefinitely. Add a replay-backed multi-keyboard regression that fails under the previous policy.
Include selected followers even when their capability or inventory record disappears. Allow removing an existing link without requiring a reachable ChangeHost target, while retaining validation when adding followers. Merge the multi-keyboard forwarding recovery fix and its replay regression.
Comment on lines +232 to +240
let restore_blocks_transition = self.slots.iter().any(|slot| {
matches!(
slot,
HostSwitchSlot::Recovering(Recovery {
restore: RestorePhase::Restoring,
..
})
)
});

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 Follower moves before restoration

If keyboard B has keyboard A as a follower while A has a pending Ready restoration, this change lets B's transition move A first. The transition also defers A's restoration, so A can leave the current host with its controls still altered until it reconnects. A pending restoration should prevent a transition from moving that keyboard as a follower.

Knowledge Base Used: Recover host-switch controls across channel retirement

Fix in Codex Fix in Claude Code

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: gui Graphical user interface platform: all Cross-platform issue type: feature New feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants