package main import ( "fmt" "syscall" "github.com/c-bata/go-prompt" "github.com/pkg/term/termios" ) const fd = 0 var orig syscall.Termios func SetRawMode() { var n syscall.Termios if err := termios.Tcgetattr(uintptr(fd), &orig); err != nil { fmt.Println("Failed to get attribute") return } n = orig // "&^=" used like: https://play.golang.org/p/8eJw3JxS4O n.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG n.Cc[syscall.VMIN] = 1 n.Cc[syscall.VTIME] = 0 termios.Tcsetattr(uintptr(fd), termios.TCSANOW, (*syscall.Termios)(&n)) } func Restore() { termios.Tcsetattr(uintptr(fd), termios.TCSANOW, &orig) } func main() { SetRawMode() defer Restore() defer fmt.Println("exited!") bufCh := make(chan []byte, 128) go readBuffer(bufCh) fmt.Print("> ") parser := prompt.NewStandardInputParser() for { b := <-bufCh if key := parser.GetKey(b); key == prompt.NotDefined { fmt.Printf("Key '%s' data:'%#v'\n", string(b), b) } else { if key == prompt.ControlC { fmt.Println("exit.") return } fmt.Printf("Key '%s' data:'%#v'\n", key, b) } fmt.Print("> ") } } func readBuffer(bufCh chan []byte) { buf := make([]byte, 1024) for { if n, err := syscall.Read(syscall.Stdin, buf); err == nil { bufCh <- buf[:n] } } }