slope/termios/termios_nonlinux.go

95 lines
2.3 KiB
Go

// +build !linux,!windows
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 {
return syscall.Termios{} // This should only happen if called from a non-tty
}
return value
}
func setTermios(termios syscall.Termios) {
err := ioctl(fd, setTermiosIoctl, uintptr(unsafe.Pointer(&termios)))
if err != nil {
panic(err)
}
runtime.KeepAlive(termios)
}
// Take input one char at a time, no need to press enter
func SetCharMode() {
SetSaneMode() // Just to make sure we are at a reasonable place first
t := getTermios()
t.Lflag = t.Lflag ^ syscall.ICANON
t.Lflag = t.Lflag ^ syscall.ECHO
setTermios(t)
}
func SetRawMode() {
var t = getTermios()
t.Iflag &^= (syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON)
t.Oflag &^= syscall.OPOST
t.Lflag &^= (syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN)
t.Cflag &^= (syscall.CSIZE | syscall.PARENB)
t.Cflag |= syscall.CS8
t.Cc[syscall.VMIN] = 1
t.Cc[syscall.VTIME] = 0
setTermios(t)
}
// Should function similar to 'reset' from a shell
func SetSaneMode() {
var t = getTermios()
t.Iflag &^= syscall.IGNBRK | syscall.INLCR | syscall.IGNCR | syscall.IXOFF | syscall.IXANY
t.Iflag |= syscall.BRKINT | syscall.ICRNL | syscall.IMAXBEL
t.Oflag |= syscall.OPOST | syscall.ONLCR
t.Oflag &^= syscall.OCRNL | syscall.ONOCR | syscall.ONLRET
t.Cflag |= syscall.CREAD
setTermios(t)
}
func SetCookedMode() {
var t = getTermios()
t.Iflag |= syscall.BRKINT | syscall.IGNPAR | syscall.ISTRIP | syscall.ICRNL | syscall.IXON
t.Oflag |= syscall.OPOST
t.Lflag |= syscall.ISIG | syscall.ICANON | syscall.ECHO
setTermios(t)
}
func Restore() {
setTermios(initial)
}