Skip to content

fix: admit keyboard input to sheet fields of the observed window - #9

Merged
iamnbutler merged 1 commit into
mainfrom
insert-sheet-window
Oct 15, 2026
Merged

iamnbutler merged 1 commit into
mainfrom
insert-sheet-window

Conversation

@iamnbutler

@iamnbutler iamnbutler commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Adds peekaboo-sheet-focus.patch for githubnext/ace#390: `desktop_insert` into a Save sheet's filename field refused with "Literal insertion could not establish its read-only preflight … focused element AXWindow failed with AX error -25212" ("Exact focused-element receipt is stale"). `desktop_type` (an AX value write) worked after #8.

Cause. #8 routed the value/focus identity read through `AXWindowIDResolver.owningWindowID`, but keyboard input (literal insertion, paste, exact-window keys) validates a separate receipt in `DetachedExactWindowFocusReader.read(expected:phase:)`. That path read the receiver's own `AXWindow` attribute and required it to name the observed window. An Open/Save panel field has no AXWindow (-25212 is kAXErrorNoValue), and an in-process sheet control's AXWindow names the sheet, so the receipt was always stale. Behind that, the key-window gate required the app's focused window to be the observed window, but while a sheet is up the sheet is key, so it would refuse next.

Change.

  • `AXWindowIDResolver.owner(of:)` returns the owning window and the nearest `AXSheet` crossed on the way. A missing or non-window AXWindow link means "walk the parents", not failure. `owningWindowID` is now a wrapper for it.
  • The exact receipt reader and the focused snapshot use that owner (`sheetWindowID` on `ExactWindowFocusSnapshot`).
  • `ExactKeyWindowSnapshot.isKey` admits a receiver inside a sheet only while that exact sheet is the focused window. Any other receiver still requires the observed window. It's used by `requireExactWindowKeyboardFocus` and the background focused-text path. A parent with an attached sheet, a different or nested sheet, sibling windows and other processes remain refused.
  • Observation focus corroboration (`DetachedAXObservationWorker.focusedElement(_:belongsTo:)`) used a direct AXWindow comparison. It now uses the same resolver.
  • Tests: resolver owner/sheet cases (including the no-AXWindow panel field and nested sheets), `validateOwningWindow` with the new contract, `isKey` cases, and two keyboard-dispatch tests through `requireExactWindowKeyboardFocus` (eligible when the receiver's sheet is key, and refused for another sheet, the parent holding the sheet, or the parent alone). They all use injected fakes.

Verification. `npm run check`. Full native build via `node dist/build.js --out … --scratch …` from a pristine Peekaboo checkout, applying the whole stack. `swift test` in PeekabooAutomationKit for `AXWindowIDResolverTests|DetachedExactWindowFocus*|UIAutomationExactWindowFocusTests|HotkeyServiceBackgroundPreparationTests|DetachedAXObservationWorker*|BackgroundInputDriver*`: all pass except `BackgroundInputDriverPositionalTargetTests` "positional value policy…" (focus/allowed), which fails on the AXFocused readback added by `peekaboo-point-focus.patch` and is unrelated to this diff. As in #8, the test target needed a local, uncommitted `default` case in `ClipboardPasteTransactionGateTests` to compile.

Not verified against a live Save sheet. The Mac was running a study and no GUI app could be opened. It assumes the app's AXFocusedWindow is the sheet while a sheet field has focus, which is the AppKit key-window behavior. If macOS instead reports the parent window, insertion still refuses before input ("keyboard focus is not on the target window") rather than typing.

The exact focused-element receipt used before keyboard input, literal
insertion and paste required the receiver's own AXWindow link to name
the observed window. Sheet controls link to the sheet, and Open/Save
panel fields can have no AXWindow at all (kAXErrorNoValue), so
desktop_insert refused in a Save sheet. Resolve the owner through the
shared resolver, track the attached sheet, and admit a sheet receiver
only while that sheet is the key window.
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