Handle keypad mode cursor key escape sequences. (#203)

Normally the terminal uses CSI escape sequences when the UP, DOWN,
LEFT, RIGHT and HOME, END keys are pressed. These look like the
following ESC [ A etc, where ESC [ is the CSI sequence.

xterm and other terminals however can generate an alternative
escape sequence called SS3 if in the application keypad mode.
This sequence is ESC O A etc.

Bash readline understands both modes so nowadays you rarely
see OA being printed when you press the up arrow while the terminal
is using the keypad mode. readline currently does not understand
these sequences.

To test this fix, I used an xterm and put it in keypad mode
using the command "tput smkx". Then I started the readline-demo
and tried using arrow keys. Without this fix, OA is printed when
I press up. With this fix, readline fetches the previous command
as per regular mode. After testing you can escape back to
regular mode using "tput rmkx".
This commit is contained in:
Thomas O'Dowd 2022-05-20 22:29:21 +09:00 committed by GitHub
parent 80e2d1961b
commit 8e4bd417b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 0 deletions

View File

@ -125,6 +125,7 @@ func (t *Terminal) ioloop() {
var ( var (
isEscape bool isEscape bool
isEscapeEx bool isEscapeEx bool
isEscapeSS3 bool
expectNextChar bool expectNextChar bool
) )
@ -152,9 +153,15 @@ func (t *Terminal) ioloop() {
if isEscape { if isEscape {
isEscape = false isEscape = false
if r == CharEscapeEx { if r == CharEscapeEx {
// ^][
expectNextChar = true expectNextChar = true
isEscapeEx = true isEscapeEx = true
continue continue
} else if r == CharO {
// ^]O
expectNextChar = true
isEscapeSS3 = true
continue
} }
r = escapeKey(r, buf) r = escapeKey(r, buf)
} else if isEscapeEx { } else if isEscapeEx {
@ -177,6 +184,15 @@ func (t *Terminal) ioloop() {
expectNextChar = true expectNextChar = true
continue continue
} }
} else if isEscapeSS3 {
isEscapeSS3 = false
if key := readEscKey(r, buf); key != nil {
r = escapeSS3Key(key)
}
if r == 0 {
expectNextChar = true
continue
}
} }
expectNextChar = true expectNextChar = true

View File

@ -43,6 +43,7 @@ const (
CharCtrlY = 25 CharCtrlY = 25
CharCtrlZ = 26 CharCtrlZ = 26
CharEsc = 27 CharEsc = 27
CharO = 79
CharEscapeEx = 91 CharEscapeEx = 91
CharBackspace = 127 CharBackspace = 127
) )
@ -123,6 +124,27 @@ func escapeExKey(key *escapeKeyPair) rune {
return r return r
} }
// translate EscOX SS3 codes for up/down/etc.
func escapeSS3Key(key *escapeKeyPair) rune {
var r rune
switch key.typ {
case 'D':
r = CharBackward
case 'C':
r = CharForward
case 'A':
r = CharPrev
case 'B':
r = CharNext
case 'H':
r = CharLineStart
case 'F':
r = CharLineEnd
default:
}
return r
}
type escapeKeyPair struct { type escapeKeyPair struct {
attr string attr string
typ rune typ rune