Skip to content
This repository was archived by the owner on Apr 19, 2024. It is now read-only.

Commit 95aedde

Browse files
authored
fix: smkx keypad-transmit mode (#367)
* fix: smkx keypad-transmit mode. * chore: remove unreachable code. * review: split application and normal mode and add links to doc. * review * review: full rewrite * feat: use KeyEscape constant * doc: add method godoc
1 parent de54c4a commit 95aedde

File tree

1 file changed

+53
-38
lines changed

1 file changed

+53
-38
lines changed

terminal/runereader_posix.go

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ import (
1616
"unsafe"
1717
)
1818

19+
const (
20+
normalKeypad = '['
21+
applicationKeypad = 'O'
22+
)
23+
1924
type runeReaderState struct {
2025
term syscall.Termios
2126
reader *bufio.Reader
@@ -60,52 +65,62 @@ func (rr *RuneReader) RestoreTermMode() error {
6065
return nil
6166
}
6267

68+
// ReadRune Parse escape sequences such as ESC [ A for arrow keys.
69+
// See https://vt100.net/docs/vt102-ug/appendixc.html
6370
func (rr *RuneReader) ReadRune() (rune, int, error) {
6471
r, size, err := rr.state.reader.ReadRune()
6572
if err != nil {
6673
return r, size, err
6774
}
6875

69-
// parse ^[ sequences to look for arrow keys
70-
if r == '\033' {
71-
if rr.state.reader.Buffered() == 0 {
72-
// no more characters so must be `Esc` key
73-
return KeyEscape, 1, nil
74-
}
75-
r, size, err = rr.state.reader.ReadRune()
76-
if err != nil {
77-
return r, size, err
78-
}
79-
if r != '[' {
80-
return r, size, fmt.Errorf("Unexpected Escape Sequence: %q", []rune{'\033', r})
81-
}
82-
r, size, err = rr.state.reader.ReadRune()
83-
if err != nil {
84-
return r, size, err
85-
}
86-
switch r {
87-
case 'D':
88-
return KeyArrowLeft, 1, nil
89-
case 'C':
90-
return KeyArrowRight, 1, nil
91-
case 'A':
92-
return KeyArrowUp, 1, nil
93-
case 'B':
94-
return KeyArrowDown, 1, nil
95-
case 'H': // Home button
96-
return SpecialKeyHome, 1, nil
97-
case 'F': // End button
98-
return SpecialKeyEnd, 1, nil
99-
case '3': // Delete Button
76+
if r != KeyEscape {
77+
return r, size, err
78+
}
79+
80+
if rr.state.reader.Buffered() == 0 {
81+
// no more characters so must be `Esc` key
82+
return KeyEscape, 1, nil
83+
}
84+
85+
r, size, err = rr.state.reader.ReadRune()
86+
if err != nil {
87+
return r, size, err
88+
}
89+
90+
// ESC O ... or ESC [ ...?
91+
if r != normalKeypad && r != applicationKeypad {
92+
return r, size, fmt.Errorf("unexpected escape sequence from terminal: %q", []rune{KeyEscape, r})
93+
}
94+
95+
keypad := r
96+
97+
r, size, err = rr.state.reader.ReadRune()
98+
if err != nil {
99+
return r, size, err
100+
}
101+
102+
switch r {
103+
case 'A': // ESC [ A or ESC O A
104+
return KeyArrowUp, 1, nil
105+
case 'B': // ESC [ B or ESC O B
106+
return KeyArrowDown, 1, nil
107+
case 'C': // ESC [ C or ESC O C
108+
return KeyArrowRight, 1, nil
109+
case 'D': // ESC [ D or ESC O D
110+
return KeyArrowLeft, 1, nil
111+
case 'F': // ESC [ F or ESC O F
112+
return SpecialKeyEnd, 1, nil
113+
case 'H': // ESC [ H or ESC O H
114+
return SpecialKeyHome, 1, nil
115+
case '3': // ESC [ 3
116+
if keypad == normalKeypad {
100117
// discard the following '~' key from buffer
101-
rr.state.reader.Discard(1)
118+
_, _ = rr.state.reader.Discard(1)
102119
return SpecialKeyDelete, 1, nil
103-
default:
104-
// discard the following '~' key from buffer
105-
rr.state.reader.Discard(1)
106-
return IgnoreKey, 1, nil
107120
}
108-
return r, size, fmt.Errorf("Unknown Escape Sequence: %q", []rune{'\033', '[', r})
109121
}
110-
return r, size, err
122+
123+
// discard the following '~' key from buffer
124+
_, _ = rr.state.reader.Discard(1)
125+
return IgnoreKey, 1, nil
111126
}

0 commit comments

Comments
 (0)