* Parse input data and return the key identifier if recognized. * * @param data - Raw input data from terminal * @returns Key identifier string (e.g., "ctrl+c") or undefined
(codepoint: number, modifier: number, baseLayoutKey?: number)
| 1210 | * @returns Key identifier string (e.g., "ctrl+c") or undefined |
| 1211 | */ |
| 1212 | function formatParsedKey(codepoint: number, modifier: number, baseLayoutKey?: number): string | undefined { |
| 1213 | const normalizedCodepoint = normalizeKittyFunctionalCodepoint(codepoint); |
| 1214 | const identityCodepoint = normalizeShiftedLetterIdentityCodepoint(normalizedCodepoint, modifier); |
| 1215 | |
| 1216 | // Use base layout key only when codepoint is not a recognized Latin |
| 1217 | // letter (a-z), digit (0-9), or symbol (/, -, [, ;, etc.). For those, |
| 1218 | // the codepoint is authoritative regardless of physical key position. |
| 1219 | // This prevents remapped layouts (Dvorak, Colemak, xremap, etc.) from |
| 1220 | // reporting the wrong key name based on the QWERTY physical position. |
| 1221 | const isLatinLetter = identityCodepoint >= 97 && identityCodepoint <= 122; // a-z |
| 1222 | const isDigit = identityCodepoint >= 48 && identityCodepoint <= 57; // 0-9 |
| 1223 | const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(identityCodepoint)); |
| 1224 | const effectiveCodepoint = |
| 1225 | isLatinLetter || isDigit || isKnownSymbol ? identityCodepoint : (baseLayoutKey ?? identityCodepoint); |
| 1226 | |
| 1227 | let keyName: string | undefined; |
| 1228 | if (effectiveCodepoint === CODEPOINTS.escape) keyName = "escape"; |
| 1229 | else if (effectiveCodepoint === CODEPOINTS.tab) keyName = "tab"; |
| 1230 | else if (effectiveCodepoint === CODEPOINTS.enter || effectiveCodepoint === CODEPOINTS.kpEnter) keyName = "enter"; |
| 1231 | else if (effectiveCodepoint === CODEPOINTS.space) keyName = "space"; |
| 1232 | else if (effectiveCodepoint === CODEPOINTS.backspace) keyName = "backspace"; |
| 1233 | else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.delete) keyName = "delete"; |
| 1234 | else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.insert) keyName = "insert"; |
| 1235 | else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.home) keyName = "home"; |
| 1236 | else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.end) keyName = "end"; |
| 1237 | else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageUp) keyName = "pageUp"; |
| 1238 | else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageDown) keyName = "pageDown"; |
| 1239 | else if (effectiveCodepoint === ARROW_CODEPOINTS.up) keyName = "up"; |
| 1240 | else if (effectiveCodepoint === ARROW_CODEPOINTS.down) keyName = "down"; |
| 1241 | else if (effectiveCodepoint === ARROW_CODEPOINTS.left) keyName = "left"; |
| 1242 | else if (effectiveCodepoint === ARROW_CODEPOINTS.right) keyName = "right"; |
| 1243 | else if (effectiveCodepoint >= 48 && effectiveCodepoint <= 57) keyName = String.fromCharCode(effectiveCodepoint); |
| 1244 | else if (effectiveCodepoint >= 97 && effectiveCodepoint <= 122) keyName = String.fromCharCode(effectiveCodepoint); |
| 1245 | else if (SYMBOL_KEYS.has(String.fromCharCode(effectiveCodepoint))) keyName = String.fromCharCode(effectiveCodepoint); |
| 1246 | |
| 1247 | if (!keyName) return undefined; |
| 1248 | return formatKeyNameWithModifiers(keyName, modifier); |
| 1249 | } |
| 1250 | |
| 1251 | export function parseKey(data: string): string | undefined { |
| 1252 | const kitty = parseKittySequence(data); |
no test coverage detected