From f73d36ad5da19e0642072da78da838bffd2db135 Mon Sep 17 00:00:00 2001 From: simyo Date: Wed, 12 Aug 2026 16:09:45 +0200 Subject: [PATCH] fix(terminal): stop Ctrl+Shift+V pasting twice xterm.js calls attachCustomKeyEventHandler on both keydown and keyup, but the handler didn't check event.type, so paste/copy/font-zoom ran twice per keypress. Gate the side-effecting calls to keydown only. --- src/components/terminal/terminal.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/terminal/terminal.js b/src/components/terminal/terminal.js index 6b7504140..ca77d4581 100644 --- a/src/components/terminal/terminal.js +++ b/src/components/terminal/terminal.js @@ -439,17 +439,22 @@ export default class TerminalComponent { setupCopyPasteHandlers() { // Add keyboard event listener to terminal element this.terminal.attachCustomKeyEventHandler((event) => { + // xterm.js invokes this handler for both "keydown" and "keyup", so + // any side-effecting action must only run once, on keydown, or it + // fires twice per keypress (e.g. paste happening twice). + const isKeyDown = event.type === "keydown"; + // Check for Ctrl+Shift+C (copy) if (event.ctrlKey && event.shiftKey && event.key === "C") { event.preventDefault(); - this.copySelection(); + if (isKeyDown) this.copySelection(); return false; } // Check for Ctrl+Shift+V (paste) if (event.ctrlKey && event.shiftKey && event.key === "V") { event.preventDefault(); - this.pasteFromClipboard(); + if (isKeyDown) this.pasteFromClipboard(); return false; } @@ -462,7 +467,7 @@ export default class TerminalComponent { (event.key === "+" || event.key === "=") ) { event.preventDefault(); - this.increaseFontSize(); + if (isKeyDown) this.increaseFontSize(); return false; } @@ -474,7 +479,7 @@ export default class TerminalComponent { event.key === "-" ) { event.preventDefault(); - this.decreaseFontSize(); + if (isKeyDown) this.decreaseFontSize(); return false; } @@ -494,8 +499,13 @@ export default class TerminalComponent { binding.key === eventKey, ); - if (binding && executeCommand(binding.name)) { - return false; + if (binding) { + if (isKeyDown) { + this._lastAppKeybindingHandled = executeCommand(binding.name); + } + if (this._lastAppKeybindingHandled) { + return false; + } } }