Skip to content
Source
Sign inSign up
Open History to see the last commit

keyCodes.test.ts

104 lines4.0 KB

1import { describe, expect, it } from "vite-plus/test";
2import ghosttyKeyHeader from "../../../../../native/libghostty-vt/include/ghostty/vt/key/event.h?raw";
3​
4import {
5 ghosttyConsumedMods,
6 ghosttyKeyForCode,
7 ghosttyKeyForEvent,
8 ghosttyUnshiftedCodepoint,
9} from "./keyCodes";
10​
11describe("ghosttyKeyForCode", () => {
12 it("matches the pinned native key enum after the function keys", () => {
13 const enumBody = ghosttyKeyHeader.slice(
14 ghosttyKeyHeader.indexOf("GHOSTTY_KEY_UNIDENTIFIED"),
15 ghosttyKeyHeader.indexOf("GHOSTTY_KEY_MAX_VALUE"),
16 );
17 const keys = [...enumBody.matchAll(/GHOSTTY_KEY_([A-Z0-9_]+)/g)].map((match) => match[1]);
18 for (const [code, native] of [
19 ["F24", "F24"],
20 ["F25", "F25"],
21 ["FnLock", "FN_LOCK"],
22 ["PrintScreen", "PRINT_SCREEN"],
23 ["ScrollLock", "SCROLL_LOCK"],
24 ["Pause", "PAUSE"],
25 ["Paste", "PASTE"],
26 ]) {
27 expect(keys).toContain(native);
28 expect(ghosttyKeyForCode(code!)).toBe(keys.indexOf(native));
29 }
30 });
31});
32​
33describe("ghosttyKeyForEvent", () => {
34 it("prefers recognized physical codes over logical keys", () => {
35 expect(ghosttyKeyForEvent({ code: "Delete", key: "Backspace" })).toBe(
36 ghosttyKeyForCode("Delete"),
37 );
38 expect(ghosttyKeyForEvent({ code: "NumpadEnter", key: "Enter" })).toBe(
39 ghosttyKeyForCode("NumpadEnter"),
40 );
41 });
42});
43​
44describe("ghosttyConsumedMods", () => {
45 const shifted = { altKey: false, ctrlKey: false, key: "@", metaKey: false, shiftKey: true };
46​
47 it("only consumes a lone Shift producing a character", () => {
48 expect(ghosttyConsumedMods(shifted)).toBe(1);
49 expect(ghosttyConsumedMods({ ...shifted, ctrlKey: true })).toBe(0);
50 expect(ghosttyConsumedMods({ ...shifted, key: "Tab" })).toBe(0);
51 expect(ghosttyConsumedMods({ ...shifted, key: " " })).toBe(1);
52 expect(ghosttyConsumedMods({ ...shifted, altKey: true }, "Linux x86_64")).toBe(0);
53 });
54​
55 it("consumes macOS Option when it produced a character", () => {
56 const option = { ...shifted, altKey: true, key: "[", shiftKey: false };
57 expect(ghosttyConsumedMods(option, "MacIntel")).toBe(1 << 2);
58 expect(ghosttyConsumedMods({ ...option, shiftKey: true }, "MacIntel")).toBe(1 | (1 << 2));
59 expect(ghosttyConsumedMods({ ...option, key: "ArrowLeft" }, "MacIntel")).toBe(0);
60 expect(ghosttyConsumedMods({ ...option, ctrlKey: true }, "MacIntel")).toBe(0);
61 expect(ghosttyConsumedMods({ ...option, metaKey: true }, "MacIntel")).toBe(0);
62 });
63});
64​
65describe("ghosttyUnshiftedCodepoint", () => {
66 it("provides the logical base character for Kitty keyboard encoding", () => {
67 expect(ghosttyUnshiftedCodepoint({ code: "KeyC", key: "c", shiftKey: false })).toBe(
68 "c".codePointAt(0),
69 );
70 expect(ghosttyUnshiftedCodepoint({ code: "KeyC", key: "C", shiftKey: true })).toBe(
71 "c".codePointAt(0),
72 );
73 expect(ghosttyUnshiftedCodepoint({ code: "Digit1", key: "!", shiftKey: true })).toBe(
74 "1".codePointAt(0),
75 );
76 expect(ghosttyUnshiftedCodepoint({ code: "Slash", key: "?", shiftKey: true })).toBe(
77 "/".codePointAt(0),
78 );
79 expect(ghosttyUnshiftedCodepoint({ code: "Digit1", key: "&", shiftKey: false })).toBe(
80 "&".codePointAt(0),
81 );
82 expect(ghosttyUnshiftedCodepoint({ code: "Enter", key: "Enter", shiftKey: false })).toBe(0);
83 });
84​
85 it("reports unknown instead of the shifted character without layout data", () => {
86 expect(ghosttyUnshiftedCodepoint({ code: "Digit7", key: "/", shiftKey: true })).toBe(0);
87 expect(ghosttyUnshiftedCodepoint({ code: "KeyD", key: "Д", shiftKey: true })).toBe(
88 "д".codePointAt(0),
89 );
90 });
91​
92 it("prefers the active browser layout over US physical key positions", () => {
93 const layoutMap = new Map([
94 ["Digit1", "&"],
95 ["KeyC", "j"],
96 ]);
97 expect(ghosttyUnshiftedCodepoint({ code: "Digit1", key: "1", shiftKey: true }, layoutMap)).toBe(
98 "&".codePointAt(0),
99 );
100 expect(ghosttyUnshiftedCodepoint({ code: "KeyC", key: "J", shiftKey: true }, layoutMap)).toBe(
101 "j".codePointAt(0),
102 );
103 });
104});