Skip to content

Extend AX-opaque exemption to web browsers - #104

Merged
alexkroman merged 3 commits into
mainfrom
claude/blurt-paste-chatgpt-google-529kjm
Jul 30, 2026
Merged

Extend AX-opaque exemption to web browsers#104
alexkroman merged 3 commits into
mainfrom
claude/blurt-paste-chatgpt-google-529kjm

Conversation

@alexkroman

@alexkroman alexkroman commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

What & why

Web browsers (Safari, Chrome, Firefox, etc.) are accessibility-opaque in practice: Chromium builds its accessibility tree lazily, and contenteditable composers (like ChatGPT's ProseMirror field) surface as generic groups with no settable value. This means "no editable AX signal" in a browser usually indicates "AX can't see the field," not "no field."

This PR extends the existing AX-opaque exemption — currently limited to Electron editors (VS Code, Slack) — to include known web browsers. The injector will now paste into browsers even when the focused element exposes no editable AX signal, matching the existing behavior for Electron apps.

Changes:

  • Add FocusCapture.isBrowserBundleID() to classify known browsers by bundle identifier prefix (supports stable and channel variants), plus an isBrowserApp() wrapper for NSRunningApplication
  • Add FocusCapture.isAXOpaqueApp() combining the browser check with the existing isElectronApp() (which is kept), browser check first to skip the Electron disk probe in the common case
  • Rename KeyInjector's injectable seam from isAXOpaqueEditor to isAXOpaqueApp and wire it to FocusCapture.isAXOpaqueApp
  • Add unit tests for browser classification
  • Update comments and BLURTENGINE.md to reflect the broader AX-opaque category

The browser list includes Safari, Chrome, Chromium, Edge, Brave, Opera, Vivaldi, Arc, Firefox, DuckDuckGo, and Orion — all matched by prefix to handle beta/dev/canary variants.

How it was tested

  • scripts/check.sh --portable passes locally; full scripts/check.sh (Swift build/tests) runs on CI (macos-26)
  • I read AGENTS.md and this doesn't reintroduce anything deliberately removed
  • Docs updated (BLURTENGINE.md)

Added BrowserBundleIDTests (22 cases: 11 stable browser bundle IDs, 5 channel variants, 5 non-browser lookalikes/negatives, 1 nil) pinning the prefix-match classification. Existing EditableTargetTests comments updated to reflect the broader AX-opaque category; KeyInjectorInsertTests covers the paste-on-no-signal path through the renamed seam.

https://claude.ai/code/session_014iyxjKUdUqKdDXzj24opJt

claude added 2 commits July 29, 2026 22:37
Web content is routinely invisible to Accessibility — Chromium builds its
tree lazily (the first query resolves only a bare AXWebArea), and
contenteditable composers like ChatGPT's expose no editable role even with
the tree live — so the pre-paste editability gate read real browser text
fields as non-editable and degraded dictations to copy-only.

Extend the AX-opaque exemption that already covered Electron editors to
known browsers (matched by bundle-identifier prefix, covering channel
variants): FocusCapture.isAXOpaqueApp = isElectronApp || isBrowserApp now
backs KeyInjector's isAXOpaqueEditor seam. The accepted trade-off is a
rare beep when a browser truly has nothing editable focused, instead of
dropping the user's words to the clipboard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iyxjKUdUqKdDXzj24opJt
isAXOpaqueApp now tries the bundle-ID prefix check before isElectronApp's
FileManager.fileExists probe, skipping synchronous file I/O on the
injector actor for the common browser case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iyxjKUdUqKdDXzj24opJt
Copilot AI review requested due to automatic review settings July 30, 2026 01:30
@alexkroman
alexkroman enabled auto-merge July 30, 2026 01:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends the engine’s “AX-opaque app” exemption used by KeyInjector so known web browsers are treated like Electron editors when Accessibility reports no editable focused element, preventing unnecessary copy-only fallback when AX can’t see real web text fields.

Changes:

  • Introduces browser bundle-id prefix classification (FocusCapture.isBrowserBundleID / isBrowserApp) and combines it with Electron detection under FocusCapture.isAXOpaqueApp.
  • Updates KeyInjector to use the broader AX-opaque classification when deciding whether to paste despite missing editable AX signals.
  • Adds unit tests for browser bundle-id classification and updates existing test comments to reflect the broader category.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Tests/BlurtEngineTests/EditableTargetTests.swift Updates test commentary to reflect the broader AX-opaque category (Electron editors + browsers).
Tests/BlurtEngineTests/BrowserBundleIDTests.swift Adds unit tests covering browser bundle-id prefix classification.
Sources/BlurtEngine/Injection/KeyInjector.swift Switches injector exemption from Electron-only to AX-opaque apps via FocusCapture.isAXOpaqueApp and updates related docs.
Sources/BlurtEngine/FocusCapture/FocusCapture+Editability.swift Adds browser detection and new isAXOpaqueApp wrapper combining browser + Electron checks.
BLURTENGINE.md Updates public engine documentation to describe the expanded AX-opaque exemption behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Sources/BlurtEngine/Injection/KeyInjector.swift Outdated
Comment thread Tests/BlurtEngineTests/BrowserBundleIDTests.swift
The seam now covers web browsers as well as Electron editors, and its
default is FocusCapture.isAXOpaqueApp — align the property, initializer
label, and test call site with that name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iyxjKUdUqKdDXzj24opJt
Copilot AI review requested due to automatic review settings July 30, 2026 01:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@alexkroman
alexkroman added this pull request to the merge queue Jul 30, 2026
Merged via the queue into main with commit cf22163 Jul 30, 2026
8 checks passed
@alexkroman
alexkroman deleted the claude/blurt-paste-chatgpt-google-529kjm branch July 30, 2026 01:57
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.

3 participants