v0.1.0 initial commit
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
package terminal
|
||||
|
||||
// Key represents a parsed input key
|
||||
type Key uint16
|
||||
|
||||
// Key constants - designed for expansion
|
||||
const (
|
||||
KeyNone Key = iota
|
||||
KeyRune // Printable character (check Event.Rune)
|
||||
|
||||
// Control keys
|
||||
KeyEscape
|
||||
KeyEnter
|
||||
KeyTab
|
||||
KeyBacktab // Shift+Tab
|
||||
KeyShiftTab // Same as KeyBacktab,for clarity
|
||||
KeyBackspace
|
||||
KeyDelete
|
||||
KeySpace
|
||||
|
||||
// Navigation
|
||||
KeyUp
|
||||
KeyDown
|
||||
KeyLeft
|
||||
KeyRight
|
||||
KeyHome
|
||||
KeyEnd
|
||||
KeyPageUp
|
||||
KeyPageDown
|
||||
KeyInsert
|
||||
|
||||
// Function keys
|
||||
KeyF1
|
||||
KeyF2
|
||||
KeyF3
|
||||
KeyF4
|
||||
KeyF5
|
||||
KeyF6
|
||||
KeyF7
|
||||
KeyF8
|
||||
KeyF9
|
||||
KeyF10
|
||||
KeyF11
|
||||
KeyF12
|
||||
|
||||
// Ctrl+letter (Ctrl+A = 0x01, Ctrl+Z = 0x1A)
|
||||
KeyCtrlA
|
||||
KeyCtrlB
|
||||
KeyCtrlC
|
||||
KeyCtrlD
|
||||
KeyCtrlE
|
||||
KeyCtrlF
|
||||
KeyCtrlG
|
||||
KeyCtrlH // Often same as Backspace
|
||||
KeyCtrlI // Often same as Tab
|
||||
KeyCtrlJ // Often same as Enter
|
||||
KeyCtrlK
|
||||
KeyCtrlL
|
||||
KeyCtrlM // Often same as Enter
|
||||
KeyCtrlN
|
||||
KeyCtrlO
|
||||
KeyCtrlP
|
||||
KeyCtrlQ
|
||||
KeyCtrlR
|
||||
KeyCtrlS
|
||||
KeyCtrlT
|
||||
KeyCtrlU
|
||||
KeyCtrlV
|
||||
KeyCtrlW
|
||||
KeyCtrlX
|
||||
KeyCtrlY
|
||||
KeyCtrlZ
|
||||
|
||||
// Ctrl+special
|
||||
KeyCtrlSpace // Ctrl+@ / Ctrl+Space (Ctrl+@ produces NUL byte 0x00)
|
||||
KeyCtrlBackslash
|
||||
KeyCtrlBracketLeft
|
||||
KeyCtrlBracketRight
|
||||
KeyCtrlCaret
|
||||
KeyCtrlUnderscore
|
||||
)
|
||||
|
||||
// Modifier flags
|
||||
type Modifier uint8
|
||||
|
||||
const (
|
||||
ModNone Modifier = 0
|
||||
ModShift Modifier = 1 << 0
|
||||
ModAlt Modifier = 1 << 1
|
||||
ModCtrl Modifier = 1 << 2
|
||||
)
|
||||
|
||||
// escapeSequence maps escape sequences to keys
|
||||
// Key: sequence after ESC [ (e.g., "A" for up arrow)
|
||||
type escapeSequence struct {
|
||||
seq string
|
||||
key Key
|
||||
mod Modifier
|
||||
}
|
||||
|
||||
// Known escape sequences (CSI sequences: ESC [ ...)
|
||||
var csiSequences = []escapeSequence{
|
||||
// Arrow keys
|
||||
{"A", KeyUp, ModNone},
|
||||
{"B", KeyDown, ModNone},
|
||||
{"C", KeyRight, ModNone},
|
||||
{"D", KeyLeft, ModNone},
|
||||
{"Z", KeyBacktab, ModShift}, // Shift+Tab
|
||||
|
||||
// Arrow keys with modifiers (xterm style: ESC [ 1 ; mod X)
|
||||
{"1;2A", KeyUp, ModShift},
|
||||
{"1;2B", KeyDown, ModShift},
|
||||
{"1;2C", KeyRight, ModShift},
|
||||
{"1;2D", KeyLeft, ModShift},
|
||||
{"1;3A", KeyUp, ModAlt},
|
||||
{"1;3B", KeyDown, ModAlt},
|
||||
{"1;3C", KeyRight, ModAlt},
|
||||
{"1;3D", KeyLeft, ModAlt},
|
||||
{"1;5A", KeyUp, ModCtrl},
|
||||
{"1;5B", KeyDown, ModCtrl},
|
||||
{"1;5C", KeyRight, ModCtrl},
|
||||
{"1;5D", KeyLeft, ModCtrl},
|
||||
|
||||
// Navigation
|
||||
{"H", KeyHome, ModNone},
|
||||
{"F", KeyEnd, ModNone},
|
||||
{"1~", KeyHome, ModNone},
|
||||
{"4~", KeyEnd, ModNone},
|
||||
{"5~", KeyPageUp, ModNone},
|
||||
{"6~", KeyPageDown, ModNone},
|
||||
{"2~", KeyInsert, ModNone},
|
||||
{"3~", KeyDelete, ModNone},
|
||||
{"7~", KeyHome, ModNone},
|
||||
{"8~", KeyEnd, ModNone},
|
||||
|
||||
// Function keys (xterm)
|
||||
{"11~", KeyF1, ModNone},
|
||||
{"12~", KeyF2, ModNone},
|
||||
{"13~", KeyF3, ModNone},
|
||||
{"14~", KeyF4, ModNone},
|
||||
{"15~", KeyF5, ModNone},
|
||||
{"17~", KeyF6, ModNone},
|
||||
{"18~", KeyF7, ModNone},
|
||||
{"19~", KeyF8, ModNone},
|
||||
{"20~", KeyF9, ModNone},
|
||||
{"21~", KeyF10, ModNone},
|
||||
{"23~", KeyF11, ModNone},
|
||||
{"24~", KeyF12, ModNone},
|
||||
|
||||
// Function keys (vt style)
|
||||
{"[A", KeyF1, ModNone},
|
||||
{"[B", KeyF2, ModNone},
|
||||
{"[C", KeyF3, ModNone},
|
||||
{"[D", KeyF4, ModNone},
|
||||
{"[E", KeyF5, ModNone},
|
||||
|
||||
// Shift+Navigation (mod=2)
|
||||
{"1;2H", KeyHome, ModShift},
|
||||
{"1;2F", KeyEnd, ModShift},
|
||||
{"2;2~", KeyInsert, ModShift},
|
||||
{"3;2~", KeyDelete, ModShift},
|
||||
{"5;2~", KeyPageUp, ModShift},
|
||||
{"6;2~", KeyPageDown, ModShift},
|
||||
|
||||
// Alt+Arrows (mod=3) - already have 1;3A-D
|
||||
// Alt+Navigation (mod=3)
|
||||
{"1;3H", KeyHome, ModAlt},
|
||||
{"1;3F", KeyEnd, ModAlt},
|
||||
{"2;3~", KeyInsert, ModAlt},
|
||||
{"3;3~", KeyDelete, ModAlt},
|
||||
{"5;3~", KeyPageUp, ModAlt},
|
||||
{"6;3~", KeyPageDown, ModAlt},
|
||||
|
||||
// Shift+Alt (mod=4)
|
||||
{"1;4A", KeyUp, ModShift | ModAlt},
|
||||
{"1;4B", KeyDown, ModShift | ModAlt},
|
||||
{"1;4C", KeyRight, ModShift | ModAlt},
|
||||
{"1;4D", KeyLeft, ModShift | ModAlt},
|
||||
{"1;4H", KeyHome, ModShift | ModAlt},
|
||||
{"1;4F", KeyEnd, ModShift | ModAlt},
|
||||
{"2;4~", KeyInsert, ModShift | ModAlt},
|
||||
{"3;4~", KeyDelete, ModShift | ModAlt},
|
||||
{"5;4~", KeyPageUp, ModShift | ModAlt},
|
||||
{"6;4~", KeyPageDown, ModShift | ModAlt},
|
||||
|
||||
// Ctrl+Arrows (mod=5) - already have 1;5A-D
|
||||
// Ctrl+Navigation (mod=5)
|
||||
{"1;5H", KeyHome, ModCtrl},
|
||||
{"1;5F", KeyEnd, ModCtrl},
|
||||
{"2;5~", KeyInsert, ModCtrl},
|
||||
{"3;5~", KeyDelete, ModCtrl},
|
||||
{"5;5~", KeyPageUp, ModCtrl},
|
||||
{"6;5~", KeyPageDown, ModCtrl},
|
||||
|
||||
// Shift+Ctrl (mod=6)
|
||||
{"1;6A", KeyUp, ModShift | ModCtrl},
|
||||
{"1;6B", KeyDown, ModShift | ModCtrl},
|
||||
{"1;6C", KeyRight, ModShift | ModCtrl},
|
||||
{"1;6D", KeyLeft, ModShift | ModCtrl},
|
||||
{"1;6H", KeyHome, ModShift | ModCtrl},
|
||||
{"1;6F", KeyEnd, ModShift | ModCtrl},
|
||||
{"2;6~", KeyInsert, ModShift | ModCtrl},
|
||||
{"3;6~", KeyDelete, ModShift | ModCtrl},
|
||||
{"5;6~", KeyPageUp, ModShift | ModCtrl},
|
||||
{"6;6~", KeyPageDown, ModShift | ModCtrl},
|
||||
|
||||
// Alt+Ctrl (mod=7)
|
||||
{"1;7A", KeyUp, ModAlt | ModCtrl},
|
||||
{"1;7B", KeyDown, ModAlt | ModCtrl},
|
||||
{"1;7C", KeyRight, ModAlt | ModCtrl},
|
||||
{"1;7D", KeyLeft, ModAlt | ModCtrl},
|
||||
{"1;7H", KeyHome, ModAlt | ModCtrl},
|
||||
{"1;7F", KeyEnd, ModAlt | ModCtrl},
|
||||
{"2;7~", KeyInsert, ModAlt | ModCtrl},
|
||||
{"3;7~", KeyDelete, ModAlt | ModCtrl},
|
||||
{"5;7~", KeyPageUp, ModAlt | ModCtrl},
|
||||
{"6;7~", KeyPageDown, ModAlt | ModCtrl},
|
||||
|
||||
// Shift+Alt+Ctrl (mod=8)
|
||||
{"1;8A", KeyUp, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8B", KeyDown, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8C", KeyRight, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8D", KeyLeft, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8H", KeyHome, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8F", KeyEnd, ModShift | ModAlt | ModCtrl},
|
||||
{"2;8~", KeyInsert, ModShift | ModAlt | ModCtrl},
|
||||
{"3;8~", KeyDelete, ModShift | ModAlt | ModCtrl},
|
||||
{"5;8~", KeyPageUp, ModShift | ModAlt | ModCtrl},
|
||||
{"6;8~", KeyPageDown, ModShift | ModAlt | ModCtrl},
|
||||
|
||||
// F-keys with modifiers (CSI style: ESC [ 1 ; mod P/Q/R/S for F1-F4)
|
||||
// F1-F4 with Shift (mod=2)
|
||||
{"1;2P", KeyF1, ModShift},
|
||||
{"1;2Q", KeyF2, ModShift},
|
||||
{"1;2R", KeyF3, ModShift},
|
||||
{"1;2S", KeyF4, ModShift},
|
||||
// F1-F4 with Alt (mod=3)
|
||||
{"1;3P", KeyF1, ModAlt},
|
||||
{"1;3Q", KeyF2, ModAlt},
|
||||
{"1;3R", KeyF3, ModAlt},
|
||||
{"1;3S", KeyF4, ModAlt},
|
||||
// F1-F4 with Ctrl (mod=5)
|
||||
{"1;5P", KeyF1, ModCtrl},
|
||||
{"1;5Q", KeyF2, ModCtrl},
|
||||
{"1;5R", KeyF3, ModCtrl},
|
||||
{"1;5S", KeyF4, ModCtrl},
|
||||
// F1-F4 with Shift+Alt (mod=4)
|
||||
{"1;4P", KeyF1, ModShift | ModAlt},
|
||||
{"1;4Q", KeyF2, ModShift | ModAlt},
|
||||
{"1;4R", KeyF3, ModShift | ModAlt},
|
||||
{"1;4S", KeyF4, ModShift | ModAlt},
|
||||
// F1-F4 with Shift+Ctrl (mod=6)
|
||||
{"1;6P", KeyF1, ModShift | ModCtrl},
|
||||
{"1;6Q", KeyF2, ModShift | ModCtrl},
|
||||
{"1;6R", KeyF3, ModShift | ModCtrl},
|
||||
{"1;6S", KeyF4, ModShift | ModCtrl},
|
||||
// F1-F4 with Alt+Ctrl (mod=7)
|
||||
{"1;7P", KeyF1, ModAlt | ModCtrl},
|
||||
{"1;7Q", KeyF2, ModAlt | ModCtrl},
|
||||
{"1;7R", KeyF3, ModAlt | ModCtrl},
|
||||
{"1;7S", KeyF4, ModAlt | ModCtrl},
|
||||
// F1-F4 with Shift+Alt+Ctrl (mod=8)
|
||||
{"1;8P", KeyF1, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8Q", KeyF2, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8R", KeyF3, ModShift | ModAlt | ModCtrl},
|
||||
{"1;8S", KeyF4, ModShift | ModAlt | ModCtrl},
|
||||
|
||||
// F5-F12 with modifiers (ESC [ N ; mod ~)
|
||||
// F5 (15~)
|
||||
{"15;2~", KeyF5, ModShift},
|
||||
{"15;3~", KeyF5, ModAlt},
|
||||
{"15;4~", KeyF5, ModShift | ModAlt},
|
||||
{"15;5~", KeyF5, ModCtrl},
|
||||
{"15;6~", KeyF5, ModShift | ModCtrl},
|
||||
{"15;7~", KeyF5, ModAlt | ModCtrl},
|
||||
{"15;8~", KeyF5, ModShift | ModAlt | ModCtrl},
|
||||
// F6 (17~)
|
||||
{"17;2~", KeyF6, ModShift},
|
||||
{"17;3~", KeyF6, ModAlt},
|
||||
{"17;4~", KeyF6, ModShift | ModAlt},
|
||||
{"17;5~", KeyF6, ModCtrl},
|
||||
{"17;6~", KeyF6, ModShift | ModCtrl},
|
||||
{"17;7~", KeyF6, ModAlt | ModCtrl},
|
||||
{"17;8~", KeyF6, ModShift | ModAlt | ModCtrl},
|
||||
// F7 (18~)
|
||||
{"18;2~", KeyF7, ModShift},
|
||||
{"18;3~", KeyF7, ModAlt},
|
||||
{"18;4~", KeyF7, ModShift | ModAlt},
|
||||
{"18;5~", KeyF7, ModCtrl},
|
||||
{"18;6~", KeyF7, ModShift | ModCtrl},
|
||||
{"18;7~", KeyF7, ModAlt | ModCtrl},
|
||||
{"18;8~", KeyF7, ModShift | ModAlt | ModCtrl},
|
||||
// F8 (19~)
|
||||
{"19;2~", KeyF8, ModShift},
|
||||
{"19;3~", KeyF8, ModAlt},
|
||||
{"19;4~", KeyF8, ModShift | ModAlt},
|
||||
{"19;5~", KeyF8, ModCtrl},
|
||||
{"19;6~", KeyF8, ModShift | ModCtrl},
|
||||
{"19;7~", KeyF8, ModAlt | ModCtrl},
|
||||
{"19;8~", KeyF8, ModShift | ModAlt | ModCtrl},
|
||||
// F9 (20~)
|
||||
{"20;2~", KeyF9, ModShift},
|
||||
{"20;3~", KeyF9, ModAlt},
|
||||
{"20;4~", KeyF9, ModShift | ModAlt},
|
||||
{"20;5~", KeyF9, ModCtrl},
|
||||
{"20;6~", KeyF9, ModShift | ModCtrl},
|
||||
{"20;7~", KeyF9, ModAlt | ModCtrl},
|
||||
{"20;8~", KeyF9, ModShift | ModAlt | ModCtrl},
|
||||
// F10 (21~)
|
||||
{"21;2~", KeyF10, ModShift},
|
||||
{"21;3~", KeyF10, ModAlt},
|
||||
{"21;4~", KeyF10, ModShift | ModAlt},
|
||||
{"21;5~", KeyF10, ModCtrl},
|
||||
{"21;6~", KeyF10, ModShift | ModCtrl},
|
||||
{"21;7~", KeyF10, ModAlt | ModCtrl},
|
||||
{"21;8~", KeyF10, ModShift | ModAlt | ModCtrl},
|
||||
// F11 (23~)
|
||||
{"23;2~", KeyF11, ModShift},
|
||||
{"23;3~", KeyF11, ModAlt},
|
||||
{"23;4~", KeyF11, ModShift | ModAlt},
|
||||
{"23;5~", KeyF11, ModCtrl},
|
||||
{"23;6~", KeyF11, ModShift | ModCtrl},
|
||||
{"23;7~", KeyF11, ModAlt | ModCtrl},
|
||||
{"23;8~", KeyF11, ModShift | ModAlt | ModCtrl},
|
||||
// F12 (24~)
|
||||
{"24;2~", KeyF12, ModShift},
|
||||
{"24;3~", KeyF12, ModAlt},
|
||||
{"24;4~", KeyF12, ModShift | ModAlt},
|
||||
{"24;5~", KeyF12, ModCtrl},
|
||||
{"24;6~", KeyF12, ModShift | ModCtrl},
|
||||
{"24;7~", KeyF12, ModAlt | ModCtrl},
|
||||
{"24;8~", KeyF12, ModShift | ModAlt | ModCtrl},
|
||||
}
|
||||
|
||||
// SS3 sequences (ESC O ...)
|
||||
var ss3Sequences = []escapeSequence{
|
||||
{"A", KeyUp, ModNone},
|
||||
{"B", KeyDown, ModNone},
|
||||
{"C", KeyRight, ModNone},
|
||||
{"D", KeyLeft, ModNone},
|
||||
{"H", KeyHome, ModNone},
|
||||
{"F", KeyEnd, ModNone},
|
||||
{"P", KeyF1, ModNone},
|
||||
{"Q", KeyF2, ModNone},
|
||||
{"R", KeyF3, ModNone},
|
||||
{"S", KeyF4, ModNone},
|
||||
|
||||
// Numeric Keypad (Application Mode)
|
||||
{"M", KeyEnter, ModNone}, // Keypad Enter
|
||||
{"X", KeyRune, ModNone}, // Keypad = (some terminals)
|
||||
{"j", KeyRune, ModNone}, // Keypad *
|
||||
{"k", KeyRune, ModNone}, // Keypad +
|
||||
{"l", KeyRune, ModNone}, // Keypad ,
|
||||
{"m", KeyRune, ModNone}, // Keypad -
|
||||
{"n", KeyRune, ModNone}, // Keypad .
|
||||
{"o", KeyRune, ModNone}, // Keypad /
|
||||
{"p", KeyRune, ModNone}, // Keypad 0
|
||||
{"q", KeyRune, ModNone}, // Keypad 1
|
||||
{"r", KeyRune, ModNone}, // Keypad 2
|
||||
{"s", KeyRune, ModNone}, // Keypad 3
|
||||
{"t", KeyRune, ModNone}, // Keypad 4
|
||||
{"u", KeyRune, ModNone}, // Keypad 5
|
||||
{"v", KeyRune, ModNone}, // Keypad 6
|
||||
{"w", KeyRune, ModNone}, // Keypad 7
|
||||
{"x", KeyRune, ModNone}, // Keypad 8
|
||||
{"y", KeyRune, ModNone}, // Keypad 9
|
||||
}
|
||||
|
||||
var csiMap = buildSequenceMap(csiSequences)
|
||||
var ss3Map = buildSequenceMap(ss3Sequences)
|
||||
|
||||
func buildSequenceMap(seqs []escapeSequence) map[string]escapeSequence {
|
||||
m := make(map[string]escapeSequence, len(seqs))
|
||||
for _, s := range seqs {
|
||||
m[s.seq] = s
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// lookupCSI performs zero-alloc map lookup via compiler optimization
|
||||
// The string([]byte) conversion inline in map access does not allocate
|
||||
func lookupCSI(seq []byte) (Key, Modifier, bool) {
|
||||
if s, ok := csiMap[string(seq)]; ok {
|
||||
return s.key, s.mod, true
|
||||
}
|
||||
return KeyNone, ModNone, false
|
||||
}
|
||||
|
||||
// lookupSS3 performs zero-alloc map lookup
|
||||
func lookupSS3(seq []byte) (Key, Modifier, bool) {
|
||||
if s, ok := ss3Map[string(seq)]; ok {
|
||||
return s.key, s.mod, true
|
||||
}
|
||||
return KeyNone, ModNone, false
|
||||
}
|
||||
Reference in New Issue
Block a user