Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions apps/web/src/terminal/ghostty/surface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,21 @@ describe("GhosttyTerminalSurface visibility", () => {
expect(surface.hasSelection()).toBe(false);
});

it("copies on Ctrl+Shift+C when a non-Latin layout reports another letter on KeyC", async () => {
vi.stubGlobal("navigator", { platform: "Linux x86_64" });
const harness = createHarness();
const surface = await harness.create({ beforeKey: () => true });
Object.assign(surface.input, { select() {} });
const execCommand = vi.fn(() => true);
Object.assign(document, { execCommand });
surface.write("SELECTED_OUTPUT");
surface.selectAll();
// Russian layout: Cyrillic Es (U+0421) on the physical C key.
key(surface, "С", "KeyC", { ctrlKey: true, shiftKey: true });
expect(execCommand).toHaveBeenCalledWith("copy");
expect(harness.onData).not.toHaveBeenCalled();
});

it("skips middle-click selection paste when the desktop turned primary paste off", async () => {
vi.stubGlobal("navigator", { platform: "Linux x86_64" });
const harness = createHarness();
Expand Down Expand Up @@ -918,6 +933,8 @@ describe("terminalLinkAtPositionWithRange", () => {

describe("isTerminalCopyShortcut", () => {
const event = (overrides: Partial<Parameters<typeof isTerminalCopyShortcut>[0]> = {}) => ({
altKey: false,
code: "KeyC",
ctrlKey: false,
key: "c",
metaKey: false,
Expand Down
19 changes: 10 additions & 9 deletions apps/web/src/terminal/ghostty/surface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { resolveEventKeys } from "@t3tools/shared/keybindingMatching";
import { isMacPlatform } from "../../lib/utils";
import { SELECTION_MULTI_CLICK_INTERVAL_MS } from "../../lib/selectionActions";
import { collectWrappedTerminalLinkLine, extractTerminalLinks } from "../../terminal-links";
Expand Down Expand Up @@ -313,14 +314,14 @@ export function terminalLinkAtPositionWithRange(
}

export function isTerminalCopyShortcut(
event: Pick<KeyboardEvent, "ctrlKey" | "key" | "metaKey" | "shiftKey">,
event: Pick<KeyboardEvent, "altKey" | "code" | "ctrlKey" | "key" | "metaKey" | "shiftKey">,
platform = navigator.platform,
) {
const key = event.key.toLowerCase();
if (key === "insert" && !isMacPlatform(platform)) {
const keys = resolveEventKeys(event);
if (keys.has("insert") && !isMacPlatform(platform)) {
return event.ctrlKey && !event.shiftKey && !event.metaKey;
}
if (key !== "c") return false;
if (!keys.has("c")) return false;
return isMacPlatform(platform) ? event.metaKey : event.ctrlKey;
}

Expand Down Expand Up @@ -355,14 +356,14 @@ export function applyTerminalCopyEvent(
}

function isTerminalPasteShortcut(
event: Pick<KeyboardEvent, "ctrlKey" | "key" | "metaKey" | "shiftKey">,
event: Pick<KeyboardEvent, "altKey" | "code" | "ctrlKey" | "key" | "metaKey" | "shiftKey">,
platform = navigator.platform,
) {
const key = event.key.toLowerCase();
if (key === "insert" && !isMacPlatform(platform)) {
const keys = resolveEventKeys(event);
if (keys.has("insert") && !isMacPlatform(platform)) {
return event.shiftKey && !event.ctrlKey && !event.metaKey;
}
if (key !== "v") return false;
if (!keys.has("v")) return false;
return isMacPlatform(platform) ? event.metaKey : event.ctrlKey && event.shiftKey;
}

Expand Down Expand Up @@ -1119,7 +1120,7 @@ export class GhosttyTerminalSurface {
const mac = isMacPlatform(navigator.platform);
const primaryModifier = mac ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey;
const selectAllShortcut =
event.key.toLowerCase() === "a" &&
resolveEventKeys(event).has("a") &&
primaryModifier &&
!event.altKey &&
(mac ? !event.shiftKey : event.shiftKey);
Expand Down
Loading