| // +build windows |
| package term |
| |
| import ( |
| "io" |
| "os" |
| |
| "github.com/docker/docker/pkg/term/winconsole" |
| ) |
| |
| // State holds the console mode for the terminal. |
| type State struct { |
| mode uint32 |
| } |
| |
| // Winsize is used for window size. |
| type Winsize struct { |
| Height uint16 |
| Width uint16 |
| x uint16 |
| y uint16 |
| } |
| |
| func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { |
| switch { |
| case os.Getenv("ConEmuANSI") == "ON": |
| // The ConEmu shell emulates ANSI well by default. |
| return os.Stdin, os.Stdout, os.Stderr |
| case os.Getenv("MSYSTEM") != "": |
| // MSYS (mingw) does not emulate ANSI well. |
| return winconsole.WinConsoleStreams() |
| default: |
| return winconsole.WinConsoleStreams() |
| } |
| } |
| |
| // GetFdInfo returns file descriptor and bool indicating whether the file is a terminal. |
| func GetFdInfo(in interface{}) (uintptr, bool) { |
| return winconsole.GetHandleInfo(in) |
| } |
| |
| // GetWinsize retrieves the window size of the terminal connected to the passed file descriptor. |
| func GetWinsize(fd uintptr) (*Winsize, error) { |
| info, err := winconsole.GetConsoleScreenBufferInfo(fd) |
| if err != nil { |
| return nil, err |
| } |
| |
| // TODO(azlinux): Set the pixel width / height of the console (currently unused by any caller) |
| return &Winsize{ |
| Width: uint16(info.Window.Bottom - info.Window.Top + 1), |
| Height: uint16(info.Window.Right - info.Window.Left + 1), |
| x: 0, |
| y: 0}, nil |
| } |
| |
| // SetWinsize sets the size of the given terminal connected to the passed file descriptor. |
| func SetWinsize(fd uintptr, ws *Winsize) error { |
| // TODO(azlinux): Implement SetWinsize |
| return nil |
| } |
| |
| // IsTerminal returns true if the given file descriptor is a terminal. |
| func IsTerminal(fd uintptr) bool { |
| return winconsole.IsConsole(fd) |
| } |
| |
| // RestoreTerminal restores the terminal connected to the given file descriptor to a |
| // previous state. |
| func RestoreTerminal(fd uintptr, state *State) error { |
| return winconsole.SetConsoleMode(fd, state.mode) |
| } |
| |
| // SaveState saves the state of the terminal connected to the given file descriptor. |
| func SaveState(fd uintptr) (*State, error) { |
| mode, e := winconsole.GetConsoleMode(fd) |
| if e != nil { |
| return nil, e |
| } |
| return &State{mode}, nil |
| } |
| |
| // DisableEcho disables echo for the terminal connected to the given file descriptor. |
| // -- See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx |
| func DisableEcho(fd uintptr, state *State) error { |
| mode := state.mode |
| mode &^= winconsole.ENABLE_ECHO_INPUT |
| mode |= winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT |
| // TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state. |
| return winconsole.SetConsoleMode(fd, mode) |
| } |
| |
| // SetRawTerminal puts the terminal connected to the given file descriptor into raw |
| // mode and returns the previous state of the terminal so that it can be |
| // restored. |
| func SetRawTerminal(fd uintptr) (*State, error) { |
| state, err := MakeRaw(fd) |
| if err != nil { |
| return nil, err |
| } |
| // TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state. |
| return state, err |
| } |
| |
| // MakeRaw puts the terminal connected to the given file descriptor into raw |
| // mode and returns the previous state of the terminal so that it can be |
| // restored. |
| func MakeRaw(fd uintptr) (*State, error) { |
| state, err := SaveState(fd) |
| if err != nil { |
| return nil, err |
| } |
| |
| // See |
| // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx |
| // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx |
| mode := state.mode |
| |
| // Disable these modes |
| mode &^= winconsole.ENABLE_ECHO_INPUT |
| mode &^= winconsole.ENABLE_LINE_INPUT |
| mode &^= winconsole.ENABLE_MOUSE_INPUT |
| // TODO(azlinux): Enable window input to handle window resizing |
| mode |= winconsole.ENABLE_WINDOW_INPUT |
| |
| // Enable these modes |
| mode |= winconsole.ENABLE_PROCESSED_INPUT |
| mode |= winconsole.ENABLE_EXTENDED_FLAGS |
| mode |= winconsole.ENABLE_INSERT_MODE |
| mode |= winconsole.ENABLE_QUICK_EDIT_MODE |
| |
| err = winconsole.SetConsoleMode(fd, mode) |
| if err != nil { |
| return nil, err |
| } |
| return state, nil |
| } |