1// +build windows 2 3package pb 4 5import ( 6 "errors" 7 "fmt" 8 "os" 9 "sync" 10 "syscall" 11 "unsafe" 12) 13 14var tty = os.Stdin 15 16var ( 17 kernel32 = syscall.NewLazyDLL("kernel32.dll") 18 19 // GetConsoleScreenBufferInfo retrieves information about the 20 // specified console screen buffer. 21 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx 22 procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") 23 24 // GetConsoleMode retrieves the current input mode of a console's 25 // input buffer or the current output mode of a console screen buffer. 26 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx 27 getConsoleMode = kernel32.NewProc("GetConsoleMode") 28 29 // SetConsoleMode sets the input mode of a console's input buffer 30 // or the output mode of a console screen buffer. 31 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx 32 setConsoleMode = kernel32.NewProc("SetConsoleMode") 33 34 // SetConsoleCursorPosition sets the cursor position in the 35 // specified console screen buffer. 36 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx 37 setConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") 38) 39 40type ( 41 // Defines the coordinates of the upper left and lower right corners 42 // of a rectangle. 43 // See 44 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311(v=vs.85).aspx 45 smallRect struct { 46 Left, Top, Right, Bottom int16 47 } 48 49 // Defines the coordinates of a character cell in a console screen 50 // buffer. The origin of the coordinate system (0,0) is at the top, left cell 51 // of the buffer. 52 // See 53 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx 54 coordinates struct { 55 X, Y int16 56 } 57 58 word int16 59 60 // Contains information about a console screen buffer. 61 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx 62 consoleScreenBufferInfo struct { 63 dwSize coordinates 64 dwCursorPosition coordinates 65 wAttributes word 66 srWindow smallRect 67 dwMaximumWindowSize coordinates 68 } 69) 70 71// terminalWidth returns width of the terminal. 72func terminalWidth() (width int, err error) { 73 var info consoleScreenBufferInfo 74 _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0) 75 if e != 0 { 76 return 0, error(e) 77 } 78 return int(info.dwSize.X) - 1, nil 79} 80 81func getCursorPos() (pos coordinates, err error) { 82 var info consoleScreenBufferInfo 83 _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0) 84 if e != 0 { 85 return info.dwCursorPosition, error(e) 86 } 87 return info.dwCursorPosition, nil 88} 89 90func setCursorPos(pos coordinates) error { 91 _, _, e := syscall.Syscall(setConsoleCursorPosition.Addr(), 2, uintptr(syscall.Stdout), uintptr(uint32(uint16(pos.Y))<<16|uint32(uint16(pos.X))), 0) 92 if e != 0 { 93 return error(e) 94 } 95 return nil 96} 97 98var ErrPoolWasStarted = errors.New("Bar pool was started") 99 100var echoLocked bool 101var echoLockMutex sync.Mutex 102 103var oldState word 104 105func lockEcho() (shutdownCh chan struct{}, err error) { 106 echoLockMutex.Lock() 107 defer echoLockMutex.Unlock() 108 if echoLocked { 109 err = ErrPoolWasStarted 110 return 111 } 112 echoLocked = true 113 114 if _, _, e := syscall.Syscall(getConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&oldState)), 0); e != 0 { 115 err = fmt.Errorf("Can't get terminal settings: %v", e) 116 return 117 } 118 119 newState := oldState 120 const ENABLE_ECHO_INPUT = 0x0004 121 const ENABLE_LINE_INPUT = 0x0002 122 newState = newState & (^(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)) 123 if _, _, e := syscall.Syscall(setConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(newState), 0); e != 0 { 124 err = fmt.Errorf("Can't set terminal settings: %v", e) 125 return 126 } 127 128 shutdownCh = make(chan struct{}) 129 return 130} 131 132func unlockEcho() (err error) { 133 echoLockMutex.Lock() 134 defer echoLockMutex.Unlock() 135 if !echoLocked { 136 return 137 } 138 echoLocked = false 139 if _, _, e := syscall.Syscall(setConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(oldState), 0); e != 0 { 140 err = fmt.Errorf("Can't set terminal settings") 141 } 142 return 143} 144