Skip to content

feat: select the input source through the host - #101

Merged
iamnbutler merged 1 commit into
mainfrom
feat/input-source-host
Oct 17, 2026
Merged

iamnbutler merged 1 commit into
mainfrom
feat/input-source-host

Conversation

@iamnbutler

Copy link
Copy Markdown
Contributor

desktop_input_source select now goes through the host, so Pause All Input stops it and the activity list shows it as "Select input source". Listing stays in the client.

Audit: client-side mutations that bypass the host

I went through native/sources/client/*.swift and src/*.ts looking for anything that posts events, writes the clipboard, or changes system state without a Bridge op:

Path What it does Status
inputsource.swift TISSelectInputSource changes the system input source moved to the host (this PR)
clipboard.swift save_path, client.swift capture path write files the agent named file output only; not desktop state. Left as is
client.ts /usr/bin/sips resizes or reads capture files file processing only
CGEvent(source: nil)?.location, CGDisplay*, CGSessionCopyCurrentDictionary, TIS listing reads reads only
switch-space, notification actions, launch/open, dock, menu bar, dialogs already Bridge ops (hotkey, action, launchApplicationWithOptions, …) covered

Nothing else needed moving, and nothing non-simple turned up.

Changes

  • New patch, appended last: peekaboo-input-source.patch adds a selectInputSource(id) Bridge op.
    • Needs no permission. Global, one-unit dispatchedUnverified native-framework delivery, answered with ok.
    • Service-owned, so it runs in the native desktop lane.
    • The host runs TIS on the main actor. An unknown ID is notFound; a nonzero TIS status is internalError.
    • Tests: wire count 130 → 131, and the op joins the unconditionally mutating set.
  • Client:
    • Validates as before (ID listed, not already selected, session unlocked).
    • Calls the op, then reads back as before.
    • A pre-dispatch refusal (such as pause) is refused with the host's message.
    • A host failure that leaves the source unchanged is refused; any other failure is unknown unless the readback shows the new source.
  • Host: allows .selectInputSource and names it in the activity list.
  • Docs: tools.md, app.md (drops the pause gap note), patches README.

Checks

  • npm run -s check, npm test (52 pass)
  • Peekaboo: OperationSemanticPlan, RequestPlan, OperationResultSemantics, HandlerMutationSemantics and OperationRecord tests (118 tests in 5 suites)
  • Native build and signed dev app. Listing works. Select while locked is refused client-side before any send.
  • Live, pending: screen locked (in Run the live checks deferred while the screen was locked #42):
    • select a second source completes and reads back, and shows in Recent Activity;
    • with input paused, select is refused with the pause message, listed as "paused", and the source is unchanged.

@iamnbutler
iamnbutler merged commit 2c3390a into main Oct 17, 2026
2 checks passed
@iamnbutler
iamnbutler deleted the feat/input-source-host branch October 17, 2026 08:33
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