Refactor pkg/term package for Windows tty support
Signed-off-by: John Gossman <johngos@microsoft.com>
This commit is contained in:
parent
d246e5f28e
commit
2d644f8ab1
3 changed files with 178 additions and 0 deletions
87
term/console_windows.go
Normal file
87
term/console_windows.go
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Consts for Get/SetConsoleMode function
|
||||||
|
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
|
||||||
|
ENABLE_ECHO_INPUT = 0x0004
|
||||||
|
ENABLE_INSERT_MODE = 0x0020
|
||||||
|
ENABLE_LINE_INPUT = 0x0002
|
||||||
|
ENABLE_MOUSE_INPUT = 0x0010
|
||||||
|
ENABLE_PROCESSED_INPUT = 0x0001
|
||||||
|
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||||
|
ENABLE_WINDOW_INPUT = 0x0008
|
||||||
|
// If parameter is a screen buffer handle, additional values
|
||||||
|
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||||
|
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||||
|
)
|
||||||
|
|
||||||
|
var kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
var (
|
||||||
|
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
|
||||||
|
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetConsoleMode(fileDesc uintptr) (uint32, error) {
|
||||||
|
var mode uint32
|
||||||
|
err := syscall.GetConsoleMode(syscall.Handle(fileDesc), &mode)
|
||||||
|
return mode, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetConsoleMode(fileDesc uintptr, mode uint32) error {
|
||||||
|
r, _, err := setConsoleModeProc.Call(fileDesc, uintptr(mode), 0)
|
||||||
|
if r == 0 {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// types for calling GetConsoleScreenBufferInfo
|
||||||
|
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx
|
||||||
|
type (
|
||||||
|
SHORT int16
|
||||||
|
|
||||||
|
SMALL_RECT struct {
|
||||||
|
Left SHORT
|
||||||
|
Top SHORT
|
||||||
|
Right SHORT
|
||||||
|
Bottom SHORT
|
||||||
|
}
|
||||||
|
|
||||||
|
COORD struct {
|
||||||
|
X SHORT
|
||||||
|
Y SHORT
|
||||||
|
}
|
||||||
|
|
||||||
|
WORD uint16
|
||||||
|
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||||
|
dwSize COORD
|
||||||
|
dwCursorPosition COORD
|
||||||
|
wAttributes WORD
|
||||||
|
srWindow SMALL_RECT
|
||||||
|
dwMaximumWindowSize COORD
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetConsoleScreenBufferInfo(fileDesc uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||||
|
var info CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
r, _, err := getConsoleScreenBufferInfoProc.Call(uintptr(fileDesc), uintptr(unsafe.Pointer(&info)), 0)
|
||||||
|
if r == 0 {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
return &info, nil
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package term
|
package term
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
89
term/term_windows.go
Normal file
89
term/term_windows.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
type State struct {
|
||||||
|
mode uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Winsize struct {
|
||||||
|
Height uint16
|
||||||
|
Width uint16
|
||||||
|
x uint16
|
||||||
|
y uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||||
|
ws := &Winsize{}
|
||||||
|
var info *CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
info, err := GetConsoleScreenBufferInfo(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ws.Height = uint16(info.srWindow.Right - info.srWindow.Left + 1)
|
||||||
|
ws.Width = uint16(info.srWindow.Bottom - info.srWindow.Top + 1)
|
||||||
|
|
||||||
|
ws.x = 0 // todo azlinux -- this is the pixel size of the Window, and not currently used by any caller
|
||||||
|
ws.y = 0
|
||||||
|
|
||||||
|
return ws, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal(fd uintptr) bool {
|
||||||
|
_, e := GetConsoleMode(fd)
|
||||||
|
return e == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||||
|
// previous state.
|
||||||
|
func RestoreTerminal(fd uintptr, state *State) error {
|
||||||
|
return SetConsoleMode(fd, state.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveState(fd uintptr) (*State, error) {
|
||||||
|
mode, e := GetConsoleMode(fd)
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return &State{mode}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx for these flag settings
|
||||||
|
func DisableEcho(fd uintptr, state *State) error {
|
||||||
|
state.mode &^= (ENABLE_ECHO_INPUT)
|
||||||
|
state.mode |= (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)
|
||||||
|
return SetConsoleMode(fd, state.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetRawTerminal(fd uintptr) (*State, error) {
|
||||||
|
oldState, err := MakeRaw(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// TODO (azlinux): implement handling interrupt and restore state of terminal
|
||||||
|
return oldState, 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) {
|
||||||
|
var state *State
|
||||||
|
state, err := SaveState(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx for these flag settings
|
||||||
|
state.mode &^= (ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)
|
||||||
|
err = SetConsoleMode(fd, state.mode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return state, nil
|
||||||
|
}
|
Loading…
Reference in a new issue