@@ -16,6 +16,11 @@ import (
1616 "unsafe"
1717)
1818
19+ const (
20+ normalKeypad = '['
21+ applicationKeypad = 'O'
22+ )
23+
1924type 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
6370func (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