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  }