Skip to content

fix(caret): screen readers follow typing, not a streaming agent (#101) - #102

Merged
Maxaubert merged 2 commits into
mainfrom
fix/101-caret-follows-typing
Sep 29, 2026
Merged

Maxaubert merged 2 commits into
mainfrom
fix/101-caret-follows-typing

Conversation

@Maxaubert

Copy link
Copy Markdown
Owner

Closes #101. The spec and plan are in docs/superpowers/specs/2026-09-29-caret-follows-typing-design.md. The owner asked for them to be written and implemented without a separate approval, relayed by the Wind session.

Problem. Magnifiers and screen readers (Wind, Windows Magnifier, Narrator) and the IME window follow xterm's helper textarea. xterm moves it to the cursor after every write. While Claude Code was busy, Wind's caret jumped from the input line (y=1737) to y=432/567 for seconds.

Measured, not assumed. I ran Claude Code 2.1.285 under a headless xterm, through the same bundled ConPTY. It streamed a 60-line answer while I typed "abc def ghi ", and I logged where the cursor sat at the end of every chunk.

Claude's view Cursor hidden Drawn caret Chunk ends off the input row
fullscreen no none 0 of 28 while typing
inline no none 6 of 26 while typing, 26 of 29 while streaming

In the inline view, every streaming frame leaves the cursor on the output row, above the input line. The suggested "find the drawn caret" design does not apply, because Claude neither hides the cursor nor draws a caret. The owner's sessions ran inline for part of the day, after Claude switched its fullscreen view off following test launches.

Fix (core/renderer/lib/termCaretHold.ts, pure and unit-tested; wired in TerminalPanel). On the normal screen:

  • The textarea is held on the caret the last keystroke produced, while the program parks the cursor above it. That caret is the lowest position the key's echo reached within 250 ms.
  • When the cursor lands at or below that caret (a new prompt, output that pushed the input down), xterm's placement stands and becomes the caret.
  • The alternate screen, a view scrolled back, and a resize all release the hold.
  • Only the textarea moves. The cursor, the pty and what is drawn are untouched.
  • Not covered: xterm's own IME composition view.

Core change, so Prism's terminals get it too through the automatic bump. Core 0.16.1, app 0.19.1. These numbers overlap with the other open PRs, and whichever merges later gets bumped again.

Not installed anywhere (owner's rule for this task): no build was installed or replaced on this PC, the stable copy included. It was tested in the repo only.

Verified:

  • Unit tests: 942 pass, 5 of them new for the hold rule. Lint and typecheck pass.
  • A new caretHold e2e in a real pwsh runs a raw-mode stand-in for Claude's inline view: an input line, plus a "stream" line 8 rows up that leaves the cursor there every 150 ms.
    • On main it failed: the textarea was at 117, the parked row, not 238, the input.
    • With the fix, the textarea stays on the input line while streaming and after the next key, and follows xterm's cursor at a plain prompt.
  • The full e2e suite passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FHHaWKR4M5QtW7Wecyuk4t

Maxaubert and others added 2 commits September 29, 2026 22:45
On the normal screen, xterm's helper textarea is held on the caret the last
key produced while the program parks the cursor above it, as Claude Code's
inline view does after every streaming frame (measured). At or below, on the
alternate screen, scrolled back or after a resize, xterm's placement stands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHHaWKR4M5QtW7Wecyuk4t
@Maxaubert
Maxaubert merged commit 1bead25 into main Sep 29, 2026
2 checks passed
@Maxaubert
Maxaubert deleted the fix/101-caret-follows-typing branch September 29, 2026 22:19
github-actions Bot pushed a commit that referenced this pull request Sep 29, 2026
#102)

On the normal screen, xterm's helper textarea is held on the caret the last
key produced while the program parks the cursor above it, as Claude Code's
inline view does after every streaming frame (measured). At or below, on the
alternate screen, scrolled back or after a resize, xterm's placement stands.


Claude-Session: https://claude.ai/code/session_01FHHaWKR4M5QtW7Wecyuk4t

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.

Screen readers and magnifiers lose the caret while an agent streams

1 participant