All checks were successful
continuous-integration/drone/push Build is passing
See #478
155 lines
5.3 KiB
Go
155 lines
5.3 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package coninput
|
|
|
|
import (
|
|
"fmt"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
var (
|
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
|
procReadConsoleInputW = modkernel32.NewProc("ReadConsoleInputW")
|
|
procPeekConsoleInputW = modkernel32.NewProc("PeekConsoleInputW")
|
|
procGetNumberOfConsoleInputEvents = modkernel32.NewProc("GetNumberOfConsoleInputEvents")
|
|
procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer")
|
|
)
|
|
|
|
// NewStdinHandle is a shortcut for windows.GetStdHandle(windows.STD_INPUT_HANDLE).
|
|
func NewStdinHandle() (windows.Handle, error) {
|
|
return windows.GetStdHandle(windows.STD_INPUT_HANDLE)
|
|
}
|
|
|
|
// WinReadConsoleInput is a thin wrapper around the Windows console API function
|
|
// ReadConsoleInput (see
|
|
// https://docs.microsoft.com/en-us/windows/console/readconsoleinput). In most
|
|
// cases it is more practical to either use ReadConsoleInput or
|
|
// ReadNConsoleInputs.
|
|
func WinReadConsoleInput(consoleInput windows.Handle, buffer *InputRecord,
|
|
length uint32, numberOfEventsRead *uint32) error {
|
|
r, _, e := syscall.Syscall6(procReadConsoleInputW.Addr(), 4,
|
|
uintptr(consoleInput), uintptr(unsafe.Pointer(buffer)), uintptr(length),
|
|
uintptr(unsafe.Pointer(numberOfEventsRead)), 0, 0)
|
|
if r == 0 {
|
|
return error(e)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReadNConsoleInputs is a wrapper around ReadConsoleInput (see
|
|
// https://docs.microsoft.com/en-us/windows/console/readconsoleinput) that
|
|
// automates the event buffer allocation in oder to provide io.Reader-like
|
|
// sematics. maxEvents must be greater than zero.
|
|
func ReadNConsoleInputs(console windows.Handle, maxEvents uint32) ([]InputRecord, error) {
|
|
if maxEvents == 0 {
|
|
return nil, fmt.Errorf("maxEvents cannot be zero")
|
|
}
|
|
|
|
var inputRecords = make([]InputRecord, maxEvents)
|
|
n, err := ReadConsoleInput(console, inputRecords)
|
|
|
|
return inputRecords[:n], err
|
|
}
|
|
|
|
// ReadConsoleInput provides an ideomatic interface to the Windows console API
|
|
// function ReadConsoleInput (see
|
|
// https://docs.microsoft.com/en-us/windows/console/readconsoleinput). The size
|
|
// of inputRecords must be greater than zero.
|
|
func ReadConsoleInput(console windows.Handle, inputRecords []InputRecord) (uint32, error) {
|
|
if len(inputRecords) == 0 {
|
|
return 0, fmt.Errorf("size of input record buffer cannot be zero")
|
|
}
|
|
|
|
var read uint32
|
|
err := WinReadConsoleInput(console, &inputRecords[0], uint32(len(inputRecords)), &read)
|
|
|
|
return read, err
|
|
}
|
|
|
|
// WinPeekConsoleInput is a thin wrapper around the Windows console API function
|
|
// PeekConsoleInput (see
|
|
// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput). In most
|
|
// cases it is more practical to either use PeekConsoleInput or
|
|
// PeekNConsoleInputs.
|
|
func WinPeekConsoleInput(consoleInput windows.Handle, buffer *InputRecord,
|
|
length uint32, numberOfEventsRead *uint32) error {
|
|
r, _, e := syscall.Syscall6(procPeekConsoleInputW.Addr(), 4,
|
|
uintptr(consoleInput), uintptr(unsafe.Pointer(buffer)), uintptr(length),
|
|
uintptr(unsafe.Pointer(numberOfEventsRead)), 0, 0)
|
|
if r == 0 {
|
|
return error(e)
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// PeekNConsoleInputs is a wrapper around PeekConsoleInput (see
|
|
// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput) that
|
|
// automates the event buffer allocation in oder to provide io.Reader-like
|
|
// sematics. maxEvents must be greater than zero.
|
|
func PeekNConsoleInputs(console windows.Handle, maxEvents uint32) ([]InputRecord, error) {
|
|
if maxEvents == 0 {
|
|
return nil, fmt.Errorf("maxEvents cannot be zero")
|
|
}
|
|
|
|
var inputRecords = make([]InputRecord, maxEvents)
|
|
n, err := PeekConsoleInput(console, inputRecords)
|
|
|
|
return inputRecords[:n], err
|
|
}
|
|
|
|
// PeekConsoleInput provides an ideomatic interface to the Windows console API
|
|
// function PeekConsoleInput (see
|
|
// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput). The size
|
|
// of inputRecords must be greater than zero.
|
|
func PeekConsoleInput(console windows.Handle, inputRecords []InputRecord) (uint32, error) {
|
|
if len(inputRecords) == 0 {
|
|
return 0, fmt.Errorf("size of input record buffer cannot be zero")
|
|
}
|
|
|
|
var read uint32
|
|
|
|
err := WinPeekConsoleInput(console, &inputRecords[0], uint32(len(inputRecords)), &read)
|
|
|
|
return read, err
|
|
}
|
|
|
|
// WinGetNumberOfConsoleInputEvents provides an ideomatic interface to the
|
|
// Windows console API function GetNumberOfConsoleInputEvents (see
|
|
// https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents).
|
|
func WinGetNumberOfConsoleInputEvents(consoleInput windows.Handle, numberOfEvents *uint32) error {
|
|
r, _, e := syscall.Syscall6(procGetNumberOfConsoleInputEvents.Addr(), 2,
|
|
uintptr(consoleInput), uintptr(unsafe.Pointer(numberOfEvents)), 0,
|
|
0, 0, 0)
|
|
if r == 0 {
|
|
return error(e)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetNumberOfConsoleInputEvents provides an ideomatic interface to the Windows
|
|
// console API function GetNumberOfConsoleInputEvents (see
|
|
// https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents).
|
|
func GetNumberOfConsoleInputEvents(console windows.Handle) (uint32, error) {
|
|
var nEvents uint32
|
|
err := WinGetNumberOfConsoleInputEvents(console, &nEvents)
|
|
|
|
return nEvents, err
|
|
}
|
|
|
|
func FlushConsoleInputBuffer(consoleInput windows.Handle) error {
|
|
r, _, e := syscall.Syscall(procFlushConsoleInputBuffer.Addr(), 1, uintptr(consoleInput), 0, 0)
|
|
if r == 0 {
|
|
return error(e)
|
|
}
|
|
|
|
return nil
|
|
}
|