export type SpecialKey = | "escape" | "tab" | "ctrl" | "alt" | "up" | "down" | "left" | "right" | "home" | "end" | "pageup" | "pagedown" | "ctrlc" | "ctrld" | "ctrlz" | "f1" | "f2" | "f3" | "f4" | "f5" | "f6" | "f7" | "f8" | "f9" | "f10" | "f11" | "f12"; export type ModifierKey = "ctrl" | "alt"; const KEY_SEQUENCES: Record = { escape: "\x1B", tab: "\t", ctrl: "", alt: "", up: "\x1B[A", down: "\x1B[B", right: "\x1B[C", left: "\x1B[D", home: "\x1B[H", end: "\x1B[F", pageup: "\x1B[5~", pagedown: "\x1B[6~", ctrlc: "\x03", ctrld: "\x04", ctrlz: "\x1A", f1: "\x1BOP", f2: "\x1BOQ", f3: "\x1BOR", f4: "\x1BOS", f5: "\x1B[15~", f6: "\x1B[17~", f7: "\x1B[18~", f8: "\x1B[19~", f9: "\x1B[20~", f10: "\x1B[21~", f11: "\x1B[23~", f12: "\x1B[24~", }; // Single character sequences with modifier prefixes const MODIFIER_PREFIXES: Record = { // Letters a: { ctrl: "\x01", alt: "\x1Ba", ctrlAlt: "\x1B\x01" }, b: { ctrl: "\x02", alt: "\x1Bb", ctrlAlt: "\x1B\x02" }, c: { ctrl: "\x03", alt: "\x1Bc", ctrlAlt: "\x1B\x03" }, d: { ctrl: "\x04", alt: "\x1Bd", ctrlAlt: "\x1B\x04" }, e: { ctrl: "\x05", alt: "\x1Be", ctrlAlt: "\x1B\x05" }, f: { ctrl: "\x06", alt: "\x1Bf", ctrlAlt: "\x1B\x06" }, g: { ctrl: "\x07", alt: "\x1Bg", ctrlAlt: "\x1B\x07" }, h: { ctrl: "\x08", alt: "\x1Bh", ctrlAlt: "\x1B\x08" }, i: { ctrl: "\x09", alt: "\x1Bi", ctrlAlt: "\x1B\x09" }, j: { ctrl: "\x0A", alt: "\x1Bj", ctrlAlt: "\x1B\x0A" }, k: { ctrl: "\x0B", alt: "\x1Bk", ctrlAlt: "\x1B\x0B" }, l: { ctrl: "\x0C", alt: "\x1Bl", ctrlAlt: "\x1B\x0C" }, m: { ctrl: "\x0D", alt: "\x1Bm", ctrlAlt: "\x1B\x0D" }, n: { ctrl: "\x0E", alt: "\x1Bn", ctrlAlt: "\x1B\x0E" }, o: { ctrl: "\x0F", alt: "\x1Bo", ctrlAlt: "\x1B\x0F" }, p: { ctrl: "\x10", alt: "\x1Bp", ctrlAlt: "\x1B\x10" }, q: { ctrl: "\x11", alt: "\x1Bq", ctrlAlt: "\x1B\x11" }, r: { ctrl: "\x12", alt: "\x1Br", ctrlAlt: "\x1B\x12" }, s: { ctrl: "\x13", alt: "\x1Bs", ctrlAlt: "\x1B\x13" }, t: { ctrl: "\x14", alt: "\x1Bt", ctrlAlt: "\x1B\x14" }, u: { ctrl: "\x15", alt: "\x1Bu", ctrlAlt: "\x1B\x15" }, v: { ctrl: "\x16", alt: "\x1Bv", ctrlAlt: "\x1B\x16" }, w: { ctrl: "\x17", alt: "\x1Bw", ctrlAlt: "\x1B\x17" }, x: { ctrl: "\x18", alt: "\x1Bx", ctrlAlt: "\x1B\x18" }, y: { ctrl: "\x19", alt: "\x1By", ctrlAlt: "\x1B\x19" }, z: { ctrl: "\x1A", alt: "\x1Bz", ctrlAlt: "\x1B\x1A" }, // Numbers "0": { ctrl: "0", alt: "\x1B0", ctrlAlt: "\x1B0" }, "1": { ctrl: "1", alt: "\x1B1", ctrlAlt: "\x1B1" }, "2": { ctrl: "\x00", alt: "\x1B2", ctrlAlt: "\x1B\x00" }, "3": { ctrl: "\x1B", alt: "\x1B3", ctrlAlt: "\x1B\x1B" }, "4": { ctrl: "\x1C", alt: "\x1B4", ctrlAlt: "\x1B\x1C" }, "5": { ctrl: "\x1D", alt: "\x1B5", ctrlAlt: "\x1B\x1D" }, "6": { ctrl: "\x1E", alt: "\x1B6", ctrlAlt: "\x1B\x1E" }, "7": { ctrl: "\x1F", alt: "\x1B7", ctrlAlt: "\x1B\x1F" }, "8": { ctrl: "\x7F", alt: "\x1B8", ctrlAlt: "\x1B\x7F" }, "9": { ctrl: "9", alt: "\x1B9", ctrlAlt: "\x1B9" }, }; export function getSequenceWithModifier( key: SpecialKey, activeModifier: ModifierKey | null ): { sequence: string; clearModifier: boolean } | null { // Handle modifier keys (one-shot) if (key === "ctrl" || key === "alt") { return null; // Modifiers don't send anything themselves } const sequence = KEY_SEQUENCES[key]; if (!sequence) return null; // Check if we have an active modifier and the key is a single character if (activeModifier && sequence.length === 1) { const char = sequence; const mapping = MODIFIER_PREFIXES[char.toLowerCase()]; if (mapping) { return { sequence: mapping[activeModifier], clearModifier: true }; } } return { sequence, clearModifier: !!activeModifier }; } export function applyModifierToChar( char: string, modifier: ModifierKey ): string | null { if (char.length !== 1) return null; const mapping = MODIFIER_PREFIXES[char.toLowerCase()]; if (!mapping) return null; return mapping[modifier]; } export { KEY_SEQUENCES };