123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- // +build windows
- package pb
- import (
- "errors"
- "fmt"
- "os"
- "sync"
- "syscall"
- "unsafe"
- )
- var tty = os.Stdin
- var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- // GetConsoleScreenBufferInfo retrieves information about the
- // specified console screen buffer.
- // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
- // GetConsoleMode retrieves the current input mode of a console's
- // input buffer or the current output mode of a console screen buffer.
- // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
- getConsoleMode = kernel32.NewProc("GetConsoleMode")
- // SetConsoleMode sets the input mode of a console's input buffer
- // or the output mode of a console screen buffer.
- // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
- setConsoleMode = kernel32.NewProc("SetConsoleMode")
- // SetConsoleCursorPosition sets the cursor position in the
- // specified console screen buffer.
- // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx
- setConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
- )
- type (
- // Defines the coordinates of the upper left and lower right corners
- // of a rectangle.
- // See
- // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311(v=vs.85).aspx
- smallRect struct {
- Left, Top, Right, Bottom int16
- }
- // Defines the coordinates of a character cell in a console screen
- // buffer. The origin of the coordinate system (0,0) is at the top, left cell
- // of the buffer.
- // See
- // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx
- coordinates struct {
- X, Y int16
- }
- word int16
- // Contains information about a console screen buffer.
- // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx
- consoleScreenBufferInfo struct {
- dwSize coordinates
- dwCursorPosition coordinates
- wAttributes word
- srWindow smallRect
- dwMaximumWindowSize coordinates
- }
- )
- // terminalWidth returns width of the terminal.
- func terminalWidth() (width int, err error) {
- var info consoleScreenBufferInfo
- _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0)
- if e != 0 {
- return 0, error(e)
- }
- return int(info.dwSize.X) - 1, nil
- }
- func getCursorPos() (pos coordinates, err error) {
- var info consoleScreenBufferInfo
- _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0)
- if e != 0 {
- return info.dwCursorPosition, error(e)
- }
- return info.dwCursorPosition, nil
- }
- func setCursorPos(pos coordinates) error {
- _, _, e := syscall.Syscall(setConsoleCursorPosition.Addr(), 2, uintptr(syscall.Stdout), uintptr(uint32(uint16(pos.Y))<<16|uint32(uint16(pos.X))), 0)
- if e != 0 {
- return error(e)
- }
- return nil
- }
- var ErrPoolWasStarted = errors.New("Bar pool was started")
- var echoLocked bool
- var echoLockMutex sync.Mutex
- var oldState word
- func lockEcho() (shutdownCh chan struct{}, err error) {
- echoLockMutex.Lock()
- defer echoLockMutex.Unlock()
- if echoLocked {
- err = ErrPoolWasStarted
- return
- }
- echoLocked = true
- if _, _, e := syscall.Syscall(getConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&oldState)), 0); e != 0 {
- err = fmt.Errorf("Can't get terminal settings: %v", e)
- return
- }
- newState := oldState
- const ENABLE_ECHO_INPUT = 0x0004
- const ENABLE_LINE_INPUT = 0x0002
- newState = newState & (^(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))
- if _, _, e := syscall.Syscall(setConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(newState), 0); e != 0 {
- err = fmt.Errorf("Can't set terminal settings: %v", e)
- return
- }
- shutdownCh = make(chan struct{})
- return
- }
- func unlockEcho() (err error) {
- echoLockMutex.Lock()
- defer echoLockMutex.Unlock()
- if !echoLocked {
- return
- }
- echoLocked = false
- if _, _, e := syscall.Syscall(setConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(oldState), 0); e != 0 {
- err = fmt.Errorf("Can't set terminal settings")
- }
- return
- }
|