term_x.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // +build linux darwin freebsd netbsd openbsd solaris dragonfly
  2. // +build !appengine
  3. package termutil
  4. import (
  5. "fmt"
  6. "os"
  7. "syscall"
  8. "unsafe"
  9. )
  10. var (
  11. tty *os.File
  12. unlockSignals = []os.Signal{
  13. os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL,
  14. }
  15. )
  16. type window struct {
  17. Row uint16
  18. Col uint16
  19. Xpixel uint16
  20. Ypixel uint16
  21. }
  22. func init() {
  23. var err error
  24. tty, err = os.Open("/dev/tty")
  25. if err != nil {
  26. tty = os.Stdin
  27. }
  28. }
  29. // TerminalWidth returns width of the terminal.
  30. func TerminalWidth() (int, error) {
  31. w := new(window)
  32. res, _, err := syscall.Syscall(sysIoctl,
  33. tty.Fd(),
  34. uintptr(syscall.TIOCGWINSZ),
  35. uintptr(unsafe.Pointer(w)),
  36. )
  37. if int(res) == -1 {
  38. return 0, err
  39. }
  40. return int(w.Col), nil
  41. }
  42. var oldState syscall.Termios
  43. func lockEcho() (err error) {
  44. fd := tty.Fd()
  45. if _, _, e := syscall.Syscall6(sysIoctl, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); e != 0 {
  46. err = fmt.Errorf("Can't get terminal settings: %v", e)
  47. return
  48. }
  49. newState := oldState
  50. newState.Lflag &^= syscall.ECHO
  51. newState.Lflag |= syscall.ICANON | syscall.ISIG
  52. newState.Iflag |= syscall.ICRNL
  53. if _, _, e := syscall.Syscall6(sysIoctl, fd, ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); e != 0 {
  54. err = fmt.Errorf("Can't set terminal settings: %v", e)
  55. return
  56. }
  57. return
  58. }
  59. func unlockEcho() (err error) {
  60. fd := tty.Fd()
  61. if _, _, e := syscall.Syscall6(sysIoctl, fd, ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); e != 0 {
  62. err = fmt.Errorf("Can't set terminal settings")
  63. }
  64. return
  65. }