Key Event Processing Logic
This module contains pure business logic for key event processing, shared between synchronous and asynchronous implementations.
No I/O operations are performed here - only character-to-key mappings.
Types
CtrlKeyResult = object isCtrlKey*: bool keyEvent*: KeyEvent
- Result of Ctrl key mapping
KeyCode = enum Char, Enter, Escape, Backspace, Tab, BackTab, Space, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Home, End, PageUp, PageDown, Insert, Delete, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12
KeyEvent = object code*: KeyCode char*: string modifiers*: set[KeyModifier]
Procs
proc applyModifiers(keyEvent: KeyEvent; modifiers: set[KeyModifier]): KeyEvent {. ...raises: [], tags: [], forbids: [].}
-
Apply modifiers to a key event
Example:
let key = KeyEvent(code: ArrowUp, char: "") let modified = applyModifiers(key, {Ctrl, Shift}) assert modified.modifiers == {Ctrl, Shift}
proc mapArrowKey(ch: char): KeyEvent {....raises: [], tags: [], forbids: [].}
-
Map escape sequence final character to arrow key
ESC [ A/B/C/D -> ArrowUp/Down/Right/Left
Example:
assert mapArrowKey('A').code == ArrowUp assert mapArrowKey('B').code == ArrowDown
proc mapBasicKey(ch: char): KeyEvent {....raises: [], tags: [], forbids: [].}
-
Map basic characters to key events
Handles: Enter, Tab, Space, Backspace, and regular characters
Example:
assert mapBasicKey('\r').code == Enter assert mapBasicKey('\t').code == Tab assert mapBasicKey('a').code == Char
proc mapCtrlLetterKey(ch: char): CtrlKeyResult {....raises: [], tags: [], forbids: [].}
-
Map Ctrl+letter combinations (x01-x1a) to key events
x01-x1a = Ctrl-A to Ctrl-Z, but exclude already-handled keys: x03 = Ctrl-C (Quit), x08 = Ctrl-H (Backspace), x09 = Ctrl-I (Tab) x0a = Ctrl-J (Line Feed), x0d = Ctrl-M (Enter), x1b = Ctrl-[ (Escape)
Example:
let result = mapCtrlLetterKey('\x01') # Ctrl-A assert result.isCtrlKey assert result.keyEvent.char == "a" assert result.keyEvent.modifiers == {Ctrl}
proc mapCtrlNumberKey(ch: char): CtrlKeyResult {....raises: [], tags: [], forbids: [].}
-
Map Ctrl+number and special control characters
Following crossterm's mapping: x00 = Ctrl-Space, x1c = Ctrl-4, x1d = Ctrl-5, x1e = Ctrl-6, x1f = Ctrl-7
Example:
let result = mapCtrlNumberKey('\x00') # Ctrl-Space assert result.isCtrlKey assert result.keyEvent.code == Space
proc mapFunctionKey(sequence: string): KeyEvent {....raises: [], tags: [], forbids: [].}
-
Map multi-digit escape sequences for function keys
Function keys use ESC [ nn ~ format: F1-F4: ESC [ 11~, 12~, 13~, 14~ (alternative to ESC O P/Q/R/S) F5-F12: ESC [ 15~, 17~, 18~, 19~, 20~, 21~, 23~, 24~
Example:
assert mapFunctionKey("11").code == F1 assert mapFunctionKey("15").code == F5
proc mapNumericKeyCode(numChar: char): KeyEvent {....raises: [], tags: [], forbids: [].}
-
Map numeric escape sequences ESC [ n ~
1/4 = Home/End, 2 = Insert, 3 = Delete, 5/6 = PageUp/PageDown
Example:
assert mapNumericKeyCode('1').code == Home assert mapNumericKeyCode('2').code == Insert
proc mapVT100FunctionKey(ch: char): KeyEvent {....raises: [], tags: [], forbids: [].}
-
Map VT100-style function keys ESC O P/Q/R/S
This is the older format for F1-F4: P = F1, Q = F2, R = F3, S = F4
Example:
assert mapVT100FunctionKey('P').code == F1 assert mapVT100FunctionKey('Q').code == F2
proc parseModifierCode(modChar: char): set[KeyModifier] {....raises: [], tags: [], forbids: [].}
-
Parse modifier code from escape sequence
Modifier encoding (1-based, subtract 1 for bit flags): 1=None, 2=Shift, 3=Alt, 4=Shift+Alt, 5=Ctrl, 6=Ctrl+Shift, 7=Ctrl+Alt, 8=Ctrl+Shift+Alt
Example:
assert parseModifierCode('2') == {Shift} assert parseModifierCode('5') == {Ctrl} assert parseModifierCode('8') == {Ctrl, Shift, Alt}