Skip to content

fix(mac): caret tracking in ChatGPT and other Chromium shells (0.5.5) - #558

Merged
Maxaubert merged 1 commit into
mainfrom
fix/mac-chatgpt-caret
Nov 7, 2026
Merged

Maxaubert merged 1 commit into
mainfrom
fix/mac-chatgpt-caret

Conversation

@Maxaubert

Copy link
Copy Markdown
Owner

Problem

Zoomed in, typing in the ChatGPT desktop app never moved the view (owner report 2026-11-07).

Cause

  • ChatGPT (com.openai.codex) is a custom Chromium shell (Codex Framework.framework), not stock Electron. It refuses AXManualAccessibility (-25205) and AXEnhancedUserInterface (-25208) on the app element, so its window holds six empty groups and Wind finds no text field.
  • Bisected on fresh launches: reading the application element's role, subrole and description turns the web content's tree on. Window walks, either switch on the content view, waiting, typing and clicking all failed.
  • Even with the tree on, AXBoundsForRange and the text-marker bounds return empty rects, but the field's AXStaticText runs do carry real frames.

Fix (CaretTracker.swift)

  • Detect Chromium shells: renderer helpers in the bundle (Electron's Frameworks/* Helper (Renderer).app or a framework's Helpers/), excluding browsers Wind already switches on.
  • For those apps, wake the tree on attach and on every key press while zoomed, so it can't go quiet.
  • Fallback caret from text-run frames, used only for shells: exact at a run's end, estimated inside a run, plus trailing spaces (Chromium leaves them out of the run).
  • A text field whose caret misses one read keeps Wind's last caret inside it instead of jumping to the whole field. This fixes the owner's "jumping and skipping".
  • Documented in mac/docs/architecture.md (Caret following). Version 0.5.5.

Verification

  • ChatGPT, real HID keys (Karabiner virtual keyboard), fresh launch, 4x: the view moved on 13 of 13 words, letter by letter, spaces included, and still followed after a 20 s idle pause. No jumps to the field.
  • Suites: swift run wind-checks, e2e.py, e2e_mouse.py: all pass.
  • e2e_caret.py: all pass except Chrome: every key keeps the caret in view. That check fails identically on unmodified main (first key compared against another Terminal's caret at x=371). It's pre-existing and environment-dependent, not from this change.

Not covered

Mid-text and wrapped-line caret positions in ChatGPT are estimates (character share of the run).

🤖 Generated with Claude Code

https://claude.ai/code/session_01SkyGaTQ1FTFz3Zwo4nohwd

ChatGPT (com.openai.codex) is a Chromium shell that refuses both
accessibility switches, so its web content never reached the tree and
typing there never moved the view. Reading the app element's role,
subrole and description wakes it (bisected); Wind does that on attach
and on every key press while zoomed. Its text has no character bounds,
so the caret comes from the frames of the field's text runs, with
trailing spaces counted, and a field whose caret misses one read keeps
the last caret instead of jumping to the whole field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SkyGaTQ1FTFz3Zwo4nohwd
@Maxaubert
Maxaubert merged commit 8c723c1 into main Nov 7, 2026
1 check passed
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