Gets many keys working on the keyboard
This commit is contained in:
commit
6526578697
|
@ -0,0 +1 @@
|
|||
lines
|
|
@ -0,0 +1,136 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"tildegit.org/sloum/lines/termios"
|
||||
)
|
||||
|
||||
const (
|
||||
UpArrow rune = iota - 20
|
||||
DownArrow
|
||||
LeftArrow
|
||||
RightArrow
|
||||
Delete
|
||||
Home
|
||||
End
|
||||
PrintScreen
|
||||
PageUp
|
||||
PageDown
|
||||
Escape rune = 27
|
||||
NewLine rune = 10
|
||||
CarriageReturn rune = 13
|
||||
BackSpace rune = 127
|
||||
)
|
||||
|
||||
func readKey() (rune, error) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
char, _, err := reader.ReadRune()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
avail := reader.Buffered()
|
||||
if char == Escape && avail > 0 {
|
||||
var b strings.Builder
|
||||
b.WriteRune(27)
|
||||
for ; avail > 0; avail-- {
|
||||
c, _, e := reader.ReadRune()
|
||||
if e != nil {
|
||||
break
|
||||
}
|
||||
b.WriteRune(c)
|
||||
}
|
||||
escSeq := b.String()
|
||||
switch true {
|
||||
case escSeq == "\033[A":
|
||||
char = UpArrow
|
||||
case escSeq == "\033[B":
|
||||
char = DownArrow
|
||||
case escSeq == "\033[C":
|
||||
char = RightArrow
|
||||
case escSeq == "\033[D":
|
||||
char = LeftArrow
|
||||
case escSeq == "\033[5~":
|
||||
char = PageUp
|
||||
case escSeq == "\033[6~":
|
||||
char = PageDown
|
||||
case IsHomeKey(escSeq):
|
||||
char = Home
|
||||
case IsEndKey(escSeq):
|
||||
char = End
|
||||
case escSeq == "\033[3~" || escSeq == "\033[P":
|
||||
char = Delete
|
||||
default:
|
||||
fmt.Printf("Odd sequence: %s\n", escSeq[1:])
|
||||
}
|
||||
}
|
||||
return char, nil
|
||||
}
|
||||
|
||||
func IsHomeKey(seq string) bool {
|
||||
switch seq {
|
||||
case "\033[1~", "\033[7~", "\033[H", "\033OH":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func IsEndKey(seq string) bool {
|
||||
switch seq {
|
||||
case "\033[4~", "\033[8~", "\033[F", "\033OF":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func PrintKey(k rune) {
|
||||
switch true {
|
||||
case k == UpArrow:
|
||||
fmt.Println("UpArrow")
|
||||
case k == DownArrow:
|
||||
fmt.Println("DownArrow")
|
||||
case k == LeftArrow:
|
||||
fmt.Println("LeftArrow")
|
||||
case k == RightArrow:
|
||||
fmt.Println("RightArrow")
|
||||
case k == Escape:
|
||||
fmt.Println("Escape")
|
||||
case k == NewLine:
|
||||
fmt.Println("NewLine")
|
||||
case k == CarriageReturn:
|
||||
fmt.Println("CarriageReturn")
|
||||
case k == Delete:
|
||||
fmt.Println("Delete")
|
||||
case k == Home:
|
||||
fmt.Println("Home")
|
||||
case k == End:
|
||||
fmt.Println("End")
|
||||
case k == BackSpace:
|
||||
fmt.Println("BackSpace")
|
||||
default:
|
||||
fmt.Printf("%c (%d)\n", k, k)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
termios.SetCharMode()
|
||||
|
||||
for {
|
||||
k, e := readKey()
|
||||
if e != nil {
|
||||
fmt.Println(e.Error())
|
||||
continue
|
||||
}
|
||||
PrintKey(k)
|
||||
if k == NewLine || k == CarriageReturn {
|
||||
break
|
||||
}
|
||||
}
|
||||
termios.Restore()
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// +build linux
|
||||
|
||||
package termios
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermiosIoctl = syscall.TCGETS
|
||||
setTermiosIoctl = syscall.TCSETS
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
// +build !linux
|
||||
|
||||
package termios
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermiosIoctl = syscall.TIOCGETA
|
||||
setTermiosIoctl = syscall.TIOCSETAF
|
||||
)
|
|
@ -0,0 +1,77 @@
|
|||
package termios
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type winsize struct {
|
||||
Row uint16
|
||||
Col uint16
|
||||
Xpixel uint16
|
||||
Ypixel uint16
|
||||
}
|
||||
|
||||
var fd = os.Stdin.Fd()
|
||||
var initial = getTermios()
|
||||
|
||||
func ioctl(fd, request, argp uintptr) error {
|
||||
if _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, request, argp); e != 0 {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetWindowSize() (int, int) {
|
||||
var value winsize
|
||||
ioctl(fd, syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&value)))
|
||||
return int(value.Col), int(value.Row)
|
||||
}
|
||||
|
||||
func getTermios() syscall.Termios {
|
||||
var value syscall.Termios
|
||||
err := ioctl(fd, getTermiosIoctl, uintptr(unsafe.Pointer(&value)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func setTermios(termios syscall.Termios) {
|
||||
err := ioctl(fd, setTermiosIoctl, uintptr(unsafe.Pointer(&termios)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
runtime.KeepAlive(termios)
|
||||
}
|
||||
|
||||
func SetCharMode() {
|
||||
t := getTermios()
|
||||
t.Lflag = t.Lflag ^ syscall.ICANON
|
||||
t.Lflag = t.Lflag ^ syscall.ECHO
|
||||
setTermios(t)
|
||||
}
|
||||
|
||||
func SetLineMode() {
|
||||
var t = getTermios()
|
||||
t.Lflag = t.Lflag | (syscall.ICANON | syscall.ECHO)
|
||||
setTermios(t)
|
||||
}
|
||||
|
||||
func SetRawMode() {
|
||||
t := getTermios()
|
||||
t.Lflag = t.Lflag ^ syscall.ICANON
|
||||
t.Lflag = t.Lflag ^ syscall.ECHO
|
||||
t.Oflag = t.Oflag ^ syscall.OPOST
|
||||
t.Iflag = t.Iflag ^ syscall.ICRNL
|
||||
t.Iflag = t.Iflag ^ syscall.IXON
|
||||
t.Cc[syscall.VMIN] = 0
|
||||
t.Cc[syscall.VTIME] = 1
|
||||
setTermios(t)
|
||||
}
|
||||
|
||||
func Restore() {
|
||||
setTermios(initial)
|
||||
}
|
Loading…
Reference in New Issue