UNPKG

emit-keypress

Version:

Drop-dead simple keypress event emitter for Node.js. Create powerful CLI applications and experiences with ease.

1,752 lines (1,745 loc) 69.7 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // index.ts import { stdin, stdout } from "process"; // node_modules/.pnpm/detect-terminal@3.0.0/node_modules/detect-terminal/dist/index.mjs import path from "path"; import { execFileSync as nodeExecFileSync } from "child_process"; import { execFileSync as nodeExecFileSync2 } from "child_process"; var __defProp2 = Object.defineProperty; var __name2 = /* @__PURE__ */ __name((target, value) => __defProp2(target, "name", { value, configurable: true }), "__name"); var TRUE_COLOR_PATTERN = /^(truecolor|24bits?)$/; var has256Color = /* @__PURE__ */ __name2((value) => { return Boolean(value?.match(/256/)); }, "has256Color"); var supportsTrueColor = /* @__PURE__ */ __name2((value) => { return Boolean(value?.match(TRUE_COLOR_PATTERN)); }, "supportsTrueColor"); var getColorSupport = /* @__PURE__ */ __name2((env) => { return { supports256Color: has256Color(env.TERM) || has256Color(env.COLORTERM), supportsTrueColor: supportsTrueColor(env.COLORTERM) }; }, "getColorSupport"); var NO_BASIC_COLOR_TERMINALS = /* @__PURE__ */ new Set([ "dumb", "linux_console", "none", "unknown", "vt100" ]); var getColorLevel = /* @__PURE__ */ __name2((env, terminal, colorSupport = getColorSupport(env)) => { const { supports256Color, supportsTrueColor: supportsTrueColor2 } = colorSupport; if (supportsTrueColor2) { return 3; } if (supports256Color) { return 2; } if (terminal && !NO_BASIC_COLOR_TERMINALS.has(terminal)) { return 1; } if (env.TERM_PROGRAM || env.COLORTERM || env.TERMUX_VERSION) { return 1; } return 0; }, "getColorLevel"); var AMBIGUOUS_ENV_TERMINALS = /* @__PURE__ */ new Set([ "linux_console", "truecolor_terminal", "vt100", "xterm", "xterm_256color", "xterm_truecolor" ]); var SHELL_PROCESS_NAMES = /* @__PURE__ */ new Set([ "bash", "csh", "dash", "fish", "ksh", "login", "node", "nodejs", "nu", "sh", "sudo", "tcsh", "zsh" ]); var normalizeIdentifier = /* @__PURE__ */ __name2((value) => { return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_"); }, "normalizeIdentifier"); var normalizeAppName = /* @__PURE__ */ __name2((value, platform) => { const appName = platform === "darwin" ? path.parse(value).name : value; return normalizeIdentifier(appName); }, "normalizeAppName"); var isAmbiguousEnvResult = /* @__PURE__ */ __name2((terminal, options = {}) => { if (!terminal) { return true; } if (options.preferOuter && (terminal === "tmux" || terminal === "screen")) { return true; } return AMBIGUOUS_ENV_TERMINALS.has(terminal); }, "isAmbiguousEnvResult"); var hasKonsoleEnvironment = /* @__PURE__ */ __name2((env) => { return Object.keys(env).some((envVar) => /konsole/i.test(envVar)); }, "hasKonsoleEnvironment"); var normalizeParentProcessName = /* @__PURE__ */ __name2((processName) => { const normalized = normalizeIdentifier(path.parse(processName).name); switch (normalized) { case "alacritty": case "aterm": case "atomic_terminal": case "eterm": case "foot": case "ghostty": case "hyper": case "kitty": case "konsole": case "kuake": case "mate_terminal": case "mrxvt": case "powershell": case "putty": case "qterminal": case "rio": case "rxvt": case "terminator": case "terminology": case "tilda": case "tmux": case "warp": case "wezterm": case "wterm": return normalized; case "apple_terminal": case "terminal": return "terminal"; case "cmd": return "cmd"; case "code": case "code_insiders": return "vscode"; case "conhost": return "conhost"; case "gnome": case "gnome_terminal": case "gnome_terminal_server": case "guake": return "gnome_terminal"; case "iterm": case "iterm2": return "iterm"; case "login": case "linux": return "linux_console"; case "pwsh": return "powershell"; case "screen": return "screen"; case "terminal_app": return "terminal_app"; case "urxvt": case "urxvt256c": case "urxvt256c_ml": case "urxvt_ml": return "rxvt"; case "wt": case "windows_terminal": return "windows_terminal"; case "xfce": case "xfce_terminal": case "xfce4_terminal": return "xfce4_terminal"; default: { if (normalized.startsWith("gnome_terminal")) { return "gnome_terminal"; } if (normalized.startsWith("warp")) { return "warp"; } return null; } } }, "normalizeParentProcessName"); var colorVariant = /* @__PURE__ */ __name2((terminal, supports256Color, supportsTrueColor2) => { return supports256Color || supportsTrueColor2 ? `${terminal}_256color` : terminal; }, "colorVariant"); var normalizeTermProgram = /* @__PURE__ */ __name2((termProgram) => { switch (termProgram) { case "apple_terminal": return "terminal"; case "eterm": return "eterm"; case "gnome_terminal": case "gnome_terminal_server": return "gnome_terminal"; case "hyper": return "hyper"; case "iterm_app": case "iterm": case "iterm2": return "iterm"; case "kitty": return "kitty"; case "konsole": return "konsole"; case "mate_terminal": return "mate_terminal"; case "powershell": return "powershell"; case "putty": return "putty"; case "qterminal": return "qterminal"; case "rio": return "rio"; case "rxvt": return "rxvt"; case "terminal_app": return "terminal_app"; case "terminal": return "terminal"; case "terminator": return "terminator"; case "termux": return "termux"; case "vscode": return "vscode"; case "warp": return "warp"; case "wezterm": return "wezterm"; case "xfce4_terminal": return "xfce4_terminal"; case "alacritty": return "alacritty"; default: return null; } }, "normalizeTermProgram"); var detectFromTerm = /* @__PURE__ */ __name2((term, env, platform) => { const { supports256Color, supportsTrueColor: supportsTrueColor2 } = getColorSupport(env); if (term === "xterm" || term === "xterm_256color") { if (supportsTrueColor2) { return "xterm_truecolor"; } if (env.VTE_VERSION) { const vteVersion = Number.parseInt(env.VTE_VERSION, 10); if (vteVersion >= 3803) { return colorVariant("gnome_terminal", supports256Color, supportsTrueColor2); } } if (hasKonsoleEnvironment(env)) { return colorVariant("konsole", supports256Color, supportsTrueColor2); } if (platform === "darwin") { return "terminal"; } return term; } switch (term) { case "linux": return "linux_console"; case "gnome": case "gnome_256color": case "gnome_terminal": case "gnome_terminal_256color": case "guake": case "terminator": return colorVariant("gnome_terminal", supports256Color, supportsTrueColor2); case "konsole": return colorVariant("konsole", supports256Color, supportsTrueColor2); case "rxvt": case "rxvt_xpm": case "rxvt_unicode": case "rxvt_unicode_256color": case "urxvt": case "urxvt_ml": case "urxvt256c": case "urxvt256c_ml": return colorVariant("rxvt", term === "rxvt" || supports256Color, supportsTrueColor2); case "xfce": case "xfce_terminal": case "xfce4_terminal": return "xfce4_terminal"; case "eterm": return colorVariant("eterm", supports256Color, supportsTrueColor2); case "xterm_kitty": case "kitty": return "kitty"; case "screen": case "screen_256color": return "screen"; case "tmux": case "tmux_256color": return "tmux"; case "vt100": return "vt100"; case "aterm": case "atomic_terminal": case "dopamine": case "foot": case "ghostty": case "kuake": case "rio": case "terminology": case "termux": case "tilda": case "wterm": case "mrxvt": return term; default: if (/screen/.test(term)) return "screen"; if (/tmux/.test(term)) return "tmux"; if (/rxvt/.test(term)) return "rxvt"; if (/vt100/.test(term)) return "vt100"; if (/linux/.test(term)) return "linux_console"; if (/alacritty/.test(term)) return "alacritty"; if (/dopamine/.test(term)) return "dopamine"; if (/kitty/.test(term)) return "kitty"; if (/ghostty/.test(term)) return "ghostty"; if (/^foot/.test(term)) return "foot"; if (/^rio/.test(term)) return "rio"; return term; } }, "detectFromTerm"); var detectFromEnvResult = /* @__PURE__ */ __name2((options = {}) => { const env = options.env ?? process.env; const platform = options.platform ?? process.platform; const term = env.TERM ? normalizeIdentifier(env.TERM) : void 0; if (platform === "android" && env.TERMUX_VERSION) { return { terminal: "termux", source: "env", generic: term }; } if (!options.preferOuter && term) { if (term.startsWith("tmux")) { return { terminal: "tmux", source: "env", generic: term }; } if (term.startsWith("screen")) { return { terminal: "screen", source: "env", generic: term }; } } if (env.KITTY_PID) { return { terminal: "kitty", source: "env", generic: term }; } if (env.GHOSTTY_RESOURCES_DIR) { return { terminal: "ghostty", source: "env", generic: term }; } if (env.ALACRITTY_SOCKET || env.ALACRITTY_LOG) { return { terminal: "alacritty", source: "env", generic: term }; } const termProgram = env.TERM_PROGRAM ? normalizeAppName(env.TERM_PROGRAM, platform) : void 0; if (termProgram) { return { terminal: normalizeTermProgram(termProgram) ?? termProgram, source: "env", generic: term }; } if (typeof env.VSCODE_PID !== "undefined" || typeof env.TERM_PROGRAM_VERSION !== "undefined" && /vscode/i.test(env.TERM_PROGRAM_VERSION)) { return { terminal: "vscode", source: "env", generic: term }; } if (term && term !== "unknown") { return { terminal: detectFromTerm(term, env, platform), source: "env", generic: term }; } const colorTerm = env.COLORTERM ? normalizeIdentifier(env.COLORTERM) : void 0; if (colorTerm === "truecolor" || colorTerm === "24bit" || colorTerm === "24bits") { return { terminal: "truecolor_terminal", source: "env", generic: term }; } if (colorTerm) { return { terminal: colorTerm, source: "env", generic: term }; } return null; }, "detectFromEnvResult"); var runPs = /* @__PURE__ */ __name2((run, args) => { return run("ps", args, { encoding: "utf8", timeout: 1e3, stdio: ["ignore", "pipe", "ignore"] }); }, "runPs"); var getParentProcess = /* @__PURE__ */ __name2((pid, options = {}) => { const run = options.execFileSync ?? nodeExecFileSync; const parentPid = Number.parseInt( runPs(run, ["-o", "ppid=", "-p", String(pid)]).trim(), 10 ); if (!Number.isFinite(parentPid) || parentPid <= 1) { return null; } const appName = runPs(run, ["-o", "comm=", "-p", String(parentPid)]).trim(); if (!appName) { return null; } return { pid: parentPid, appName }; }, "getParentProcess"); var colorVariant2 = /* @__PURE__ */ __name2((terminal, supports256Color, supportsTrueColor2) => { return supports256Color || supportsTrueColor2 ? `${terminal}_256color` : terminal; }, "colorVariant"); var applyParentColorVariant = /* @__PURE__ */ __name2((terminal, env) => { const { supports256Color, supportsTrueColor: supportsTrueColor2 } = getColorSupport(env); switch (terminal) { case "eterm": case "konsole": case "rxvt": return colorVariant2(terminal, supports256Color, supportsTrueColor2); case "gnome_terminal": case "terminator": return colorVariant2("gnome_terminal", supports256Color, supportsTrueColor2); default: return terminal; } }, "applyParentColorVariant"); var detectFromParentProcessResult = /* @__PURE__ */ __name2((options = {}) => { const env = options.env ?? process.env; const platform = options.platform ?? process.platform; if (platform === "win32" || env.SSH_CONNECTION) { return null; } const seenPids = /* @__PURE__ */ new Set(); let pid = options.pid ?? process.pid; for (let depth = 0; depth < 12; depth += 1) { if (seenPids.has(pid)) { break; } seenPids.add(pid); try { const parent = getParentProcess(pid, options); if (!parent) { break; } const normalized = normalizeParentProcessName(parent.appName); if (normalized === "screen" || normalized === "tmux") { if (!options.preferOuter) { return { terminal: normalized, source: "parent", appName: parent.appName, pid: parent.pid }; } pid = parent.pid; continue; } if (normalized) { return { terminal: applyParentColorVariant(normalized, env), source: "parent", appName: parent.appName, pid: parent.pid }; } if (!SHELL_PROCESS_NAMES.has(normalizeIdentifier(parent.appName))) { break; } pid = parent.pid; } catch { break; } } return null; }, "detectFromParentProcessResult"); var detectFromProcessTitleResult = /* @__PURE__ */ __name2((options = {}) => { const processTitle = (options.processTitle ?? process.title)?.toLowerCase() ?? ""; if (/^alacritty/.test(processTitle)) { return { terminal: "alacritty", source: "process_title" }; } if (/^kitty/.test(processTitle)) { return { terminal: "kitty", source: "process_title" }; } if (/^wezterm/.test(processTitle)) { return { terminal: "wezterm", source: "process_title" }; } if (/^hyper/.test(processTitle)) { return { terminal: "hyper", source: "process_title" }; } if (/^foot/.test(processTitle)) { return { terminal: "foot", source: "process_title" }; } if (/^rio/.test(processTitle)) { return { terminal: "rio", source: "process_title" }; } if (/^ghostty/.test(processTitle)) { return { terminal: "ghostty", source: "process_title" }; } if (/bash/.test(processTitle)) { return { terminal: "bash", source: "process_title" }; } if (/zsh/.test(processTitle)) { return { terminal: "zsh", source: "process_title" }; } if (/ksh/.test(processTitle)) { return { terminal: "ksh", source: "process_title" }; } if (/fish/.test(processTitle)) { return { terminal: "fish", source: "process_title" }; } if (/csh/.test(processTitle)) { return { terminal: "csh", source: "process_title" }; } if (/tcsh/.test(processTitle)) { return { terminal: "tcsh", source: "process_title" }; } if (/pwsh/.test(processTitle)) { return { terminal: "powershell", source: "process_title" }; } if (/powershell/.test(processTitle)) { return { terminal: "powershell", source: "process_title" }; } if (/cmd/.test(processTitle)) { return { terminal: "cmd", source: "process_title" }; } if (/sh$/.test(processTitle)) { return { terminal: "sh", source: "process_title" }; } if (/^node/.test(processTitle)) { return { terminal: "node", source: "process_title" }; } return null; }, "detectFromProcessTitleResult"); var runShellTerm = /* @__PURE__ */ __name2((run) => { return run("sh", ["-c", 'printf %s "$TERM"'], { encoding: "utf8", timeout: 1e3, stdio: ["ignore", "pipe", "ignore"] }); }, "runShellTerm"); var detectFromShellResult = /* @__PURE__ */ __name2((options = {}) => { const env = options.env ?? process.env; const platform = options.platform ?? process.platform; try { if (platform === "win32") { if (env.WT_SESSION) { return { terminal: "windows_terminal", source: "shell" }; } const shell = env.COMSPEC?.toLowerCase() || ""; if (/powershell/i.test(shell)) { return { terminal: "powershell", source: "shell" }; } if (/pwsh/i.test(shell)) { return { terminal: "powershell", source: "shell" }; } if (/cmd\.exe/i.test(shell)) { return { terminal: "cmd", source: "shell" }; } if (/wt\.exe/i.test(shell)) { return { terminal: "windows_terminal", source: "shell" }; } if (/conhost\.exe/i.test(shell)) { return { terminal: "conhost", source: "shell" }; } return { terminal: "windows_cmd", source: "shell" }; } const run = options.execFileSync ?? nodeExecFileSync2; const terminal = normalizeIdentifier(runShellTerm(run)); if (!terminal) { return null; } if (!options.preferOuter) { if (terminal.startsWith("tmux")) { return { terminal: "tmux", source: "shell" }; } if (terminal.startsWith("screen")) { return { terminal: "screen", source: "shell" }; } } return { terminal, source: "shell" }; } catch { return null; } }, "detectFromShellResult"); var getTerminalResult = /* @__PURE__ */ __name2((options) => { const envTerminal = detectFromEnvResult(options); let result = envTerminal; if (options.resolveAmbiguousFromParent && isAmbiguousEnvResult(envTerminal?.terminal ?? null, options)) { result = detectFromParentProcessResult(options) ?? result; } result ??= detectFromShellResult(options); result ??= detectFromProcessTitleResult(options); return result ?? { terminal: envTerminal?.terminal ?? "unknown", source: envTerminal ? envTerminal.source : "unknown", generic: envTerminal?.generic }; }, "getTerminalResult"); var detectTerminalDetails = /* @__PURE__ */ __name2((options = {}) => { const env = options.env ?? process.env; const stdout2 = options.stdout ?? process.stdout; const isTTY = Boolean(stdout2.isTTY); const isSSH = Boolean(env.SSH_CONNECTION); const term = env.TERM?.trim(); const termProgram = env.TERM_PROGRAM?.trim(); const colorTerm = env.COLORTERM?.trim(); const colorSupport = getColorSupport(env); if (!isTTY && !options.unpipe) { return { terminal: "none", source: "none", isTTY, isSSH, isAmbiguous: false, supportsColor: false, colorLevel: 0, supports256Color: colorSupport.supports256Color, supportsTrueColor: colorSupport.supportsTrueColor, term, termProgram, colorTerm, generic: "none" }; } const result = getTerminalResult(options); const colorLevel = getColorLevel(env, result.terminal, colorSupport); return { terminal: result.terminal, source: result.source, isTTY, isSSH, isAmbiguous: result.source === "env" && isAmbiguousEnvResult(result.terminal, options), colorLevel, supportsColor: colorLevel > 0, supports256Color: colorSupport.supports256Color, supportsTrueColor: colorSupport.supportsTrueColor, term, termProgram, colorTerm, generic: result.generic ?? term?.toLowerCase() ?? "unknown", pid: result.pid, appName: result.appName }; }, "detectTerminalDetails"); var detectTerminal = /* @__PURE__ */ __name2((options = {}) => { return detectTerminalDetails(options).terminal; }, "detectTerminal"); // src/emit-keypress.ts import { StringDecoder } from "string_decoder"; import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "timers"; // src/keypress.ts var kEscape = "\x1B"; var kUTF16SurrogateThreshold = 65536; function CSI(strings, ...args) { let ret = `${kEscape}[`; for (let n = 0; n < strings.length; n++) { ret += strings[n]; if (n < args.length) { ret += args[n]; } } return ret; } __name(CSI, "CSI"); CSI.kEscape = kEscape; CSI.kClearToLineBeginning = CSI`1K`; CSI.kClearToLineEnd = CSI`0K`; CSI.kClearLine = CSI`2K`; CSI.kClearScreenDown = CSI`0J`; var CSI_U_ENABLE = `${kEscape}[>4;1m`; var CSI_U_DISABLE = `${kEscape}[>4;0m`; var KITTY_ENABLE = `${kEscape}[>1u`; var KITTY_DISABLE = `${kEscape}[<u`; function charLengthAt(str, i) { if (str.length <= i) { return 1; } return str.codePointAt(i) >= kUTF16SurrogateThreshold ? 2 : 1; } __name(charLengthAt, "charLengthAt"); function* emitKeys(stream) { while (true) { let ch = yield; let s = ch; let escaped = false; const key = { sequence: null, name: void 0, ctrl: false, meta: false, shift: false, fn: false }; if (ch === kEscape) { escaped = true; s += ch = yield; if (ch === kEscape) { s += ch = yield; } } if (escaped && (ch === "O" || ch === "[")) { let code = ch; let modifier = 0; if (ch === "O") { s += ch = yield; if (ch >= "0" && ch <= "9") { modifier = (ch >> 0) - 1; s += ch = yield; } code += ch; } else if (ch === "[") { s += ch = yield; if (ch === "[") { code += ch; s += ch = yield; } const cmdStart = s.length - 1; if (ch >= "0" && ch <= "9") { s += ch = yield; if (ch >= "0" && ch <= "9") { s += ch = yield; if (ch >= "0" && ch <= "9") { s += ch = yield; } } } if (ch === ";") { s += ch = yield; if (ch >= "0" && ch <= "9") { s += yield; } } const cmd = s.slice(cmdStart); let match; const SPECIAL_NAMES = { 8: "backspace", // BS (ctrl+h legacy) 9: "tab", 10: "enter", // LF 13: "return", // CR 27: "escape", 32: "space", 127: "backspace" // DEL }; if (match = /^(\d+);(\d+)u$/.exec(cmd)) { const charCode = parseInt(match[1], 10); modifier = parseInt(match[2], 10) - 1; const char = String.fromCharCode(charCode); key.name = SPECIAL_NAMES[charCode] || char.toLowerCase(); key.ctrl = Boolean(modifier & 4); key.meta = Boolean(modifier & 10); key.shift = Boolean(modifier & 1) || char !== char.toLowerCase(); key.code = `[${match[1]}u`; key.sequence = s; stream.emit("keypress", void 0, key); continue; } if (match = /^27;(\d+);(\d+)~$/.exec(cmd)) { modifier = parseInt(match[1], 10) - 1; const charCode = parseInt(match[2], 10); const char = String.fromCharCode(charCode); key.name = SPECIAL_NAMES[charCode] || char.toLowerCase(); key.ctrl = Boolean(modifier & 4); key.meta = Boolean(modifier & 10); key.shift = Boolean(modifier & 1) || char !== char.toLowerCase(); key.code = `[27;${match[1]};${match[2]}~`; key.sequence = s; stream.emit("keypress", void 0, key); continue; } if (match = /^(?:(\d\d?)(?:;(\d))?([~^$])|(\d{3}~))$/.exec(cmd)) { if (match[4]) { code += match[4]; } else { code += match[1] + match[3]; modifier = (match[2] || 1) - 1; } } else if (match = /^((\d;)?(\d))?([A-Za-z])$/.exec(cmd)) { code += match[4]; modifier = (match[3] || 1) - 1; } else { code += cmd; } } if (/\[(?:1[5-9]|2[0-2]);10/.test(code)) { s += ch = yield; } key.ctrl = Boolean(modifier & 4); key.meta = Boolean(modifier & 10); key.shift = Boolean(modifier & 1); key.code = code; if (!key.meta) { const parts = [...s]; if (parts[0] === "\x1B" && parts[1] === "\x1B") { key.meta = true; } } if (/\x1B\[1;[59][FH]/.test(s)) { key.fn = true; } switch (code) { case "[M": { key.name = "mouse"; s += ch = yield; s += ch = yield; s += ch = yield; break; } /* xterm/gnome ESC [ letter (with modifier) */ case "[P": key.name = "f1"; key.fn = true; break; case "[Q": key.name = "f2"; key.fn = true; break; case "[R": key.name = "f3"; key.fn = true; break; case "[S": key.name = "f4"; key.fn = true; break; /* xterm/gnome ESC O letter (without modifier) */ case "OP": key.name = "f1"; key.fn = true; break; case "OQ": key.name = "f2"; key.fn = true; break; case "OR": key.name = "f3"; key.fn = true; break; case "OS": key.name = "f4"; key.fn = true; break; /* xterm/rxvt ESC [ number ~ */ case "[11~": key.name = "f1"; key.fn = true; break; case "[12~": key.name = "f2"; key.fn = true; break; case "[13~": key.name = "f3"; key.fn = true; break; case "[14~": key.name = "f4"; key.fn = true; break; /* paste bracket mode */ case "[200~": key.name = "paste-start"; break; case "[201~": key.name = "paste-end"; break; /* from Cygwin and used in libuv */ case "[[A": key.name = "f1"; key.fn = true; break; case "[[B": key.name = "f2"; key.fn = true; break; case "[[C": key.name = "f3"; key.fn = true; break; case "[[D": key.name = "f4"; key.fn = true; break; case "[[E": key.name = "f5"; key.fn = true; break; /* common */ case "[15~": key.name = "f5"; key.fn = true; break; case "[17~": key.name = "f6"; key.fn = true; break; case "[18~": key.name = "f7"; key.fn = true; break; case "[19~": key.name = "f8"; key.fn = true; break; case "[20~": key.name = "f9"; key.fn = true; break; case "[21~": key.name = "f10"; key.fn = true; break; case "[23~": key.name = "f11"; key.fn = true; break; case "[24~": key.name = "f12"; key.fn = true; break; /* common */ case "[15;10": key.name = "f5"; key.fn = true; key.shift = true; key.meta = true; break; case "[17;10": key.name = "f7"; key.fn = true; key.shift = true; key.meta = true; break; case "[18;10": key.name = "f8"; key.fn = true; key.shift = true; key.meta = true; break; case "[19;10": key.name = "f9"; key.fn = true; key.shift = true; key.meta = true; break; case "[20;10": key.name = "f10"; key.fn = true; key.shift = true; key.meta = true; break; case "[21;10": key.name = "f11"; key.fn = true; key.shift = true; key.meta = true; break; case "[22;10": key.name = "f12"; key.fn = true; key.shift = true; key.meta = true; break; /* xterm ESC [ letter */ case "[A": key.name = "up"; break; case "[B": key.name = "down"; break; case "[C": key.name = "right"; break; case "[D": key.name = "left"; break; case "[E": key.name = "clear"; break; case "[F": key.name = "end"; break; case "[H": key.name = "home"; break; /* xterm/gnome ESC O letter */ case "OA": key.name = "up"; break; case "OB": key.name = "down"; break; case "OC": key.name = "right"; break; case "OD": key.name = "left"; break; case "OE": key.name = "clear"; break; case "OF": key.name = "end"; break; case "OH": key.name = "home"; break; /* xterm/rxvt ESC [ number ~ */ case "[1~": key.name = "home"; break; case "[2~": key.name = "insert"; break; case "[3~": key.name = "delete"; key.shift = !s.includes("3;5~"); key.fn = /^\[3;[256]~$/.test(s.slice(1)); break; case "[4~": key.name = "end"; break; case "[5~": key.name = "pageup"; break; case "[6~": key.name = "pagedown"; break; /* putty */ case "[[5~": key.name = "pageup"; break; case "[[6~": key.name = "pagedown"; break; /* rxvt */ case "[7~": key.name = "home"; break; case "[8~": key.name = "end"; break; /* rxvt keys with modifiers */ case "[a": key.name = "up"; key.shift = true; break; case "[b": key.name = "down"; key.shift = true; break; case "[c": key.name = "right"; key.shift = true; break; case "[d": key.name = "left"; key.shift = true; break; case "[e": key.name = "clear"; key.shift = true; break; case "[2$": key.name = "insert"; key.shift = true; break; case "[3$": key.name = "delete"; key.shift = true; break; case "[5$": key.name = "pageup"; key.shift = true; break; case "[6$": key.name = "pagedown"; key.shift = true; break; case "[7$": key.name = "home"; key.shift = true; break; case "[8$": key.name = "end"; key.shift = true; break; case "Oa": key.name = "up"; key.ctrl = true; break; case "Ob": key.name = "down"; key.ctrl = true; break; case "Oc": key.name = "right"; key.ctrl = true; break; case "Od": key.name = "left"; key.ctrl = true; break; case "Oe": key.name = "clear"; key.ctrl = true; break; case "[2^": key.name = "insert"; key.ctrl = true; break; case "[3^": key.name = "delete"; key.ctrl = true; break; case "[5^": key.name = "pageup"; key.ctrl = true; break; case "[6^": key.name = "pagedown"; key.ctrl = true; break; case "[7^": key.name = "home"; key.ctrl = true; break; case "[8^": key.name = "end"; key.ctrl = true; break; case "[3;5~": key.name = "delete"; key.ctrl = true; key.fn = true; break; case "[1;13": case "[1;14": key.shift = code === "[1;14"; key.ctrl = true; key.meta = true; if (ch = yield) { s += ch; switch (ch) { case "A": key.name = "up"; break; case "B": key.name = "down"; break; case "C": key.name = "right"; break; case "D": key.name = "left"; break; case "F": key.name = "right"; key.fn = true; break; case "H": key.name = "left"; key.fn = true; break; default: break; } } break; case "[3;10": if (ch = yield) { s += ch; key.name = "delete"; key.shift = true; key.meta = true; key.fn = true; } break; case "[3;13": case "[3;14": if (ch = yield) { s += ch; key.name = "delete"; key.ctrl = true; key.shift = code === "[3;14"; key.meta = true; key.fn = true; } break; case "[5;14": case "[6;14": if (ch = yield) { s += ch; key.name = code === "[5;14" ? "up" : "down"; key.ctrl = true; key.shift = true; key.meta = true; key.fn = true; } break; case "[1;10": if (ch = yield) { s += ch; } switch (ch) { case "A": key.name = "up"; break; case "B": key.name = "down"; break; case "C": key.name = "right"; break; case "D": key.name = "left"; break; case "F": key.name = "right"; key.fn = true; break; case "H": key.name = "left"; key.fn = true; break; case "P": key.name = "f1"; key.fn = true; break; case "Q": key.name = "f2"; key.fn = true; break; case "R": key.name = "f3"; key.fn = true; break; case "S": key.name = "f4"; key.fn = true; break; default: break; } key.shift = true; key.meta = true; break; case "[5;10": case "[6;10": if (ch = yield) { s += ch; key.name = code === "[5;10" ? "up" : "down"; key.shift = true; key.fn = true; } key.meta = true; break; /* misc. */ case "[Z": key.name = "tab"; key.shift = true; break; default: key.name = void 0; break; } } else if (ch === "\r") { key.name = "return"; key.meta = escaped; } else if (ch === "\n") { key.name = "enter"; key.meta = escaped; } else if (ch === " ") { key.name = "tab"; key.meta = escaped; } else if (ch === "\b") { key.name = "backspace"; key.ctrl = true; key.meta = escaped; } else if (ch === "\x7F") { key.name = "backspace"; key.meta = escaped; } else if (ch === kEscape) { key.name = "escape"; key.meta = escaped; } else if (ch === " ") { key.name = "space"; key.meta = escaped; } else if (!escaped && ch <= "") { key.name = String.fromCharCode(ch.charCodeAt(0) + "a".charCodeAt(0) - 1); key.ctrl = true; } else if (/^[0-9A-Za-z]$/.exec(ch) !== null) { key.name = ch; key.shift = /^[A-Z]$/.exec(ch) !== null; key.meta = escaped; } else if (escaped) { key.name = ch.length ? void 0 : "escape"; key.meta = false; } key.sequence = s; if (s.length !== 0 && (key.name !== void 0 || escaped)) { stream.emit("keypress", escaped ? void 0 : s, key); } else if (charLengthAt(s, 0) === s.length) { stream.emit("keypress", s, key); } } } __name(emitKeys, "emitKeys"); // src/emit-keypress.ts var { kEscape: kEscape2 } = CSI; var KEYPRESS_DECODER = /* @__PURE__ */ Symbol("keypress-decoder"); var ESCAPE_DECODER = /* @__PURE__ */ Symbol("escape-decoder"); var kSawKeyPress = /* @__PURE__ */ Symbol("saw-key-press"); var ESCAPE_CODE_TIMEOUT = 500; function emitKeypressEvents(stream, iface = {}) { if (stream[KEYPRESS_DECODER]) return; stream[KEYPRESS_DECODER] = new StringDecoder("utf8"); stream[ESCAPE_DECODER] = emitKeys(stream); stream[ESCAPE_DECODER].next(); const triggerEscape = /* @__PURE__ */ __name(() => stream[ESCAPE_DECODER].next(""), "triggerEscape"); const { escapeCodeTimeout = ESCAPE_CODE_TIMEOUT } = iface; let timeoutId; function onData(input) { if (stream.listenerCount("keypress") > 0) { const string = stream[KEYPRESS_DECODER].write(input); if (string) { clearTimeout2(timeoutId); iface[kSawKeyPress] = charLengthAt(string, 0) === string.length; iface.isCompletionEnabled = false; let length = 0; for (const character of string) { length += character.length; if (length === string.length) { iface.isCompletionEnabled = true; } try { stream[ESCAPE_DECODER].next(character); if (length === string.length && character === kEscape2) { timeoutId = setTimeout2(triggerEscape, escapeCodeTimeout); } } catch (err) { stream[ESCAPE_DECODER] = emitKeys(stream); stream[ESCAPE_DECODER].next(); throw err; } } } } else { stream.off("data", onData); stream.on("newListener", onNewListener); } } __name(onData, "onData"); function onNewListener(event) { if (event === "keypress") { stream.on("data", onData); stream.off("newListener", onNewListener); } } __name(onNewListener, "onNewListener"); if (stream.listenerCount("keypress") > 0) { stream.on("data", onData); } else { stream.on("newListener", onNewListener); } } __name(emitKeypressEvents, "emitKeypressEvents"); // src/mousepress.ts var mousepress = /* @__PURE__ */ __name((s, buf, state = {}) => { let parts; let b; let x; let y; let mod; let params; let down; let page; let button; const key = { name: void 0, ctrl: false, meta: false, shift: false }; if (Buffer.isBuffer(s)) { if (s[0] > 127 && s[1] === void 0) { s[0] -= 128; s = "\x1B" + s.toString("utf8"); } else { s = s.toString("utf8"); } } const bx = s.charCodeAt(4); const by = s.charCodeAt(5); if (buf[0] === 27 && buf[1] === 91 && buf[2] === 77 && (state.isVTE || bx >= 65533 || by >= 65533 || bx > 0 && bx < 32 || by > 0 && by < 32 || buf[4] > 223 && buf[4] < 248 && buf.length === 6 || buf[5] > 223 && buf[5] < 248 && buf.length === 6)) { b = buf[3]; x = buf[4]; y = buf[5]; if (x < 32) x += 255; if (y < 32) y += 255; if (x === 255) x = 255; if (y === 255) y = 255; s = "\x1B[M" + String.fromCharCode(b) + String.fromCharCode(x) + String.fromCharCode(y); } if (parts = /^\x1b\[M([\x00\u0020-\uffff]{3})/.exec(s)) { b = parts[1].charCodeAt(0); x = parts[1].charCodeAt(1); y = parts[1].charCodeAt(2); key.name = "mouse"; key.type = "X10"; key.raw = [b, x, y, parts[0]]; key.buf = buf; key.x = x - 32; key.y = y - 32; if (state.zero) { key.x--; key.y--; } if (x === 0) key.x = 255; if (y === 0) key.y = 255; mod = b >> 2; key.shift = Boolean(mod & 1); key.meta = Boolean(mod >> 1 & 1); key.ctrl = Boolean(mod >> 2 & 1); b -= 32; if (b >> 6 & 1) { key.action = b & 1 ? "wheeldown" : "wheelup"; key.button = "middle"; } else if (b === 3) { key.action = "mouseup"; key.button = state._lastButton || "unknown"; delete state._lastButton; } else { key.action = "mousedown"; button = b & 3; key.button = button === 0 ? "left" : button === 1 ? "middle" : button === 2 ? "right" : "unknown"; state._lastButton = key.button; } if (b === 35 || b === 39 || b === 51 || b === 43 || state.isVTE && (b === 32 || b === 36 || b === 48 || b === 40)) { delete key.button; key.action = "mousemove"; } key.sequence = s; return key; } if (parts = /^\x1b\[(\d+;\d+;\d+)M/.exec(s)) { params = parts[1].split(";"); b = Number(params[0]); x = Number(params[1]); y = Number(params[2]); key.name = "mouse"; key.type = "urxvt"; key.raw = [b, x, y, parts[0]]; key.buf = buf; key.x = x; key.y = y; if (state.zero) { key.x--; key.y--; } mod = b >> 2; key.shift = Boolean(mod & 1); key.meta = Boolean(mod >> 1 & 1); key.ctrl = Boolean(mod >> 2 & 1); if (b === 128 || b === 129) b = 67; b -= 32; if (b >> 6 & 1) { key.action = b & 1 ? "wheeldown" : "wheelup"; key.button = "middle"; } else if (b === 3) { key.action = "mouseup"; key.button = state._lastButton || "unknown"; delete state._lastButton; } else { key.action = "mousedown"; button = b & 3; key.button = button === 0 ? "left" : button === 1 ? "middle" : button === 2 ? "right" : "unknown"; state._lastButton = key.button; } if (b === 35 || b === 39 || b === 51 || b === 43 || state.isVTE && (b === 32 || b === 36 || b === 48 || b === 40)) { delete key.button; key.action = "mousemove"; } key.sequence = s; return key; } if (parts = /^\x1b\[<(\d+;\d+;\d+)([mM])/.exec(s)) { down = parts[2] === "M"; params = parts[1].split(";"); b = Number(params[0]); x = Number(params[1]); y = Number(params[2]); key.name = "mouse"; key.type = "sgr"; key.raw = [b, x, y, parts[0]]; key.buf = buf; key.x = x; key.y = y; if (state.zero) { key.x--; key.y--; } mod = b >> 2; key.shift = Boolean(mod & 1); key.meta = Boolean(mod >> 1 & 1); key.ctrl = Boolean(mod >> 2 & 1); if (b >> 6 & 1) { key.action = b & 1 ? "wheeldown" : "wheelup"; key.button = "middle"; } else { key.action = down ? "mousedown" : "mouseup"; button = b & 3; key.button = button === 0 ? "left" : button === 1 ? "middle" : button === 2 ? "right" : "unknown"; } if (b === 35 || b === 39 || b === 51 || b === 43 || state.isVTE && (b === 32 || b === 36 || b === 48 || b === 40)) { delete key.button; key.action = "mousemove"; } key.sequence = s; return key; } if (parts = /^\x1b\[<(\d+;\d+;\d+;\d+)&w/.exec(s)) { params = parts[1].split(";"); b = Number(params[0]); x = Number(params[1]); y = Number(params[2]); page = Number(params[3]); key.name = "mouse"; key.type = "dec"; key.raw = [b, x, y, parts[0]]; key.buf = buf; key.x = x; key.y = y; key.page = page; if (state.zero) { key.x--; key.y--; } key.action = b === 3 ? "mouseup" : "mousedown"; key.button = b === 2 ? "left" : b === 4 ? "middle" : b === 6 ? "right" : "unknown"; key.sequence = s; return key; } if (parts = /^\x1b\[24([0135])~\[(\d+),(\d+)\]\r/.exec(s)) { b = Number(parts[1]); x = Number(parts[2]); y = Number(parts[3]); key.name = "mouse"; key.type = "vt300"; key.raw = [b, x, y, parts[0]]; key.buf = buf; key.x = x; key.y = y; if (state.zero) { key.x--; key.y--; } key.action = "mousedown"; key.button = b === 1 ? "left" : b === 2 ? "middle" : b === 5 ? "right" : "unknown"; key.sequence = s; return key; } if (parts = /^\x1b\[(O|I)/.exec(s)) { key.action = parts[1] === "I" ? "focus" : "blur"; } key.x = s.charCodeAt(4) - 32; key.y = s.charCodeAt(5) - 32; key.scroll = 0; key.ctrl = Boolean(1 << 4 & b); key.meta = Boolean(1 << 3 & b); key.shift = Boolean(1 << 2 & b); key.release = (3 & b) === 3; if (1 << 6 & b) { key.scroll = 1 & b ? 1 : -1; } if (!key.release && !key.scroll) { key.button = b & 3; } key.sequence = s; return key; }, "mousepress"); // src/keycodes.ts var keycodes = [ { sequence: "\r", shortcut: "return" }, { sequence: "\x7F", shortcut: "backspace" }, { sequence: "\x1B", shortcut: "escape" }, { sequence: "\x1B[1~", shortcut: "home" }, { sequence: "\x1B\x1B[1~", shortcut: "home" }, { sequence: "\x1B[2~", shortcut: "insert" }, { sequence: "\x1B[3~", shortcut: "delete" }, { sequence: "\x1B[4~", shortcut: "end" }, { sequence: "\x1B[A", shortcut: "up" }, { sequence: "\x1B[B", shortcut: "down" }, { sequence: "\x1B[C", shortcut: "right" }, { sequence: "\x1B[D", shortcut: "left" }, // <shift> { sequence: "\x1B[2;2~", shortcut: "shift+insert" }, { sequence: "\x1B[5;2~", shortcut: "shift+pageup" }, { sequence: "\x1B[6;2~", shortcut: "shift+pagedown" }, { sequence: "\x1B[1;2A", shortcut: "shift+up" }, { sequence: "\x1B[1;2B", shortcut: "shift+down" }, { sequence: "\x1B[1;2C", shortcut: "shift+right" }, { sequence: "\x1B[1;2D", shortcut: "shift+left" }, { sequence: "\x1B[Z", shortcut: "shift+tab" }, // <meta> { sequence: "\x1Bf", shortcut: "meta+right" }, { sequence: "\x1Bb", shortcut: "meta+left" }, { sequence: "\x1B[1;9A", shortcut: "meta+up" }, { sequence: "\x1B[1;9B", shortcut: "meta+down" }, { sequence: "\x1B[1;9C", shortcut: "cmd+meta+right" }, { sequence: "\x1B[1;9D", shortcut: "cmd+meta+left" }, { sequence: "\x1B[2;3~", shortcut: "meta+insert" }, { sequence: "\x1B[3;3~", shortcut: "meta+delete" }, { sequence: "\x1B[5;3~", shortcut: "meta+pageup" }, { sequence: "\x1B[6;3~", shortcut: "meta+pagedown" }, { sequence: "\x1B\x7F", shortcut: "meta+backspace" }, // <shift+meta> { sequence: "\x1B[1;10A", shortcut: "shift+meta+up" }, { sequence: "\x1B[1;10B", shortcut: "shift+meta+down" }, { sequence: "\x1B[1;10C", shortcut: "shift+meta+right" }, { sequence: "\x1B[1;10D", shortcut: "shift+meta+left" }, { sequence: "\x1B[2;4~", shortcut: "shift+meta+insert" }, { sequence: "\x1B[3;4~", shortcut: "shift+meta+delete" }, { sequence: "\x1B[5;4~", shortcut: "shift+meta+pageup" }, { sequence: "\x1B[6;4~", shortcut: "shift+meta+pagedown" }, // <ctrl> { sequence: "\0", shortcut: "ctrl+`" }, { sequence: "\f", shortcut: "ctrl+4" }, // { sequence: '\x0d', shortcut: 'ctrl+5' }, { sequence: "", shortcut: "ctrl+6" }, { sequence: "", shortcut: "ctrl+7" }, { sequence: "", shortcut: "ctrl+a" }, { sequence: "", shortcut: "ctrl+b" }, { sequence: "", shortcut: "ctrl+c" }, { sequence: "", shortcut: "ctrl+d" }, { sequence: "", shortcut: "ctrl+e" }, { sequence: "", shortcut: "ctrl+f" }, { sequence: "\x07", shortcut: "ctrl+g" }, // { sequence: '\b', shortcut: 'ctrl+h' }, { sequence: " ", shortcut: "ctrl+i" }, { sequence: "\n", shortcut: "ctrl+j", command: "enter" }, { sequence: "\v", shortcut: "ctrl+k" }, { sequence: "\f", shortcut: "ctrl+l" }, { sequence: "", shortcut: "ctrl+n" }, { sequence: "", shortcut: "ctrl+o" }, { sequence: "", shortcut: "ctrl+p" }, { sequence: "", shortcut: "ctrl+q" }, { sequence: "", shortcut: "ctrl+r" }, { sequence: "", shortcut: "ctrl+s" }, { sequence: "", shortcut: "ctrl+t" }, { sequence: "", shortcut: "ctrl+u" }, { sequence: "", shortcut: "ctrl+v" }, { sequence: "", shortcut: "ctrl+w" }, { sequence: "", shortcut: "ctrl+x" }, { sequence: "", shortcut: "ctrl+y" }, { sequence: "", shortcut: "ctrl+z" }, { sequence: "", shortcut: "ctrl+-" }, { sequence: "", shortcut: "ctrl+|" }, { sequence: "", shortcut: "ctrl+]" }, { sequence: "\x1B[1;5A", shortcut: "ctrl+up", weight: -1 }, { sequence: "\x1B[1;5B", shortcut: "ctrl+down", weight: -1 }, { sequence: "\x1B[1;5C", shortcut: "ctrl+right", weight: -1 }, { sequence: "\x1B[1;5D", shortcut: "ctrl+left", weight: -1 }, { sequence: "\x1B[2;5~", shortcut: "ctrl+insert", weight: -1 }, { sequence: "\x1B[5;5~", shortcut: "ctrl+pageup", weight: -1 }, { sequence: "\x1B[6;5~", shortcut: "ctrl+pagedown", weight: -1 }, // <ctrl+shift> { sequence: "\x1B[1;6B", shortcut: "ctrl+shift+down" }, { sequence: "\x1B[1;6D", shortcut: "ctrl+shift+left" }, { sequence: "\x1B[1;6C", shortcut: "ctrl+shift+right" }, { sequence: "\x1B[1;6A", shortcut: "ctrl+shift+up" }, // <ctrl+shift+meta> { sequence: "\x1B[1;14B", shortcut: "ctrl+shift+meta+down" }, { sequence: "\x1B[1;14D", shortcut: "ctrl+shift+meta+left" }, { sequence: "\x1B[1;14C", shortcut: "ctrl+shift+meta+right" }, // <fn> { sequence: "\x1B[H", shortcut: "fn+left", name: "home" }, { sequence: "\x1B[F", shortcut: "fn+right", name: "end" }, { sequence: "\x1B[5~", shortcut: "fn+up", name: "pageup" }, { sequence: "\x1B[6~", shortcut: "fn+down", name: "pagedown" }, // <fn+ctrl> { sequence: "\x1B[1;5F", shortcut: "fn+ctrl+right" }, { sequence: "\x1B[1;5H", shortcut: "fn+ctrl+left" },