This repository has been archived by the owner on Nov 24, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkeybind_unix.go
80 lines (66 loc) · 1.73 KB
/
keybind_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// +build !windows
package keybind
import (
"errors"
"syscall"
"unicode/utf8"
"github.com/pkg/term/termios"
)
type Term struct {
orgTerm syscall.Termios
}
// To receive all input, disable canonical mode, input echo and signal.
func Open() *Term {
// Get current terminal parameters
orgTerm := getTerm()
rawTerm := rawModeTerm(orgTerm)
setTerm(rawTerm)
return &Term{
orgTerm: orgTerm,
}
}
// Read one rune or control sequence.
func (t *Term) ReadRune() (rune, error) {
readBuf := make([]byte, 1)
runeBuf := []byte{}
for {
_, err := syscall.Read(syscall.Stdin, readBuf)
if err != nil {
return NUL, err
}
// Send char only when runeBuf is valid utf-8 byte sequence
runeBuf = append(runeBuf, readBuf[0])
if utf8.FullRune(runeBuf) {
ch, _ := utf8.DecodeRune(runeBuf)
return ch, nil
} else if len(runeBuf) > utf8.UTFMax {
return NUL, errors.New("invalid byte sequence as utf-8")
}
}
}
// Reset terminal to canonical mode.
func (t *Term) Close() {
setTerm(t.orgTerm)
}
func getTerm() syscall.Termios {
var term syscall.Termios
if err := termios.Tcgetattr(uintptr(syscall.Stdin), &term); err != nil {
panic(err)
}
return term
}
func setTerm(term syscall.Termios) {
if err := termios.Tcsetattr(uintptr(syscall.Stdin), termios.TCSAFLUSH, &term); err != nil {
panic(err)
}
}
// returns non-canonical mode term for keybind
func rawModeTerm(term syscall.Termios) syscall.Termios {
term.Iflag &= syscall.IGNCR // ignore received CR
term.Lflag ^= syscall.ICANON // disable canonical mode
term.Lflag ^= syscall.ECHO // disable echo of input
term.Lflag ^= syscall.ISIG // disable signal
term.Cc[syscall.VMIN] = 1 // number of bytes to read()
term.Cc[syscall.VTIME] = 0 // timeout of read()
return term
}