github.com/burke/ttyutils@v0.0.0-20160630170808-5017fbbf251a/ttyutils.go (about) 1 package ttyutils 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "syscall" 8 "unsafe" 9 ) 10 11 type Termios syscall.Termios 12 13 type Ttysize struct { 14 Lines uint16 15 Columns uint16 16 } 17 18 func IsTerminal(fd uintptr) bool { 19 var termios syscall.Termios 20 _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 21 return err == 0 22 } 23 24 func Winsize(of *os.File) (Ttysize, error) { 25 var dimensions [4]uint16 26 27 err := ioctl(of.Fd(), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions))) 28 if err != nil { 29 return Ttysize{}, err 30 } 31 32 return Ttysize{dimensions[0], dimensions[1]}, nil 33 } 34 35 func MirrorWinsize(from, to *os.File) error { 36 var dimensions [4]uint16 37 38 err := ioctl(from.Fd(), syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&dimensions))) 39 if err != nil { 40 return err 41 } 42 err = ioctl(to.Fd(), syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(&dimensions))) 43 if err != nil { 44 return err 45 } 46 return nil 47 } 48 49 func NoEcho(fd uintptr) (*Termios, error) { 50 var s Termios 51 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&s)), 0, 0, 0); err != 0 { 52 return nil, err 53 } 54 55 oldState := s 56 s.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK 57 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlWriteTermios, uintptr(unsafe.Pointer(&s)), 0, 0, 0); err != 0 { 58 return nil, err 59 } 60 61 return &oldState, nil 62 } 63 64 func MakeTerminalRaw(fd uintptr) (*Termios, error) { 65 var s Termios 66 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&s)), 0, 0, 0); err != 0 { 67 return nil, err 68 } 69 70 oldState := s 71 s.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF | syscall.IMAXBEL | syscall.BRKINT 72 s.Iflag |= syscall.IGNBRK 73 s.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG | syscall.IEXTEN | syscall.ECHOE | syscall.ECHOK 74 s.Oflag &^= syscall.OPOST 75 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlWriteTermios, uintptr(unsafe.Pointer(&s)), 0, 0, 0); err != 0 { 76 return nil, err 77 } 78 79 return &oldState, nil 80 } 81 82 func RestoreTerminalState(fd uintptr, termios *Termios) error { 83 _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(termios)), 0, 0, 0) 84 return err 85 } 86 87 func ioctl(fd uintptr, cmd uintptr, ptr uintptr) error { 88 _, _, e := syscall.Syscall( 89 syscall.SYS_IOCTL, 90 fd, 91 cmd, 92 uintptr(unsafe.Pointer(ptr)), 93 ) 94 if e != 0 { 95 return errors.New(fmt.Sprintf("ioctl failed! %s", e)) 96 } 97 return nil 98 }