Created
March 3, 2016 19:30
-
-
Save zellyn/14935c93efc64e4d4162 to your computer and use it in GitHub Desktop.
evil keypress
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I cobbled together a (unix-specific, syscall-using) solution based on the | |
stack overflow answer to the same question in python, and a previous post | |
on this list. References inline. | |
Note: this seems to work, but I haven't taken the time to really understand | |
what I'm doing, and I welcome any suggestions or fixes. | |
// https://groups.google.com/d/msg/golang-nuts/8o9fxPaeFu8/uSFYfobL5EgJ | |
// http://go.pastie.org/813153 | |
func getTermios() (result syscall.Termios, err error) { | |
r1, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), | |
syscall.TCGETS, uintptr(unsafe.Pointer(&result))) | |
if errno != 0 { | |
return result, os.NewSyscallError("SYS_IOCTL", errno) | |
} | |
if r1 != 0 { | |
return result, fmt.Errorf("Error: expected first syscall result to be 0, | |
got %d", r1) | |
} | |
return result, nil | |
} | |
func setTermios(t syscall.Termios) error { | |
r1, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), | |
syscall.TCSETS, uintptr(unsafe.Pointer(&t))) | |
if errno != 0 { | |
return os.NewSyscallError("SYS_IOCTL", errno) | |
} | |
if r1 != 0 { | |
return fmt.Errorf("Error: expected first syscall result to be 0, got %d", | |
r1) | |
} | |
return nil | |
} | |
func getFileStatusFlags() (int32, error) { | |
r1, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(syscall.Stdin), | |
syscall.F_GETFL, 0) | |
if errno != 0 { | |
return 0, os.NewSyscallError("SYS_FCNTL", errno) | |
} | |
r := int32(r1) | |
if r < 0 { | |
return 0, fmt.Errorf("Error: expected first syscall result to be >= 0, got | |
%d", r) | |
} | |
return r, nil | |
} | |
func setFileStatusFlags(f int32) error { | |
r1, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(syscall.Stdin), | |
syscall.F_SETFL, uintptr(f)) | |
if errno != 0 { | |
return os.NewSyscallError("SYS_FCNTL", errno) | |
} | |
if r1 != 0 { | |
return fmt.Errorf("Error: expected first syscall result to be 0, got %d", | |
r1) | |
} | |
return nil | |
} | |
// http://stackoverflow.com/a/6599441/23582 | |
func readSingleKeypress() (byte, error) { | |
oldFl, err := getFileStatusFlags() | |
if err != nil { | |
return 0, err | |
} | |
oldTermios, err := getTermios() | |
if err != nil { | |
return 0, err | |
} | |
defer setFileStatusFlags(oldFl) | |
defer setTermios(oldTermios) | |
newFl, newTermios := oldFl, oldTermios | |
newTermios.Iflag &^= (syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | | |
syscall.ISTRIP) | |
newTermios.Iflag &^= (syscall.INLCR | syscall.IGNCR | syscall.ICRNL | | |
syscall.IXON) | |
newTermios.Oflag &^= syscall.OPOST | |
newTermios.Cflag &^= (syscall.CSIZE | syscall.PARENB) | |
newTermios.Cflag |= syscall.CS8 | |
newTermios.Lflag &^= (syscall.ECHONL | syscall.ECHO | syscall.ICANON | | |
syscall.ISIG | syscall.IEXTEN) | |
newTermios.Cc[syscall.VMIN] = 1 | |
newTermios.Cc[syscall.VTIME] = 0 | |
if err = setTermios(newTermios); err != nil { | |
return 0, err | |
} | |
newFl &^= syscall.O_NONBLOCK | |
if err = setFileStatusFlags(newFl); err != nil { | |
return 0, err | |
} | |
keys := []byte{0} | |
n, err := syscall.Read(syscall.Stdin, keys) | |
if err != nil { | |
return 0, err | |
} | |
if n != 1 { | |
return 0, fmt.Errorf("Expected to read 1 byte, got %d", n) | |
} | |
return keys[0], nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment