Skip to content

Hotkey routing and the menu's copy move into Core - #76

Open
dinooo13 wants to merge 2 commits into
mainfrom
core/hotkey-routing-and-copy
Open

dinooo13 wants to merge 2 commits into
mainfrom
core/hotkey-routing-and-copy

Conversation

@dinooo13

Copy link
Copy Markdown
Owner

Part of #73, point 1.

This is option (b) of the issue's point 1: the two app-target decisions that round two found bugs in move into Core as values and seams, where the existing tests reach them. There is no app test target.

What

HotkeyRouting (new, Sources/PladderCore/HotkeyRouting.swift). It does the deciding that HotkeyRouter used to do: the grant, the sustained Secure Event Input reading, the stand-in at the first observation, and a chord change that uses the last reading. observe(accessibilityTrusted:secureInputEnabled:at:) returns one Change that carries both the new source and the stand-in, or nil when nothing changed. hotkeyChanged(to:) returns the new source, if there is one. HotkeyRouter keeps the two monitors, the weak coordinator, systemShortcuts and displayName. Its update now makes a single coordinator call with both fields, so a grant flip still restarts the monitor once (4187a7e). The router writes its observable routing only when the value changed, so a poll with nothing new invalidates no view, the same as the old if trusted != accessibilityTrusted guard. The tests are in HotkeyRoutingTests: grant flip, first observation, a quiet poll, secure input at 0/2/4 s, a modifier-only chord staying on the tap, a chord change using the last reading, and a few edge cases. One more test applies a Change to a real coordinator with fake monitors and checks that the new monitor starts once, with the stand-in.

TextOutput.copy is now a protocol requirement with no default. PasteboardOutput.copy already had the right signature, so it keeps the nspasteboard.org markers and still ends a pending restore. DemoOutput and the tests' FakeOutput implement it, and nothing else conforms (pladder-cli has no TextOutput of its own). DictationCoordinator.copyLastTranscript() copies lastTranscript?.text through it and does nothing when there is no transcript. AppModel.copyLastTranscript delegates to it, and AppModel's stored output is gone. The new tests are copyingTheLastTranscriptGoesThroughTheOutput and copyingWithNoLastTranscriptDoesNothing.

The docs are updated: ARCHITECTURE "Tap and Carbon", "The app" and "Paste and clipboard", and the app-split line of CLAUDE.md. No section names changed.

Differences from the plan

  • HotkeyRouting.observe also returns a Change when the stand-in changes without a flip. This cannot happen today: with the chord fixed, a grant change that changes the stand-in also changes the source. It keeps the Change complete without depending on that. In every reachable case the behaviour is the same as before.

Release path

Nothing here is on the release path, between recordingStopped and inserted. copyLastTranscript is a separate method, and the router runs on the permission poll and on settings changes. No benchmark is needed.

swift build has no warnings and swift test is green.

🤖 Generated with Claude Code

dinooo13 and others added 2 commits October 16, 2026 15:28
…n Core

The router's decision (the grant, the sustained secure-input reading, the first observation's stand-in, a chord change with the last reading) moves out of the app into `HotkeyRouting`, which returns one `Change` carrying the source and the stand-in together. `HotkeyRouter` keeps the monitors and hands each change to the coordinator in one update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… output seam

`TextOutput` gains `copy` as a requirement, which `PasteboardOutput` already served. `DictationCoordinator.copyLastTranscript` copies the last transcript through it, so the menu's copy is tested in Core against the fake output, and `AppModel` no longer keeps the output itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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