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

Commit

Permalink
fix: smkx keypad-transmit mode (#367)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ldez authored Sep 10, 2021
1 parent de54c4a commit 95aedde
Showing 1 changed file with 53 additions and 38 deletions.
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})
}
return r, size, err

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

0 comments on commit 95aedde

Please sign in to comment.