emit-keypress
Advanced tools
+153
-22
@@ -22,4 +22,9 @@ "use strict"; | ||
| // index.ts | ||
| var emit_keypress_exports = {}; | ||
| __export(emit_keypress_exports, { | ||
| var index_exports = {}; | ||
| __export(index_exports, { | ||
| DISABLE_MOUSE: () => DISABLE_MOUSE, | ||
| DISABLE_PASTE_BRACKET_MODE: () => DISABLE_PASTE_BRACKET_MODE, | ||
| ENABLE_MOUSE: () => ENABLE_MOUSE, | ||
| ENABLE_PASTE_BRACKET_MODE: () => ENABLE_PASTE_BRACKET_MODE, | ||
| MAX_PASTE_BUFFER: () => MAX_PASTE_BUFFER, | ||
| NON_PRINTABLE_CHAR_REGEX: () => NON_PRINTABLE_CHAR_REGEX, | ||
@@ -30,3 +35,3 @@ PRINTABLE_CHAR_REGEX: () => PRINTABLE_CHAR_REGEX, | ||
| cursor: () => cursor, | ||
| default: () => emit_keypress_default, | ||
| default: () => index_default, | ||
| disableMouse: () => disableMouse, | ||
@@ -43,2 +48,3 @@ disablePaste: () => disablePaste, | ||
| isPrintableCharacter: () => isPrintableCharacter, | ||
| isWindows: () => isWindows, | ||
| keycodes: () => keycodes, | ||
@@ -56,4 +62,5 @@ metaKeys: () => metaKeys, | ||
| }); | ||
| module.exports = __toCommonJS(emit_keypress_exports); | ||
| module.exports = __toCommonJS(index_exports); | ||
| var import_node_process = require("process"); | ||
| var import_detect_terminal = require("detect-terminal"); | ||
@@ -66,3 +73,2 @@ // src/emit-keypress.ts | ||
| var kEscape = "\x1B"; | ||
| var kSubstringSearch = Symbol("kSubstringSearch"); | ||
| var kUTF16SurrogateThreshold = 65536; | ||
@@ -85,2 +91,6 @@ function CSI(strings, ...args) { | ||
| 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) { | ||
@@ -147,2 +157,41 @@ if (str.length <= i) { | ||
| 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)) { | ||
@@ -186,2 +235,3 @@ if (match[4]) { | ||
| } | ||
| /* xterm/gnome ESC [ letter (with modifier) */ | ||
| case "[P": | ||
@@ -203,2 +253,3 @@ key.name = "f1"; | ||
| break; | ||
| /* xterm/gnome ESC O letter (without modifier) */ | ||
| case "OP": | ||
@@ -220,2 +271,3 @@ key.name = "f1"; | ||
| break; | ||
| /* xterm/rxvt ESC [ number ~ */ | ||
| case "[11~": | ||
@@ -237,2 +289,3 @@ key.name = "f1"; | ||
| break; | ||
| /* paste bracket mode */ | ||
| case "[200~": | ||
@@ -244,2 +297,3 @@ key.name = "paste-start"; | ||
| break; | ||
| /* from Cygwin and used in libuv */ | ||
| case "[[A": | ||
@@ -265,2 +319,3 @@ key.name = "f1"; | ||
| break; | ||
| /* common */ | ||
| case "[15~": | ||
@@ -298,2 +353,3 @@ key.name = "f5"; | ||
| break; | ||
| /* common */ | ||
| case "[15;10": | ||
@@ -341,2 +397,3 @@ key.name = "f5"; | ||
| break; | ||
| /* xterm ESC [ letter */ | ||
| case "[A": | ||
@@ -363,2 +420,3 @@ key.name = "up"; | ||
| break; | ||
| /* xterm/gnome ESC O letter */ | ||
| case "OA": | ||
@@ -385,2 +443,3 @@ key.name = "up"; | ||
| break; | ||
| /* xterm/rxvt ESC [ number ~ */ | ||
| case "[1~": | ||
@@ -406,2 +465,3 @@ key.name = "home"; | ||
| break; | ||
| /* putty */ | ||
| case "[[5~": | ||
@@ -413,2 +473,3 @@ key.name = "pageup"; | ||
| break; | ||
| /* rxvt */ | ||
| case "[7~": | ||
@@ -420,2 +481,3 @@ key.name = "home"; | ||
| break; | ||
| /* rxvt keys with modifiers */ | ||
| case "[a": | ||
@@ -635,2 +697,3 @@ key.name = "up"; | ||
| break; | ||
| /* misc. */ | ||
| case "[Z": | ||
@@ -689,5 +752,5 @@ key.name = "tab"; | ||
| var { kEscape: kEscape2 } = CSI; | ||
| var KEYPRESS_DECODER = Symbol("keypress-decoder"); | ||
| var ESCAPE_DECODER = Symbol("escape-decoder"); | ||
| var kSawKeyPress = Symbol("saw-key-press"); | ||
| 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; | ||
@@ -1058,6 +1121,6 @@ function emitKeypressEvents(stream, iface = {}) { | ||
| // <fn> | ||
| { sequence: "\x1B[6~", shortcut: "fn+down", name: "end" }, | ||
| { sequence: "\x1B[H", shortcut: "fn+left", name: "home" }, | ||
| { sequence: "\x1B[F", shortcut: "fn+right", name: "pagedown" }, | ||
| { 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> | ||
@@ -1156,2 +1219,50 @@ { sequence: "\x1B[1;5F", shortcut: "fn+ctrl+right" }, | ||
| // src/keyboard-protocol.ts | ||
| var KITTY_PROTOCOL = { | ||
| name: "kitty", | ||
| enable: `${kEscape}[>1u`, | ||
| disable: `${kEscape}[<u` | ||
| }; | ||
| var MOK_PROTOCOL = { | ||
| name: "mok", | ||
| enable: `${kEscape}[>4;1m`, | ||
| disable: `${kEscape}[>4;0m` | ||
| }; | ||
| var KITTY_PROTOCOL_TERMINALS = /* @__PURE__ */ new Set([ | ||
| "kitty", | ||
| "alacritty", | ||
| "foot", | ||
| "ghostty", | ||
| "iterm", | ||
| "rio", | ||
| "wezterm" | ||
| ]); | ||
| var MOK_TERMINALS = /* @__PURE__ */ new Set([ | ||
| "windows_terminal", | ||
| "xterm", | ||
| "gnome_terminal", | ||
| "konsole", | ||
| "vscode", | ||
| "xfce4_terminal", | ||
| "mate_terminal", | ||
| "terminator" | ||
| ]); | ||
| var getKeyboardProtocol = /* @__PURE__ */ __name((terminal) => { | ||
| if (KITTY_PROTOCOL_TERMINALS.has(terminal)) return KITTY_PROTOCOL; | ||
| if (MOK_TERMINALS.has(terminal)) return MOK_PROTOCOL; | ||
| return null; | ||
| }, "getKeyboardProtocol"); | ||
| var resetKeyboardProtocol = /* @__PURE__ */ __name((output) => { | ||
| output.write(KITTY_PROTOCOL.disable); | ||
| output.write(MOK_PROTOCOL.disable); | ||
| }, "resetKeyboardProtocol"); | ||
| var enableKeyboardProtocol = /* @__PURE__ */ __name((terminal, output) => { | ||
| const protocol = getKeyboardProtocol(terminal); | ||
| if (!protocol) return null; | ||
| output.write(protocol.enable); | ||
| return () => { | ||
| output.write(protocol.disable); | ||
| }; | ||
| }, "enableKeyboardProtocol"); | ||
| // src/utils.ts | ||
@@ -1246,2 +1357,5 @@ var PRINTABLE_CHAR_REGEX = /^(?!.*[\uFEFF])[\p{L}\p{N}\p{P}\p{S}\p{Z}\p{M}\u200D\s]+$/u; | ||
| if (keyName === "undefined") keyName = ""; | ||
| if (keyName === "end" || keyName === "home") { | ||
| modifiers.delete("fn"); | ||
| } | ||
| const output = modifiers.size > 0 && keyName ? `${sortModifiers([...modifiers]).join("+")}+${keyName}` : keyName; | ||
@@ -1265,5 +1379,5 @@ return output.length > 1 ? output : ""; | ||
| b.weight ||= 0; | ||
| return a.weight === b.weight ? 0 : a.weight > b.weight ? 1 : -1; | ||
| return a.weight === b.weight ? 0 : b.weight > a.weight ? 1 : -1; | ||
| }); | ||
| return bindings; | ||
| return bindings.filter((b) => b.weight !== -1); | ||
| }, "prioritizeKeymap"); | ||
@@ -1275,9 +1389,8 @@ var isPrintableCharacter = /* @__PURE__ */ __name((s) => { | ||
| // index.ts | ||
| var ESC = "\x1B"; | ||
| var isWindows = globalThis.process.platform === "win32"; | ||
| var MAX_PASTE_BUFFER = 1024 * 1024; | ||
| var ENABLE_PASTE_BRACKET_MODE = `${ESC}[?2004h`; | ||
| var DISABLE_PASTE_BRACKET_MODE = `${ESC}[?2004l`; | ||
| var ENABLE_MOUSE = `${ESC}[?1003h`; | ||
| var DISABLE_MOUSE = `${ESC}[?1003l`; | ||
| var ENABLE_PASTE_BRACKET_MODE = `${kEscape}[?2004h`; | ||
| var DISABLE_PASTE_BRACKET_MODE = `${kEscape}[?2004l`; | ||
| var ENABLE_MOUSE = `${kEscape}[?1003h`; | ||
| var DISABLE_MOUSE = `${kEscape}[?1003l`; | ||
| var enablePaste = /* @__PURE__ */ __name((stdout2) => { | ||
@@ -1297,9 +1410,9 @@ stdout2.write(ENABLE_PASTE_BRACKET_MODE); | ||
| hide: /* @__PURE__ */ __name((stdout2) => { | ||
| stdout2.write(`${ESC}[?25l`); | ||
| stdout2.write(`${kEscape}[?25l`); | ||
| }, "hide"), | ||
| show: /* @__PURE__ */ __name((stdout2) => { | ||
| stdout2.write(`${ESC}[?25h`); | ||
| stdout2.write(`${kEscape}[?25h`); | ||
| }, "show"), | ||
| position: /* @__PURE__ */ __name((stdout2) => { | ||
| stdout2.write(`${ESC}[6n`); | ||
| stdout2.write(`${kEscape}[6n`); | ||
| }, "position") | ||
@@ -1375,3 +1488,4 @@ }; | ||
| enablePasteMode = false, | ||
| pasteModeTimeout = 100 | ||
| pasteModeTimeout = 100, | ||
| keyboardProtocol = false | ||
| }) => { | ||
@@ -1388,2 +1502,3 @@ if (!input || input !== process.stdin && !input.isTTY) { | ||
| let pasteTimeout = null; | ||
| let disableProtocol = null; | ||
| const clearPasteState = /* @__PURE__ */ __name(() => { | ||
@@ -1447,2 +1562,7 @@ pasting = false; | ||
| } | ||
| const found = keymap.filter((k) => k.sequence === key.sequence); | ||
| if (found.length === 1) { | ||
| key = { ...key, ...found[0] }; | ||
| addShortcut = false; | ||
| } | ||
| const shortcut = key.shortcut ? sortShortcutModifier(key.shortcut) : createShortcut(key); | ||
@@ -1487,2 +1607,3 @@ if (!key.shortcut && hasModifier(key)) { | ||
| if (enablePasteMode) disablePaste(output); | ||
| if (disableProtocol) disableProtocol(); | ||
| if (onKeypress) input.off("keypress", handleKeypress); | ||
@@ -1502,2 +1623,6 @@ if (pasteTimeout) clearTimeout(pasteTimeout); | ||
| } | ||
| resetKeyboardProtocol(output); | ||
| if (keyboardProtocol) { | ||
| disableProtocol = enableKeyboardProtocol((0, import_detect_terminal.detectTerminal)(), output); | ||
| } | ||
| if (!isWindows && input.isTTY) input.setRawMode(true); | ||
@@ -1523,5 +1648,10 @@ if (hideCursor) cursor.hide(output); | ||
| var { emitKeypress } = createEmitKeypress(); | ||
| var emit_keypress_default = emitKeypress; | ||
| var index_default = emitKeypress; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| DISABLE_MOUSE, | ||
| DISABLE_PASTE_BRACKET_MODE, | ||
| ENABLE_MOUSE, | ||
| ENABLE_PASTE_BRACKET_MODE, | ||
| MAX_PASTE_BUFFER, | ||
| NON_PRINTABLE_CHAR_REGEX, | ||
@@ -1543,2 +1673,3 @@ PRINTABLE_CHAR_REGEX, | ||
| isPrintableCharacter, | ||
| isWindows, | ||
| keycodes, | ||
@@ -1545,0 +1676,0 @@ metaKeys, |
+147
-22
@@ -5,11 +5,11 @@ var __defProp = Object.defineProperty; | ||
| // index.ts | ||
| import { stdin, stdout } from "node:process"; | ||
| import { stdin, stdout } from "process"; | ||
| import { detectTerminal } from "detect-terminal"; | ||
| // src/emit-keypress.ts | ||
| import { StringDecoder } from "node:string_decoder"; | ||
| import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "node:timers"; | ||
| import { StringDecoder } from "string_decoder"; | ||
| import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "timers"; | ||
| // src/keypress.ts | ||
| var kEscape = "\x1B"; | ||
| var kSubstringSearch = Symbol("kSubstringSearch"); | ||
| var kUTF16SurrogateThreshold = 65536; | ||
@@ -32,2 +32,6 @@ function CSI(strings, ...args) { | ||
| 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) { | ||
@@ -94,2 +98,41 @@ if (str.length <= i) { | ||
| 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)) { | ||
@@ -133,2 +176,3 @@ if (match[4]) { | ||
| } | ||
| /* xterm/gnome ESC [ letter (with modifier) */ | ||
| case "[P": | ||
@@ -150,2 +194,3 @@ key.name = "f1"; | ||
| break; | ||
| /* xterm/gnome ESC O letter (without modifier) */ | ||
| case "OP": | ||
@@ -167,2 +212,3 @@ key.name = "f1"; | ||
| break; | ||
| /* xterm/rxvt ESC [ number ~ */ | ||
| case "[11~": | ||
@@ -184,2 +230,3 @@ key.name = "f1"; | ||
| break; | ||
| /* paste bracket mode */ | ||
| case "[200~": | ||
@@ -191,2 +238,3 @@ key.name = "paste-start"; | ||
| break; | ||
| /* from Cygwin and used in libuv */ | ||
| case "[[A": | ||
@@ -212,2 +260,3 @@ key.name = "f1"; | ||
| break; | ||
| /* common */ | ||
| case "[15~": | ||
@@ -245,2 +294,3 @@ key.name = "f5"; | ||
| break; | ||
| /* common */ | ||
| case "[15;10": | ||
@@ -288,2 +338,3 @@ key.name = "f5"; | ||
| break; | ||
| /* xterm ESC [ letter */ | ||
| case "[A": | ||
@@ -310,2 +361,3 @@ key.name = "up"; | ||
| break; | ||
| /* xterm/gnome ESC O letter */ | ||
| case "OA": | ||
@@ -332,2 +384,3 @@ key.name = "up"; | ||
| break; | ||
| /* xterm/rxvt ESC [ number ~ */ | ||
| case "[1~": | ||
@@ -353,2 +406,3 @@ key.name = "home"; | ||
| break; | ||
| /* putty */ | ||
| case "[[5~": | ||
@@ -360,2 +414,3 @@ key.name = "pageup"; | ||
| break; | ||
| /* rxvt */ | ||
| case "[7~": | ||
@@ -367,2 +422,3 @@ key.name = "home"; | ||
| break; | ||
| /* rxvt keys with modifiers */ | ||
| case "[a": | ||
@@ -582,2 +638,3 @@ key.name = "up"; | ||
| break; | ||
| /* misc. */ | ||
| case "[Z": | ||
@@ -636,5 +693,5 @@ key.name = "tab"; | ||
| var { kEscape: kEscape2 } = CSI; | ||
| var KEYPRESS_DECODER = Symbol("keypress-decoder"); | ||
| var ESCAPE_DECODER = Symbol("escape-decoder"); | ||
| var kSawKeyPress = Symbol("saw-key-press"); | ||
| 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; | ||
@@ -1005,6 +1062,6 @@ function emitKeypressEvents(stream, iface = {}) { | ||
| // <fn> | ||
| { sequence: "\x1B[6~", shortcut: "fn+down", name: "end" }, | ||
| { sequence: "\x1B[H", shortcut: "fn+left", name: "home" }, | ||
| { sequence: "\x1B[F", shortcut: "fn+right", name: "pagedown" }, | ||
| { 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> | ||
@@ -1103,2 +1160,50 @@ { sequence: "\x1B[1;5F", shortcut: "fn+ctrl+right" }, | ||
| // src/keyboard-protocol.ts | ||
| var KITTY_PROTOCOL = { | ||
| name: "kitty", | ||
| enable: `${kEscape}[>1u`, | ||
| disable: `${kEscape}[<u` | ||
| }; | ||
| var MOK_PROTOCOL = { | ||
| name: "mok", | ||
| enable: `${kEscape}[>4;1m`, | ||
| disable: `${kEscape}[>4;0m` | ||
| }; | ||
| var KITTY_PROTOCOL_TERMINALS = /* @__PURE__ */ new Set([ | ||
| "kitty", | ||
| "alacritty", | ||
| "foot", | ||
| "ghostty", | ||
| "iterm", | ||
| "rio", | ||
| "wezterm" | ||
| ]); | ||
| var MOK_TERMINALS = /* @__PURE__ */ new Set([ | ||
| "windows_terminal", | ||
| "xterm", | ||
| "gnome_terminal", | ||
| "konsole", | ||
| "vscode", | ||
| "xfce4_terminal", | ||
| "mate_terminal", | ||
| "terminator" | ||
| ]); | ||
| var getKeyboardProtocol = /* @__PURE__ */ __name((terminal) => { | ||
| if (KITTY_PROTOCOL_TERMINALS.has(terminal)) return KITTY_PROTOCOL; | ||
| if (MOK_TERMINALS.has(terminal)) return MOK_PROTOCOL; | ||
| return null; | ||
| }, "getKeyboardProtocol"); | ||
| var resetKeyboardProtocol = /* @__PURE__ */ __name((output) => { | ||
| output.write(KITTY_PROTOCOL.disable); | ||
| output.write(MOK_PROTOCOL.disable); | ||
| }, "resetKeyboardProtocol"); | ||
| var enableKeyboardProtocol = /* @__PURE__ */ __name((terminal, output) => { | ||
| const protocol = getKeyboardProtocol(terminal); | ||
| if (!protocol) return null; | ||
| output.write(protocol.enable); | ||
| return () => { | ||
| output.write(protocol.disable); | ||
| }; | ||
| }, "enableKeyboardProtocol"); | ||
| // src/utils.ts | ||
@@ -1193,2 +1298,5 @@ var PRINTABLE_CHAR_REGEX = /^(?!.*[\uFEFF])[\p{L}\p{N}\p{P}\p{S}\p{Z}\p{M}\u200D\s]+$/u; | ||
| if (keyName === "undefined") keyName = ""; | ||
| if (keyName === "end" || keyName === "home") { | ||
| modifiers.delete("fn"); | ||
| } | ||
| const output = modifiers.size > 0 && keyName ? `${sortModifiers([...modifiers]).join("+")}+${keyName}` : keyName; | ||
@@ -1212,5 +1320,5 @@ return output.length > 1 ? output : ""; | ||
| b.weight ||= 0; | ||
| return a.weight === b.weight ? 0 : a.weight > b.weight ? 1 : -1; | ||
| return a.weight === b.weight ? 0 : b.weight > a.weight ? 1 : -1; | ||
| }); | ||
| return bindings; | ||
| return bindings.filter((b) => b.weight !== -1); | ||
| }, "prioritizeKeymap"); | ||
@@ -1222,9 +1330,8 @@ var isPrintableCharacter = /* @__PURE__ */ __name((s) => { | ||
| // index.ts | ||
| var ESC = "\x1B"; | ||
| var isWindows = globalThis.process.platform === "win32"; | ||
| var MAX_PASTE_BUFFER = 1024 * 1024; | ||
| var ENABLE_PASTE_BRACKET_MODE = `${ESC}[?2004h`; | ||
| var DISABLE_PASTE_BRACKET_MODE = `${ESC}[?2004l`; | ||
| var ENABLE_MOUSE = `${ESC}[?1003h`; | ||
| var DISABLE_MOUSE = `${ESC}[?1003l`; | ||
| var ENABLE_PASTE_BRACKET_MODE = `${kEscape}[?2004h`; | ||
| var DISABLE_PASTE_BRACKET_MODE = `${kEscape}[?2004l`; | ||
| var ENABLE_MOUSE = `${kEscape}[?1003h`; | ||
| var DISABLE_MOUSE = `${kEscape}[?1003l`; | ||
| var enablePaste = /* @__PURE__ */ __name((stdout2) => { | ||
@@ -1244,9 +1351,9 @@ stdout2.write(ENABLE_PASTE_BRACKET_MODE); | ||
| hide: /* @__PURE__ */ __name((stdout2) => { | ||
| stdout2.write(`${ESC}[?25l`); | ||
| stdout2.write(`${kEscape}[?25l`); | ||
| }, "hide"), | ||
| show: /* @__PURE__ */ __name((stdout2) => { | ||
| stdout2.write(`${ESC}[?25h`); | ||
| stdout2.write(`${kEscape}[?25h`); | ||
| }, "show"), | ||
| position: /* @__PURE__ */ __name((stdout2) => { | ||
| stdout2.write(`${ESC}[6n`); | ||
| stdout2.write(`${kEscape}[6n`); | ||
| }, "position") | ||
@@ -1322,3 +1429,4 @@ }; | ||
| enablePasteMode = false, | ||
| pasteModeTimeout = 100 | ||
| pasteModeTimeout = 100, | ||
| keyboardProtocol = false | ||
| }) => { | ||
@@ -1335,2 +1443,3 @@ if (!input || input !== process.stdin && !input.isTTY) { | ||
| let pasteTimeout = null; | ||
| let disableProtocol = null; | ||
| const clearPasteState = /* @__PURE__ */ __name(() => { | ||
@@ -1394,2 +1503,7 @@ pasting = false; | ||
| } | ||
| const found = keymap.filter((k) => k.sequence === key.sequence); | ||
| if (found.length === 1) { | ||
| key = { ...key, ...found[0] }; | ||
| addShortcut = false; | ||
| } | ||
| const shortcut = key.shortcut ? sortShortcutModifier(key.shortcut) : createShortcut(key); | ||
@@ -1434,2 +1548,3 @@ if (!key.shortcut && hasModifier(key)) { | ||
| if (enablePasteMode) disablePaste(output); | ||
| if (disableProtocol) disableProtocol(); | ||
| if (onKeypress) input.off("keypress", handleKeypress); | ||
@@ -1449,2 +1564,6 @@ if (pasteTimeout) clearTimeout(pasteTimeout); | ||
| } | ||
| resetKeyboardProtocol(output); | ||
| if (keyboardProtocol) { | ||
| disableProtocol = enableKeyboardProtocol(detectTerminal(), output); | ||
| } | ||
| if (!isWindows && input.isTTY) input.setRawMode(true); | ||
@@ -1470,4 +1589,9 @@ if (hideCursor) cursor.hide(output); | ||
| var { emitKeypress } = createEmitKeypress(); | ||
| var emit_keypress_default = emitKeypress; | ||
| var index_default = emitKeypress; | ||
| export { | ||
| DISABLE_MOUSE, | ||
| DISABLE_PASTE_BRACKET_MODE, | ||
| ENABLE_MOUSE, | ||
| ENABLE_PASTE_BRACKET_MODE, | ||
| MAX_PASTE_BUFFER, | ||
| NON_PRINTABLE_CHAR_REGEX, | ||
@@ -1478,3 +1602,3 @@ PRINTABLE_CHAR_REGEX, | ||
| cursor, | ||
| emit_keypress_default as default, | ||
| index_default as default, | ||
| disableMouse, | ||
@@ -1491,2 +1615,3 @@ disablePaste, | ||
| isPrintableCharacter, | ||
| isWindows, | ||
| keycodes, | ||
@@ -1493,0 +1618,0 @@ metaKeys, |
+15
-9
| { | ||
| "name": "emit-keypress", | ||
| "description": "Drop-dead simple keypress event emitter for Node.js. Create powerful CLI applications and experiences with ease.", | ||
| "version": "1.0.1", | ||
| "version": "2.0.0", | ||
| "main": "dist/index.js", | ||
@@ -9,3 +9,6 @@ "module": "dist/index.mjs", | ||
| "author": "Jon Schlinkert (https://github.com/jonschlinkert)", | ||
| "repository": "enquirer/emit-keypress", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/enquirer/emit-keypress.git" | ||
| }, | ||
| "bugs": { | ||
@@ -23,14 +26,17 @@ "url": "https://github.com/enquirer/emit-keypress/issues" | ||
| }, | ||
| "dependencies": { | ||
| "detect-terminal": "^2.0.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "^20.12.7", | ||
| "@typescript-eslint/eslint-plugin": "^7.13.1", | ||
| "@typescript-eslint/parser": "^7.13.1", | ||
| "@types/node": "^24.10.1", | ||
| "@typescript-eslint/eslint-plugin": "^8.48.1", | ||
| "@typescript-eslint/parser": "^8.48.1", | ||
| "ansi-colors": "^4.1.3", | ||
| "esbuild-register": "^3.5.0", | ||
| "esbuild-register": "^3.6.0", | ||
| "eslint": "^8.57.0", | ||
| "gulp-format-md": "^2.0.0", | ||
| "prettier": "^3.5.3", | ||
| "ts-mocha": "^10.0.0", | ||
| "prettier": "^3.7.4", | ||
| "ts-mocha": "^11.1.0", | ||
| "tsconfig-paths": "^4.2.0", | ||
| "tsup": "^8.0.2" | ||
| "tsup": "^8.5.1" | ||
| }, | ||
@@ -37,0 +43,0 @@ "keywords": [ |
+131
-2
@@ -25,3 +25,3 @@ # emit-keypress [](https://www.npmjs.com/package/emit-keypress) [](https://npmjs.org/package/emit-keypress) [](https://npmjs.org/package/emit-keypress) | ||
| It's lightweight, no dependencies, easy to use, and easy to customize. It's designed to be used in a wide range of use-cases, from simple command-line utilities to complex terminal applications. | ||
| It's lightweight with only one dependency for detecting the terminal. It's easy to use, and easy to customize. It's designed to be used in a wide range of use-cases, from simple command-line utilities to complex terminal applications. | ||
@@ -144,2 +144,131 @@ Powerful CLI applications can be built with this module. | ||
| ### onMousepress | ||
| Pass an `onMousepress` function to handle mouse events. When provided, mouse tracking is automatically enabled. | ||
| ```ts | ||
| emitKeypress({ | ||
| onKeypress: (input, key, close) => { | ||
| console.log('key:', key); | ||
| }, | ||
| onMousepress: (mouse, close) => { | ||
| console.log('mouse:', mouse); | ||
| // mouse.x, mouse.y, mouse.button, mouse.action, etc. | ||
| } | ||
| }); | ||
| ``` | ||
| ### Paste Mode | ||
| Enable bracketed paste mode to handle multi-line pastes as a single event. | ||
| ```ts | ||
| emitKeypress({ | ||
| enablePasteMode: true, | ||
| pasteModeTimeout: 100, // timeout in ms | ||
| maxPasteBuffer: 1024 * 1024, // 1MB limit | ||
| onKeypress: (input, key, close) => { | ||
| if (key.name === 'paste') { | ||
| console.log('pasted:', key.sequence); | ||
| } | ||
| } | ||
| }); | ||
| ``` | ||
| ### Enhanced Keyboard Protocol | ||
| Enable the Kitty or modifyOtherKeys keyboard protocol for better key detection in supported terminals. | ||
| ```ts | ||
| emitKeypress({ | ||
| keyboardProtocol: true, | ||
| onKeypress: (input, key, close) => { | ||
| // Enhanced key reporting with better modifier detection | ||
| console.log({ input, key }); | ||
| } | ||
| }); | ||
| ``` | ||
| Supported terminals include: kitty, alacritty, foot, ghostty, iterm, rio, wezterm (Kitty protocol), and windows_terminal, xterm, gnome_terminal, konsole, vscode, xfce4_terminal, mate_terminal, terminator (modifyOtherKeys protocol). | ||
| ### Cursor Control | ||
| Control cursor visibility and get cursor position. | ||
| ```ts | ||
| import { cursor, emitKeypress } from 'emit-keypress'; | ||
| // Hide/show cursor | ||
| cursor.hide(process.stdout); | ||
| cursor.show(process.stdout); | ||
| // Or use the hideCursor option | ||
| emitKeypress({ | ||
| hideCursor: true, | ||
| onKeypress: (input, key, close) => { | ||
| // cursor is automatically shown when close() is called | ||
| } | ||
| }); | ||
| // Get initial cursor position | ||
| emitKeypress({ | ||
| initialPosition: true, | ||
| onKeypress: (input, key, close) => { | ||
| if (key.name === 'position') { | ||
| console.log('cursor at:', key.x, key.y); | ||
| } | ||
| } | ||
| }); | ||
| ``` | ||
| ### Options | ||
| | Option | Type | Default | Description | | ||
| | --- | --- | --- | --- | | ||
| | `input` | `ReadStream` | `process.stdin` | Input stream to listen on | | ||
| | `output` | `WriteStream` | `process.stdout` | Output stream for escape sequences | | ||
| | `keymap` | `Array` | `[]` | Custom key mappings | | ||
| | `onKeypress` | `Function` | required | Keypress event handler | | ||
| | `onMousepress` | `Function` | `undefined` | Mouse event handler (enables mouse tracking) | | ||
| | `onExit` | `Function` | `undefined` | Called when the stream closes | | ||
| | `escapeCodeTimeout` | `number` | `500` | Timeout for escape sequences (ms) | | ||
| | `handleClose` | `boolean` | `true` | Register cleanup on process exit | | ||
| | `hideCursor` | `boolean` | `false` | Hide cursor while listening | | ||
| | `initialPosition` | `boolean` | `false` | Request initial cursor position | | ||
| | `enablePasteMode` | `boolean` | `false` | Enable bracketed paste mode | | ||
| | `pasteModeTimeout` | `number` | `100` | Paste mode timeout (ms) | | ||
| | `maxPasteBuffer` | `number` | `1048576` | Max paste buffer size (bytes) | | ||
| | `keyboardProtocol` | `boolean` | `false` | Enable enhanced keyboard protocol | | ||
| ### createEmitKeypress | ||
| Create an isolated instance with its own exit handlers. | ||
| ```ts | ||
| import { createEmitKeypress } from 'emit-keypress'; | ||
| const { emitKeypress, onExitHandlers } = createEmitKeypress({ | ||
| setupProcessHandlers: true | ||
| }); | ||
| ``` | ||
| ## History | ||
| ### v2.0.0 | ||
| * Added `onMousepress` option for mouse event handling with automatic mouse tracking | ||
| * Added bracketed paste mode support (`enablePasteMode`, `pasteModeTimeout`, `maxPasteBuffer`) | ||
| * Added enhanced keyboard protocol support for Kitty and modifyOtherKeys (`keyboardProtocol` option) | ||
| * Added `createEmitKeypress` factory for creating isolated instances with separate exit handlers | ||
| * Added `cursor` utilities for hiding/showing cursor and getting position | ||
| * Added `initialPosition` option to request cursor position on start | ||
| * Added `hideCursor` option for automatic cursor visibility management | ||
| * Added `onExit` callback option | ||
| * Added CSI u (Kitty) and modifyOtherKeys protocol parsing for better modifier key detection | ||
| * Added `fn` modifier support to key objects | ||
| * Added automatic terminal detection for keyboard protocol selection | ||
| * Added `keycodes` export with comprehensive key sequence mappings | ||
| * Improved exit handler management with WeakMap-based session counting | ||
| * Improved cleanup: protocols are reset, mouse/paste modes disabled on close | ||
| ## About | ||
@@ -193,2 +322,2 @@ | ||
| _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on February 05, 2025._ | ||
| _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on December 10, 2025._ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
328489
22.78%3231
8.53%320
67.54%1
Infinity%6
20%+ Added
+ Added