1// DOM KeyboardEvent -> libghostty key model. Pure: no wasm, no DOM types.
2// Ghostty's key enum is named after W3C KeyboardEvent.code values, so the
3// mapping is a mechanical name transform plus a small irregular table.
4
5import { GhosttyKey } from "./ghostty/constants.ts";
6
7// Bit values from vendor/include/ghostty/vt/key/event.h (#defines, invisible
8// to the enum generator — verified on vendor bump by test/keys.test.ts).
9export const MODS_SHIFT = 1 << 0;
10export const MODS_CTRL = 1 << 1;
11export const MODS_ALT = 1 << 2;
12export const MODS_SUPER = 1 << 3;
13export const MODS_CAPS_LOCK = 1 << 4;
14export const MODS_NUM_LOCK = 1 << 5;
15
16const IRREGULAR: Record<string, string> = {
17 MetaLeft: "GHOSTTY_KEY_META_LEFT",
18 MetaRight: "GHOSTTY_KEY_META_RIGHT",
19 OSLeft: "GHOSTTY_KEY_META_LEFT",
20 OSRight: "GHOSTTY_KEY_META_RIGHT",
21};
22
23/** "KeyA" -> GHOSTTY_KEY_A, "ArrowDown" -> GHOSTTY_KEY_ARROW_DOWN, "F1" -> GHOSTTY_KEY_F1, "Digit1" -> GHOSTTY_KEY_DIGIT_1. */
24export function domCodeToGhosttyKey(code: string): number | null {
25 if (code === "") return null;
26 let name = IRREGULAR[code];
27 if (name === undefined) {
28 const letter = /^Key([A-Z])$/.exec(code);
29 if (letter !== null) {
30 name = `GHOSTTY_KEY_${letter[1]}`;
31 } else if (/^F\d+$/.test(code)) {
32 name = `GHOSTTY_KEY_${code}`;
33 } else {
34 const snake = code
35 .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
36 .replace(/([A-Za-z])(\d)/g, "$1_$2")
37 .toUpperCase();
38 name = `GHOSTTY_KEY_${snake}`;
39 }
40 }
41 const value = (GhosttyKey as Record<string, number>)[name];
42 // GHOSTTY_KEY_UNIDENTIFIED (0) means "no key" — report it as unmapped.
43 return value === undefined || value === GhosttyKey.GHOSTTY_KEY_UNIDENTIFIED ? null : value;
44}
45
46export interface ModState {
47 ctrlKey: boolean;
48 altKey: boolean;
49 metaKey: boolean;
50 shiftKey: boolean;
51}
52
53export function domEventMods(event: ModState): number {
54 let mods = 0;
55 if (event.shiftKey) mods |= MODS_SHIFT;
56 if (event.ctrlKey) mods |= MODS_CTRL;
57 if (event.altKey) mods |= MODS_ALT;
58 if (event.metaKey) mods |= MODS_SUPER;
59 return mods;
60}