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

fix: smkx keypad-transmit mode #367

Merged
merged 7 commits into from
Sep 10, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 53 additions & 38 deletions terminal/runereader_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import (
"unsafe"
)

const (
normalKeypad = '['
applicationKeypad = 'O'
)

type runeReaderState struct {
term syscall.Termios
reader *bufio.Reader
Expand Down Expand Up @@ -60,52 +65,62 @@ func (rr *RuneReader) RestoreTermMode() error {
return nil
}

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

// parse ^[ sequences to look for arrow keys
if r == '\033' {
if rr.state.reader.Buffered() == 0 {
// no more characters so must be `Esc` key
return KeyEscape, 1, nil
}
r, size, err = rr.state.reader.ReadRune()
if err != nil {
return r, size, err
}
if r != '[' {
return r, size, fmt.Errorf("Unexpected Escape Sequence: %q", []rune{'\033', r})
}
r, size, err = rr.state.reader.ReadRune()
if err != nil {
return r, size, err
}
switch r {
case 'D':
return KeyArrowLeft, 1, nil
case 'C':
return KeyArrowRight, 1, nil
case 'A':
return KeyArrowUp, 1, nil
case 'B':
return KeyArrowDown, 1, nil
case 'H': // Home button
return SpecialKeyHome, 1, nil
case 'F': // End button
return SpecialKeyEnd, 1, nil
case '3': // Delete Button
if r != KeyEscape {
return r, size, err
}

if rr.state.reader.Buffered() == 0 {
// no more characters so must be `Esc` key
return KeyEscape, 1, nil
}

r, size, err = rr.state.reader.ReadRune()
if err != nil {
return r, size, err
}

// ESC O ... or ESC [ ...?
if r != normalKeypad && r != applicationKeypad {
return r, size, fmt.Errorf("unexpected escape sequence from terminal: %q", []rune{KeyEscape, r})
}

keypad := r

r, size, err = rr.state.reader.ReadRune()
if err != nil {
return r, size, err
}

switch r {
case 'A': // ESC [ A or ESC O A
return KeyArrowUp, 1, nil
case 'B': // ESC [ B or ESC O B
return KeyArrowDown, 1, nil
case 'C': // ESC [ C or ESC O C
return KeyArrowRight, 1, nil
case 'D': // ESC [ D or ESC O D
return KeyArrowLeft, 1, nil
case 'F': // ESC [ F or ESC O F
return SpecialKeyEnd, 1, nil
case 'H': // ESC [ H or ESC O H
return SpecialKeyHome, 1, nil
case '3': // ESC [ 3
if keypad == normalKeypad {
// discard the following '~' key from buffer
rr.state.reader.Discard(1)
_, _ = rr.state.reader.Discard(1)
return SpecialKeyDelete, 1, nil
default:
// discard the following '~' key from buffer
rr.state.reader.Discard(1)
return IgnoreKey, 1, nil
}
return r, size, fmt.Errorf("Unknown Escape Sequence: %q", []rune{'\033', '[', r})
ldez marked this conversation as resolved.
Show resolved Hide resolved
}
return r, size, err

// discard the following '~' key from buffer
_, _ = rr.state.reader.Discard(1)
return IgnoreKey, 1, nil
}