feat(input): user-session input broker MVP for service mode#129
Open
bestlux wants to merge 1 commit into
Open
Conversation
The LocalSystem service cannot observe or inject interactive desktop input from session 0, so service-mode input truthfully reported service_session_unsupported and real mouse/keyboard handoff never worked. This adds the smallest safe broker path while keeping the MSI-owned service as the trust/network/routing authority: - daemon: InputBrokerRelay state plus Attach/Exchange/Detach control-plane APIs on the existing allowed-user named pipe; the service-mode capture backend relays broker events through the unchanged edge-switch/owner/peer-queue paths, and the inject loop hands queued frames to the broker instead of dropping them while a fresh broker is attached - tray: hosts the broker in the interactive user session; captures with the shared HookInputPump (moved to platform-windows), injects authenticated frames with SendInput, and applies daemon-owned lock state - fail closed: attach rejected outside service mode and for session 0 brokers; wrong/stale/replaced tokens rejected; a silent broker reverts the runtime to service_session_unsupported within seconds; held keys get synthetic releases - diagnostics: capture backend mode reports user_session_broker only while attached; tray Settings states the unlocked-desktop-only scope Scope is the normal unlocked desktop of the selected allowed user. Lock screen, secure desktop, UAC prompts, and elevated apps remain unsupported (no BND-NEXT-9C claims). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The MSI-owned LocalSystem service runs in session 0 and can never observe or inject interactive desktop input, so service-mode input honestly reported
service_session_unsupportedand physical mouse/keyboard handoff did not work. This PR lands the smallest safe user-session input broker so normal unlocked-desktop input sharing works in service mode, while the service remains the trust/network/routing authority.Architecture choice: tray-hosted broker (no new helper binary). The tray already runs at sign-in in the intended user's interactive session as the allowed user and already speaks the service control pipe. The service named-pipe ACL (SYSTEM, Administrators, exactly one allowed user SID) stays the trust boundary; the broker rides it and adds no new socket, ACL surface, firewall rule, relay, or transport change. Full rationale and control-path map:
docs/architecture/user-session-input-broker.md.What changed
InputBrokerRelaystate plusAttachInputBroker/ExchangeInputBroker/DetachInputBrokercontrol-plane RPCs. In service mode the capture backend relays broker-observed events through the unchanged edge-switch/layout/owner/per-peer-queue paths, and the inject loop leaves queued frames for the broker (owner re-checked per frame at dispatch) instead of failing them, while a fresh broker is attached.HookInputPump(hook/raw-input translation moved from the daemon intoplatform-windowsfor reuse), injects authenticated incoming frames withSendInput, applies daemon-owned lock state, and flushes synthetic release events before detach.service_session_unsupportedwithin ~3s; held keys/buttons get synthetic releases on target change or broker loss.input_capture_backend_modereportsuser_session_brokeronly while a fresh broker is attached; tray Settings anddocs/user/service-mode.mdstate the unlocked-desktop-only scope; newinput_broker_*transport events.Explicitly not claimed / unchanged
Lock screen, secure desktop, UAC prompts, elevated apps, and other users' sessions remain unsupported (no BND-NEXT-9C claims). Pairing/trust, firewall, transport, and layout sync are untouched; existing service-session unsupported diagnostics are preserved when no broker is attached.
Validation
cargo fmt --all -- --checkcleancargo clippy --workspace --all-targets -- -D warningscleancargo test --workspace: 426 passed, 0 failed (includes newstate::tests::input_brokerfail-closed/routing tests, broker backend readiness tests, and ipc-api event round-trip tests)git diff --checkcleanManual two-PC dogfood
BoundlessServicerunning); sign in as that user so the tray starts.boundlessctl daemon status→ confirm the service ownsnpipe://./pipe/boundlessd-api; tray Settings should briefly showservice_session_unsupported, thenuser_session_brokeronce the tray attaches.transport eventsshowsinput_broker_attached/input_broker_inject_dispatchedand noinput_broker_inject_reportfailures.service_session_unsupportedand remote input must stop (fail closed); restart tray → broker re-attaches.Risks
platform-windowsis behavior-preserving (tests ported), but the in-session daemon capture path shares it — regressions there would affect non-service mode too.🤖 Generated with Claude Code