Catch the alt key modifier

This commit is contained in:
Christian Rocha 2020-02-19 18:35:34 -05:00
parent f88269fb22
commit eefa9c7aa3
No known key found for this signature in database
GPG Key ID: D6CC7A16E5878018
1 changed files with 35 additions and 27 deletions

54
key.go
View File

@ -11,11 +11,16 @@ import (
type KeyMsg Key
// String returns a friendly name for a key
func (k *KeyMsg) String() string {
func (k *KeyMsg) String() (str string) {
if k.Alt {
str += "alt+"
}
if k.Type == KeyRune {
return string(k.Rune)
str += string(k.Rune)
return str
} else if s, ok := keyNames[int(k.Type)]; ok {
return s
str += s
return str
}
return ""
}
@ -29,6 +34,7 @@ func (k *KeyMsg) IsRune() bool {
type Key struct {
Type KeyType
Rune rune
Alt bool
}
// KeyType indicates the key pressed
@ -183,7 +189,6 @@ var sequences = map[string]KeyType{
"\x1b[B": KeyDown,
"\x1b[C": KeyRight,
"\x1b[D": KeyLeft,
"\x1b5B5A": KeyShiftTab,
}
// ReadKey reads keypress input from a TTY and returns a string representation
@ -192,41 +197,44 @@ func ReadKey(r io.Reader) (Key, error) {
var buf [256]byte
// Read and block
n, err := r.Read(buf[:])
numBytes, err := r.Read(buf[:])
if err != nil {
return Key{}, err
}
// Hex representation of input sequence
hex := fmt.Sprintf("%x", buf[:n])
switch hex {
case "1b5b5a":
// Shift+tab needs some very special handling
if "1b5b5a" == fmt.Sprintf("%x", buf[:numBytes]) {
return Key{Type: KeyShiftTab}, nil
}
// Get rune
c, _ := utf8.DecodeRune(buf[:])
if c == utf8.RuneError {
return Key{}, errors.New("no such rune")
// Get unicode value
char, _ := utf8.DecodeRune(buf[:])
if char == utf8.RuneError {
return Key{}, errors.New("could not decode rune")
}
// Is it a control character?
if n == 1 && c <= keyUS || c == keyDEL {
return Key{Type: KeyType(c)}, nil
if numBytes == 1 && char <= keyUS || char == keyDEL {
return Key{Type: KeyType(char)}, nil
}
// Is it a special sequence, like an arrow key?
if k, ok := sequences[string(buf[:n])]; ok {
if k, ok := sequences[string(buf[:numBytes])]; ok {
return Key{Type: k}, nil
}
// If the first byte is an escape sequence, and we're still here, just
// send a null to avoid sending bizarre escape sequences down the line
if n > 0 && buf[0] == 0x1b {
return Key{Type: KeyNull}, nil
// Is the alt key pressed? The buffer will be prefixed with an escape
// sequence if so
if numBytes > 1 && buf[0] == 0x1b {
// Now remove the initial escape sequence and re-process to get the
// character.
c, _ := utf8.DecodeRune(buf[1:])
if c == utf8.RuneError {
return Key{}, errors.New("could not decode rune after removing initial escape")
}
return Key{Alt: true, Type: KeyRune, Rune: c}, nil
}
// Nope, just a regular, ol' rune
return Key{Type: KeyRune, Rune: c}, nil
// Just a regular, ol' rune
return Key{Type: KeyRune, Rune: char}, nil
}