Repository navigation
fix(macos): expose the terminal view as an accessibility text area - #23
Merged
Merged
Conversation
Dictation tools insert text through the macOS Accessibility API: they look for a focused text element they can write to. Ember's terminal view (winit's WinitView) exposed nothing, so the focused element was the bare window and tools like Speechify fell back to "copy it yourself". iTerm2's terminal view is a focused AXTextArea with settable AXValue and AXSelectedTextRange; Ember's now matches. The NSAccessibility methods are added to winit's view class at runtime (class_addMethod), never replacing anything: if the class already implements any of them, nothing is installed. A client writing AXValue pastes the text it inserted into the focused pane through the normal paste path (bracketed-paste aware). Setting AXSelectedTextRange is accepted and ignored. Screen text is published only once a client has started reading the view, so there is no cost otherwise. macOS only. Co-Authored-By: Claude Opus 5.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.
Problem
Dictation tools such as Speechify insert text through the macOS Accessibility API: they look for a focused text element they can write to. Ember's terminal view exposed nothing to accessibility, so the focused element was the bare window and Speechify fell back to its "copy text" button. In iTerm2 the same dictation goes straight into the prompt.
Fix
The terminal view now presents itself as a focused
AXTextArea, matching iTerm2's terminal view:AXValue(the focused pane's screen text),AXSelectedTextRange(the cursor),AXInsertionPointLineNumber,AXNumberOfCharacters,AXVisibleCharacterRange,AXSelectedText(empty).AXValuepastes the text the client inserted (the new value minus what it last read) into the focused pane through the normal paste path, bracketed paste included. Text a client removes is ignored, since the terminal's text is read-only. SettingAXSelectedTextRangeis accepted and ignored, because the program running in the terminal owns the caret.How it's installed:
class_addMethod. Existing methods are never replaced: if the class already implements any of them (a future winit, say), nothing is installed and a warning is logged.Keyboard input, copy, and OSC 52 code paths are untouched.
Verification
Accessibility dump of the focused element (
AXFocusedUIElementof the app):Before (v0.6.0):
After (this branch):
iTerm2, for reference:
AXFocusedalso reads as settable here. That comes from NSView's inherited default, not from this change.Write path: an Accessibility API client read
AXValue, then set it to that value plusecho ax-insert-ok. The text landed at the zsh prompt without being executed (bracketed paste). The next read showed the prompt line, withAXSelectedTextRangeat the cursor.cargo test --workspace,cargo clippy,cargo fmt --check;ember-platformchecks forx86_64-unknown-linux-gnuinsertText:calls made outside an IME composition, the same gap that drops emoji-picker input; it's tracked as a separate fix.🤖 Generated with Claude Code