From 8e4bd417b9169c9482a55f3faaeef208b5bf7eb4 Mon Sep 17 00:00:00 2001 From: Thomas O'Dowd Date: Fri, 20 May 2022 22:29:21 +0900 Subject: [PATCH] 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". --- terminal.go | 16 ++++++++++++++++ utils.go | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/terminal.go b/terminal.go index 1078631..38413d0 100644 --- a/terminal.go +++ b/terminal.go @@ -125,6 +125,7 @@ func (t *Terminal) ioloop() { var ( isEscape bool isEscapeEx bool + isEscapeSS3 bool expectNextChar bool ) @@ -152,9 +153,15 @@ func (t *Terminal) ioloop() { if isEscape { isEscape = false if r == CharEscapeEx { + // ^][ expectNextChar = true isEscapeEx = true continue + } else if r == CharO { + // ^]O + expectNextChar = true + isEscapeSS3 = true + continue } r = escapeKey(r, buf) } else if isEscapeEx { @@ -177,6 +184,15 @@ func (t *Terminal) ioloop() { expectNextChar = true continue } + } else if isEscapeSS3 { + isEscapeSS3 = false + if key := readEscKey(r, buf); key != nil { + r = escapeSS3Key(key) + } + if r == 0 { + expectNextChar = true + continue + } } expectNextChar = true diff --git a/utils.go b/utils.go index f9bacd2..0706dd4 100644 --- a/utils.go +++ b/utils.go @@ -43,6 +43,7 @@ const ( CharCtrlY = 25 CharCtrlZ = 26 CharEsc = 27 + CharO = 79 CharEscapeEx = 91 CharBackspace = 127 ) @@ -123,6 +124,27 @@ func escapeExKey(key *escapeKeyPair) rune { 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 { attr string typ rune