c++ 实时监看控制台事件(ReadConsoleInput的运用)

前言

有时候会感觉输入一个事件假如用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)
        表示该事件与焦点变化相关。这些事件也在内部使用,并且通常不需要由开发者直接处理。
  • 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

  • dwMousePositionCOORD结构体,表示鼠标事件发生时的屏幕位置(以控制台屏幕缓冲区的字符单元坐标为单位)。
  • 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文档以获取准确信息。

后文

这个玩意确实挺深奥的,看多几遍就懂了

在 C 语言中,可以使用第三方库或操作系统提供的 API 来检测键盘事件。以下是两种常见的方法: 1. 使用第三方库 可以使用像 ncurses 这样的第三方库来检测键盘事件。这种方法可以在 Linux 和 macOS 等操作系统上使用。 下面是一个使用 ncurses 检测键盘事件的示例程序: ```c #include <ncurses.h> int main() { int ch; initscr(); // 初始化 ncurses cbreak(); // 禁用行缓冲,可以立即读取输入 noecho(); // 关闭回显,不显示用户输入的字符 keypad(stdscr, TRUE); // 开启键盘映射,可以捕捉特殊键如方向键、F1 等 while ((ch = getch()) != KEY_F(1)) { // 循环读取输入,直到按下 F1 键 printw("您按下了键:%d\n", ch); // 打印用户输入的键码 refresh(); // 刷新屏幕 } endwin(); // 结束 ncurses return 0; } ``` 2. 使用操作系统提供的 API 可以使用操作系统提供的 API 来检测键盘事件。例如,在 Windows 操作系统中,可以使用 `GetAsyncKeyState` 函数来检测键盘事件。这个函数可以检测键盘上的某个键是否被按下,可以检测普通键和特殊键如方向键、Shift 等。 下面是一个使用 `GetAsyncKeyState` 函数检测键盘事件的示例程序: ```c #include <Windows.h> #include <stdio.h> int main() { while (1) { // 循环读取输入 if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) { // 如果按下了 Esc 键,则退出循环 break; } for (int i = 0; i < 256; i++) { // 遍历所有键 if (GetAsyncKeyState(i) & 0x8000) { // 如果某个键被按下 printf("您按下了键:%d\n", i); // 打印用户输入的键码 } } Sleep(10); // 暂停 10 毫秒,避免过多占用 CPU 资源 } return 0; } ``` 需要注意的是,这种方法只能在 Windows 操作系统中使用。在其他操作系统中,可能需要使用不同的函数来检测键盘事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值