diff --git a/decoder.go b/decoder.go index 9c45b47..f32833d 100644 --- a/decoder.go +++ b/decoder.go @@ -316,6 +316,19 @@ func (p *EventDecoder) parseCsi(b []byte) (int, Event) { i++ } + // Linux console function keys F1-F5 are historically sent as + // ESC [ [ A through ESC [ [ E. The second '[' is not a valid CSI + // parameter, intermediate, or prefix byte, so no other sequence uses + // this form. Handle it explicitly before the normal CSI parsing. + if i < len(b) && b[i] == '[' { + if i+1 < len(b) { + if c := b[i+1]; c >= 'A' && c <= 'E' { + return i + 2, KeyPressEvent{Code: KeyF1 + rune(c-'A')} + } + } + return i + 1, UnknownCsiEvent(b[:i+1]) + } + // Initial CSI byte if i < len(b) && b[i] >= '<' && b[i] <= '?' { cmd |= ansi.Cmd(b[i]) << parser.PrefixShift diff --git a/key_test.go b/key_test.go index 3035b1b..89047ad 100644 --- a/key_test.go +++ b/key_test.go @@ -93,6 +93,27 @@ func buildBaseSeqTests() []seqTest { KeyPressEvent{Code: KeySpace, Mod: ModAlt}, }, }, + // Linux console function keys F1-F5 (ESC [ [ A .. ESC [ [ E). + seqTest{ + []byte("\x1b[[A"), + []Event{KeyPressEvent{Code: KeyF1}}, + }, + seqTest{ + []byte("\x1b[[B"), + []Event{KeyPressEvent{Code: KeyF2}}, + }, + seqTest{ + []byte("\x1b[[C"), + []Event{KeyPressEvent{Code: KeyF3}}, + }, + seqTest{ + []byte("\x1b[[D"), + []Event{KeyPressEvent{Code: KeyF4}}, + }, + seqTest{ + []byte("\x1b[[E"), + []Event{KeyPressEvent{Code: KeyF5}}, + }, ) return td }