Files
Codeman/docs
Michael GrundbergandClaude Opus 5.5 6c5d53ebfe fix(paste): cancel the Ctrl+V keydown once the paste trap has the clipboard
Ctrl+V in Firefox still pasted the clipboard twice some of the time.
Right-click → Paste never did.

`_handleImagePaste()` focuses a hidden contenteditable trap, calls
`document.execCommand('paste')`, and reads the clipboard from the paste
event that lands on the trap. Firefox dispatches that event synchronously,
inside the `execCommand` call. It then delivers the key's own paste as a
separate task, about 10 ms later in Playwright's Firefox. The one-shot flag
from b87bc687 drops that second event, but only if it still reaches the
trap. The trap removes itself and refocuses the terminal on a
`setTimeout(0)` queued by the first event, and that timer races the second
paste. When the timer wins, the second paste lands on xterm's textarea,
xterm's own `handlePasteEvent` sends the clipboard again, and the flag
never sees it.

The trap now cancels the keydown when its paste listener has already run
by the time `execCommand` returns, so Firefox never issues the second
paste. Both callers pass the keydown as `target.keyEvent`: the main pane's
key handler in terminal-ui.js and a tile's in terminal-tile.js. Chromium
and WebKit refuse the command and dispatch nothing from it, so their
keydown is left alone, because its default action delivers their only
paste event.

Measured in Playwright's Firefox with the trap removed before the key's
paste arrived: the paste reached xterm's textarea and the text went in
twice. With the keydown cancelled, the key's paste never fired. End to end
on an isolated instance with a shell session, 20 Ctrl+V presses gave 20
pastes in both Firefox and Chromium.

test/image-paste-trap.test.ts gains a harness option in which
`execCommand` delivers the paste from inside the call, as Firefox does.
New cases cover the keydown being cancelled for the main pane and for a
tile, being left alone when `execCommand` delivers nothing, and a caller
that passes no keydown. The two cancel cases fail without this change.

test/terminal-tile-input.test.ts now expects the tile to pass its keydown
along with its terminal and session.

Docs: the Terminal paste section of docs/architecture-invariants.md and
the paste-trap entry in src/web/CLAUDE.md now describe the race and the
rule. The section's old claim that the key's default action alone always
reaches the trap is replaced, since in Firefox it can miss it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:20:41 +01:00
..
2026-08-22 14:13:58 +02:00
2026-08-04 15:02:46 +02:00