|
|
@@ -17,53 +17,7 @@
|
|
|
package terminal
|
|
|
|
|
|
import (
|
|
|
- "syscall"
|
|
|
- "unsafe"
|
|
|
-)
|
|
|
-
|
|
|
-const (
|
|
|
- enableLineInput = 2
|
|
|
- enableEchoInput = 4
|
|
|
- enableProcessedInput = 1
|
|
|
- enableWindowInput = 8
|
|
|
- enableMouseInput = 16
|
|
|
- enableInsertMode = 32
|
|
|
- enableQuickEditMode = 64
|
|
|
- enableExtendedFlags = 128
|
|
|
- enableAutoPosition = 256
|
|
|
- enableProcessedOutput = 1
|
|
|
- enableWrapAtEolOutput = 2
|
|
|
-)
|
|
|
-
|
|
|
-var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
|
-
|
|
|
-var (
|
|
|
- procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
|
- procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
|
|
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
|
|
-)
|
|
|
-
|
|
|
-type (
|
|
|
- short int16
|
|
|
- word uint16
|
|
|
-
|
|
|
- coord struct {
|
|
|
- x short
|
|
|
- y short
|
|
|
- }
|
|
|
- smallRect struct {
|
|
|
- left short
|
|
|
- top short
|
|
|
- right short
|
|
|
- bottom short
|
|
|
- }
|
|
|
- consoleScreenBufferInfo struct {
|
|
|
- size coord
|
|
|
- cursorPosition coord
|
|
|
- attributes word
|
|
|
- window smallRect
|
|
|
- maximumWindowSize coord
|
|
|
- }
|
|
|
+ "golang.org/x/sys/windows"
|
|
|
)
|
|
|
|
|
|
type State struct {
|
|
|
@@ -73,8 +27,8 @@ type State struct {
|
|
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
|
func IsTerminal(fd int) bool {
|
|
|
var st uint32
|
|
|
- r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
|
- return r != 0 && e == 0
|
|
|
+ err := windows.GetConsoleMode(windows.Handle(fd), &st)
|
|
|
+ return err == nil
|
|
|
}
|
|
|
|
|
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
|
|
@@ -82,14 +36,12 @@ func IsTerminal(fd int) bool {
|
|
|
// restored.
|
|
|
func MakeRaw(fd int) (*State, error) {
|
|
|
var st uint32
|
|
|
- _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
|
- if e != 0 {
|
|
|
- return nil, error(e)
|
|
|
+ if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
- raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
|
|
|
- _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
|
|
|
- if e != 0 {
|
|
|
- return nil, error(e)
|
|
|
+ raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT)
|
|
|
+ if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
return &State{st}, nil
|
|
|
}
|
|
|
@@ -98,9 +50,8 @@ func MakeRaw(fd int) (*State, error) {
|
|
|
// restore the terminal after a signal.
|
|
|
func GetState(fd int) (*State, error) {
|
|
|
var st uint32
|
|
|
- _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
|
- if e != 0 {
|
|
|
- return nil, error(e)
|
|
|
+ if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
return &State{st}, nil
|
|
|
}
|
|
|
@@ -108,25 +59,23 @@ func GetState(fd int) (*State, error) {
|
|
|
// Restore restores the terminal connected to the given file descriptor to a
|
|
|
// previous state.
|
|
|
func Restore(fd int, state *State) error {
|
|
|
- _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
|
|
|
- return err
|
|
|
+ return windows.SetConsoleMode(windows.Handle(fd), state.mode)
|
|
|
}
|
|
|
|
|
|
// GetSize returns the dimensions of the given terminal.
|
|
|
func GetSize(fd int) (width, height int, err error) {
|
|
|
- var info consoleScreenBufferInfo
|
|
|
- _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
|
|
|
- if e != 0 {
|
|
|
- return 0, 0, error(e)
|
|
|
+ var info windows.ConsoleScreenBufferInfo
|
|
|
+ if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
|
|
|
+ return 0, 0, err
|
|
|
}
|
|
|
- return int(info.size.x), int(info.size.y), nil
|
|
|
+ return int(info.Size.X), int(info.Size.Y), nil
|
|
|
}
|
|
|
|
|
|
// passwordReader is an io.Reader that reads from a specific Windows HANDLE.
|
|
|
type passwordReader int
|
|
|
|
|
|
func (r passwordReader) Read(buf []byte) (int, error) {
|
|
|
- return syscall.Read(syscall.Handle(r), buf)
|
|
|
+ return windows.Read(windows.Handle(r), buf)
|
|
|
}
|
|
|
|
|
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
|
|
@@ -134,21 +83,19 @@ func (r passwordReader) Read(buf []byte) (int, error) {
|
|
|
// returned does not include the \n.
|
|
|
func ReadPassword(fd int) ([]byte, error) {
|
|
|
var st uint32
|
|
|
- _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
|
- if e != 0 {
|
|
|
- return nil, error(e)
|
|
|
+ if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
old := st
|
|
|
|
|
|
- st &^= (enableEchoInput)
|
|
|
- st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
|
|
|
- _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
|
|
|
- if e != 0 {
|
|
|
- return nil, error(e)
|
|
|
+ st &^= (windows.ENABLE_ECHO_INPUT)
|
|
|
+ st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT)
|
|
|
+ if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
|
|
|
defer func() {
|
|
|
- syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
|
|
|
+ windows.SetConsoleMode(windows.Handle(fd), old)
|
|
|
}()
|
|
|
|
|
|
return readPasswordLine(passwordReader(fd))
|