diff --git a/windows/input_record.go b/windows/input_record.go new file mode 100644 index 000000000..1b539bc17 --- /dev/null +++ b/windows/input_record.go @@ -0,0 +1,32 @@ +package windows + +// InputRecord is the data structure that ReadConsoleInput writes into. +// All Documentation originally provided by Michael Niksa, et al. at Microsoft Corporation +// under CC Attribution 4.0 International +// via https://docs.microsoft.com/en-us/windows/console/input-record-str +type InputRecord struct { + // 0x1: Key event + // 0x2: Will never be read when using ReadConsoleInput + // 0x4: Window buffer size event + // 0x8: Deprecated + // 0x10: Deprecated + // Original source: https://docs.microsoft.com/en-us/windows/console/input-record-str#members + Type uint16 + _ [2]byte // discard the next two bytes + + // Data contents are: + // If the event is a key event (Type == 1): + // - Data[0] is 0x1 if the key is pressed, 0x0 if the key is released + // - Data[3] is the keycode of the pressed key, see + // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + // - Data[5] is the ascii or Unicode keycode. + // - Data[6] stores the state of the modifier keys. + // Original source: https://docs.microsoft.com/en-us/windows/console/key-event-record-str + // + // If the event is a window buffer size event (Type == 4): + // - Data[0] is the new amount of character rows + // - Data[1] is the new amount of character columns + // Original source: https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str + Data [6]uint16 +} + diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index c38c59d77..7b1d09df0 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -285,6 +285,7 @@ var ( procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW") procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject") procReadConsoleW = modkernel32.NewProc("ReadConsoleW") + procReadConsoleInputW = modkernel32.NewProc("ReadConsoleInputW") procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW") procReadFile = modkernel32.NewProc("ReadFile") procReleaseMutex = modkernel32.NewProc("ReleaseMutex") @@ -2421,6 +2422,12 @@ func QueryInformationJobObject(job Handle, JobObjectInformationClass int32, JobO return } +// ReadConsole reads characters from the console and writes the Unicode keycode(s) into buf +// buf should point to the element in an array where writing should begin +// toread specifies how many characters should be read +// read should point to a uint32 where the number of characters actually read should be stored +// inputControl should be set to NULL, as it currently has no effect +// See: https://docs.microsoft.com/en-us/windows/console/readconsole func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) { r1, _, e1 := syscall.Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0) if r1 == 0 { @@ -2429,6 +2436,24 @@ func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, input return } +// ReadConsoleInput reads keypresses from console. +// The data is read into the array starting at buf. +// toread is the amount of keypresses that should be read. +// The actual amount of keypresses read is stored in read. +// The difference between ReadConsole and ReadConsoleInput is that +// - ReadConsole only reads character insertion (reads any character key pressed) +// - ReadConsoleInput reads any key (both key press and key release) as well as mouse, focus and window size change events +// See: https://docs.microsoft.com/en-us/windows/console/readconsoleinput +func ReadConsoleInput(console Handle, rec *InputRecord, toread uint32, read *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procReadConsoleInputW.Addr(), 4, + uintptr(console), uintptr(unsafe.Pointer(rec)), uintptr(toread), + uintptr(unsafe.Pointer(read)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { var _p0 uint32 if watchSubTree {