From 421e443d307bc91871b5a26f5fc5dde6e87ad0fb Mon Sep 17 00:00:00 2001 From: suraj-markup Date: Mon, 2 Mar 2026 01:56:02 +0530 Subject: [PATCH] fix(terminal): remove DOM paste handler that could double-paste with xterm.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xterm.js handles paste natively via its internal textarea — our container-level paste listener either double-pastes (if the event bubbles) or is dead code (if xterm calls stopPropagation). Also remove the dead isPaste key handler block that returned true (same as default). Co-Authored-By: Claude Opus 4.6 --- .../web/src/components/DirectTerminal.tsx | 31 ++----------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/packages/web/src/components/DirectTerminal.tsx b/packages/web/src/components/DirectTerminal.tsx index 9e80a9383..5a5a51b12 100644 --- a/packages/web/src/components/DirectTerminal.tsx +++ b/packages/web/src/components/DirectTerminal.tsx @@ -225,10 +225,9 @@ export function DirectTerminal({ } }); - // Intercept Cmd+C/V (Mac) and Ctrl+Shift+C/V (Linux/Win) for clipboard. - // Cmd+C is kept as a fallback (selection may still be alive). - // Cmd+V intercepts the key so xterm doesn't process it; the actual - // paste is handled by the DOM "paste" event listener below. + // Intercept Cmd+C (Mac) and Ctrl+Shift+C (Linux/Win) for copy. + // Paste (Cmd+V / Ctrl+Shift+V) is handled natively by xterm.js + // via its internal textarea — no custom handler needed. terminal.attachCustomKeyEventHandler((e: KeyboardEvent) => { if (e.type !== "keydown") return true; @@ -243,32 +242,9 @@ export function DirectTerminal({ return false; } - // Cmd+V / Ctrl+Shift+V — trigger native paste event - const isPaste = - (e.metaKey && !e.ctrlKey && !e.altKey && e.code === "KeyV") || - (e.ctrlKey && e.shiftKey && e.code === "KeyV"); - if (isPaste) { - // Let the browser fire the "paste" event (handled below). - // Returning true allows the event to propagate normally. - return true; - } - return true; }); - // Handle paste via the DOM "paste" event — this provides clipboard - // content through ClipboardEvent.clipboardData without needing the - // Clipboard API "clipboard-read" permission. - const termEl = terminalRef.current!; - const handlePaste = (e: ClipboardEvent) => { - const text = e.clipboardData?.getData("text/plain"); - if (text) { - e.preventDefault(); - terminal.paste(text); - } - }; - termEl.addEventListener("paste", handlePaste); - // Handle window resize (works with whatever ws is current) const handleResize = () => { const currentWs = ws.current; @@ -369,7 +345,6 @@ export function DirectTerminal({ cleanup = () => { selectionDisposable.dispose(); if (safetyTimer) clearTimeout(safetyTimer); - termEl.removeEventListener("paste", handlePaste as EventListener); window.removeEventListener("resize", handleResize); inputDisposable?.dispose(); inputDisposable = null;