From 88080a7c7a3af5642a7b87a50baeaf5760fda26b Mon Sep 17 00:00:00 2001 From: Shadman Taqi Date: Fri, 28 Aug 2026 20:28:27 +0600 Subject: [PATCH 1/2] test(web): cover Ctrl+Insert as a terminal copy shortcut Shift+Insert already pastes. Ctrl+Insert currently falls through because isTerminalCopyShortcut only matches the C key. --- apps/web/src/terminal/ghostty/surface.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/web/src/terminal/ghostty/surface.test.ts b/apps/web/src/terminal/ghostty/surface.test.ts index ee3240b41b08..2ef7fe26a115 100644 --- a/apps/web/src/terminal/ghostty/surface.test.ts +++ b/apps/web/src/terminal/ghostty/surface.test.ts @@ -556,6 +556,20 @@ describe("isTerminalCopyShortcut", () => { expect(isTerminalCopyShortcut(event({ key: "C", metaKey: true }), "MacIntel")).toBe(true); expect(isTerminalCopyShortcut(event({ key: "j", metaKey: true }), "MacIntel")).toBe(false); }); + + it("supports the conventional Ctrl+Insert copy shortcut", () => { + expect(isTerminalCopyShortcut(event({ key: "Insert", ctrlKey: true }), "Linux x86_64")).toBe( + true, + ); + expect(isTerminalCopyShortcut(event({ key: "Insert" }), "Linux x86_64")).toBe(false); + expect( + isTerminalCopyShortcut( + event({ key: "Insert", ctrlKey: true, shiftKey: true }), + "Linux x86_64", + ), + ).toBe(false); + expect(isTerminalCopyShortcut(event({ key: "Insert", ctrlKey: true }), "MacIntel")).toBe(false); + }); }); describe("applyTerminalCopyEvent", () => { From b0b9776db3e3ef8c523b77898f18267f21237ba3 Mon Sep 17 00:00:00 2001 From: Shadman Taqi Date: Fri, 28 Aug 2026 20:28:29 +0600 Subject: [PATCH 2/2] fix(web): copy terminal selection with Ctrl+Insert Mirror the Shift+Insert paste branch. Ctrl+Insert is the GTK/VTE copy chord and the one tiling WMs send for universal clipboard on a terminal window. Copy only, do not treat it as SIGINT. Closes #8525 --- apps/web/src/terminal/ghostty/surface.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/web/src/terminal/ghostty/surface.ts b/apps/web/src/terminal/ghostty/surface.ts index 29aaac6f6abd..ca1cd5a18eb2 100644 --- a/apps/web/src/terminal/ghostty/surface.ts +++ b/apps/web/src/terminal/ghostty/surface.ts @@ -321,7 +321,11 @@ export function isTerminalCopyShortcut( event: Pick, platform = navigator.platform, ) { - if (event.key.toLowerCase() !== "c") return false; + const key = event.key.toLowerCase(); + if (key === "insert" && !isMacPlatform(platform)) { + return event.ctrlKey && !event.shiftKey && !event.metaKey; + } + if (key !== "c") return false; return isMacPlatform(platform) ? event.metaKey : event.ctrlKey; } @@ -1027,12 +1031,12 @@ export class GhosttyTerminalSurface { // A plain Ctrl+C/Cmd+C fires the browser's native copy event, caught in // onCopyEvent; not preventing the default keeps that path alive. WebKit // omits the keyboard copy event without a DOM selection, so race the - // clipboard write against it the same way paste races its read. The - // Shift variant has no native event (Chrome binds Ctrl+Shift+C to + // clipboard write against it the same way paste races its read. Ctrl+Shift+C + // and Ctrl+Insert have no native copy event (Chrome binds the former to // inspect), so synthesize one with execCommand("copy"). const selection = this.getSelection(); this.primeCopy(selection); - if (event.shiftKey) { + if (event.shiftKey || event.key.toLowerCase() === "insert") { event.preventDefault(); document.execCommand("copy"); } else {