目录
前言
有时候会感觉输入一个事件假如用cin
或用scanf
有点仓促,输入完还要按个Enter感觉不咋样
怎么做呢?
我们可以使用ReadConsoleInput来解决我们的想法
正片开始!!!
ReadConsoleInput
头文件
首先我们需要导入头windows.h
才能使用ReadConsoleInput
函数
这个没什么好说的
构造
BOOL ReadConsoleInput(
HANDLE hConsoleInput,
PINPUT_RECORD lpBuffer,
DWORD nLength,
LPDWORD lpNumberOfEventsRead
);
- HANDLE hConsoleInput
- 这个不用怎么解释,用
GetStdHandle(STD_INPUT_HANDLE);
就可以了
- 这个不用怎么解释,用
- PINPUT_RECORD lpBuffer
- 一个列表定义
PINPUT_RECORD even[len];
就行了
- 一个列表定义
- DWORD nLenght
- lpBuffer的长度
- LPDWORD lpNumberOfEventsRead
- 指向一个变量的指针,函数将写回实际读取到的事件数量
为什么要一个列表(选看)
(这仅是我个人的理解)
因为假如你同时输入很多个事件有一些就会被导致堵塞所以我们要给他一个装事件的列表
获取输入(PINPUT_RECORD)
构造
typedef struct _INPUT_RECORD {
WORD EventType; // 事件类型
union {
KEY_EVENT_RECORD KeyEvent; // 键盘事件
MOUSE_EVENT_RECORD MouseEvent; // 鼠标事件
WINDOW_BUFFER_SIZE_EVENT WindowBufferSizeEvent; // 窗口缓冲区大小事件
MENU_EVENT_RECORD MenuEvent; // 菜单事件
FOCUS_EVENT_RECORD FocusEvent; // 焦点事件
} Event;
} INPUT_RECORD, *PINPUT_RECORD;
- WORD EventType
- 事件类型用 EventType 字段指定,常见的事件类型包括:
- KEY_EVENT(0x0001):
表示该事件是一个键盘事件。此时,Event成员将包含一个KEY_EVENT_RECORD结构体,该结构体提供了有关键盘事件的详细信息,如按键是否被按下、按键的重复次数、虚拟键码、虚拟扫描码、Unicode字符或ASCII字符表示、以及控制键的状态等。 - MOUSE_EVENT(0x0002):
表示该事件是一个鼠标事件。此时,Event成员将包含一个MOUSE_EVENT_RECORD结构体,该结构体提供了有关鼠标移动或鼠标按钮按下的详细信息,如鼠标的位置、按钮状态等。
WINDOW_BUFFER_SIZE_EVENT(0x0004):
表示该事件是控制台屏幕缓冲区大小变更事件。此时,Event成员将包含一个WINDOW_BUFFER_SIZE_RECORD结构体,该结构体提供了有关控制台屏幕缓冲区新大小的信息。 - MENU_EVENT(0x0008):
表示该事件与菜单相关。然而,在大多数控制台应用程序中,这些事件通常在内部使用,且通常不需要由开发者直接处理。 - FOCUS_EVENT(0x0010):
表示该事件与焦点变化相关。这些事件也在内部使用,并且通常不需要由开发者直接处理。
- KEY_EVENT(0x0001):
- 事件类型用 EventType 字段指定,常见的事件类型包括:
- Event
- 各种事件,看后文
KEY_EVENT_RECORD
它包含了关于按键事件的详细信息,如按键是否被按下、按键的重复次数、虚拟键码、虚拟扫描码、转换后的 Unicode 或 ASCII 字符,以及控制键(如 Shift、Ctrl、Alt 等)的状态。
KEY_EVENT_RECORD结构体包含以下成员:
- BOOL bKeyDown:指示按键是否被按下。如果按键被按下,则为
TRUE
;如果按键被释放,则为FALSE
。 - WORD wRepeatCount:表示按键被按下的重复次数。这个值在按键被持续按下时会增加,但在某些情况下(如自动重复被禁用时),它可能不会被正确更新。
- WORD wVirtualKeyCode:虚拟键码,以独立于设备的方式标识被按下的键。例如,
VK_SPACE
表示空格键,VK_RETURN
表示回车键。 - WORD wVirtualScanCode:虚拟扫描码,表示键盘硬件生成的依赖于设备的值。这个值对于大多数应用程序来说不是必需的,但在某些需要模拟硬件级输入的场景中可能会用到。
- union { WCHAR UnicodeChar; CHAR AsciiChar; } uChar:一个联合体,包含转换后的 Unicode 字符或 ASCII 字符。如果按键是一个可打印字符,并且应用程序以 Unicode 模式运行,则
UnicodeChar
将包含该字符的 Unicode 编码。如果应用程序以 ASCII 模式运行,则AsciiChar
将包含该字符的 ASCII 编码(但请注意,并非所有按键都会生成有效的 ASCII 字符)。 - DWORD dwControlKeyState:控制键的状态。这个成员可以是一个或多个标志的组合,用于指示哪些控制键(如 Shift、Ctrl、Alt 等)在按键事件发生时被按下。
事例
这是动态获取键盘输入的样例
#include <iostream>
#include <windows.h>
int main() {
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE) {
std::cerr << "GetStdHandle error\n";
return 1;
}
const int maxEvents = 128;
INPUT_RECORD irInBuf[maxEvents];
DWORD cNumRead;
while (true) {
// 读取控制台输入
if (!ReadConsoleInput(hStdin, irInBuf, maxEvents, &cNumRead)) {
std::cerr << "ReadConsoleInput error\n";
return 1;
}
// 处理每一个事件
for (DWORD i = 0; i < cNumRead; ++i) {
if (irInBuf[i].EventType == KEY_EVENT) {
KEY_EVENT_RECORD& ker = irInBuf[i].Event.KeyEvent;
if (ker.bKeyDown) { // 仅处理按键按下事件
std::cout << "Key Pressed: " << ker.wVirtualKeyCode << std::endl;
}
}
}
}
return 0;
}
其他事件类型(选看)
MOUSE_EVENT_RECORD
- dwMousePosition:
COORD
结构体,表示鼠标事件发生时的屏幕位置(以控制台屏幕缓冲区的字符单元坐标为单位)。 - dwButtonState:一个DWORD值,表示鼠标按钮的状态。最左侧的鼠标按钮对应最低有效位(0x0001),最右侧的鼠标按钮对应次低有效位(0x0002),其他按钮依次类推。如果按下了某个按钮,则对应的位被设置为1。
- dwControlKeyState:一个DWORD值,表示控制键(如Shift、Ctrl、Alt等)的状态。它可以是这些控制键状态标志的组合。
- dwEventFlags:一个DWORD值,表示鼠标事件的类型。例如,鼠标移动(MOUSE_MOVED)、双击(DOUBLE_CLICK)、水平滚轮移动(MOUSE_HWHEELED)或垂直滚轮移动(MOUSE_WHEELED)等。
WINDOW_BUFFER_SIZE_RECORD(对应于WINDOW_BUFFER_SIZE_EVENT)
- dwSize:一个
COORD
结构体,表示控制台屏幕缓冲区的新大小,包括宽度和高度。
MENU_EVENT_RECORD
- 这个结构体通常包含与菜单操作相关的详细信息,但在Windows控制台API的常规使用中,这些事件不是由开发者直接处理的,因此其具体成员可能不直接对开发者可见或需要。它们更多是由Windows控制台内部机制使用。
FOCUS_EVENT_RECORD
- bFocusEvent:一个布尔值,通常用于指示控制台窗口是否获得了或失去了焦点。然而,请注意,在
FOCUS_EVENT_RECORD
的实际定义中,可能并不直接包含名为bFocusEvent
的成员,而是可能通过其他方式(如事件类型或特定标志)来表示焦点事件。由于FOCUS_EVENT_RECORD
的具体实现可能因Windows版本或API的更新而有所不同,因此建议查阅最新的Windows控制台API文档以获取准确信息。
后文
这个玩意确实挺深奥的,看多几遍就懂了