描述控制台输入缓冲区中的输入事件。可以使用ReadConsoleInput或PeekConsoleInput函数从输入缓冲区读取这些记录,也可以使用WriteConsoleInput函数将这些记录写入输入缓冲区。
类型声明:
typedef struct _INPUT_RECORD { WORD EventType; union { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } Event; } INPUT_RECORD;EventType
输入事件类型的句柄和存储在Event成员中的事件记录。
该成员可以是以下值之一。
值含义FOCUS_EVENT 0x0010该事件成员包含一个FOCUS_EVENT_RECORD结构。这些事件在内部使用,应该被忽略。KEY_EVENT 0x0001该事件成员包含一个KEY_EVENT_RECORD结构有关键盘事件的信息。MENU_EVENT 0x0008该事件成员包含一个MENU_EVENT_RECORD结构。这些事件在内部使用,应该被忽略。MOUSE_EVENT 0x0002所述事件构件包含MOUSE_EVENT_RECORD结构用约鼠标移动或按键按压事件的信息。WINDOW_BUFFER_SIZE_EVENT 0x0004该事件成员包含一个WINDOW_BUFFER_SIZE_RECORD结构有关控制台屏幕缓冲区的新大小信息。事件 事件信息。此成员的格式取决于EventType成员指定的事件类型。
描述控制台INPUT_RECORD结构中的键盘输入事件。
typedef struct _KEY_EVENT_RECORD { BOOL bKeyDown; WORD wRepeatCount; WORD wVirtualKeyCode; WORD wVirtualScanCode; union { WCHAR UnicodeChar; CHAR AsciiChar; } uChar; DWORD dwControlKeyState; } KEY_EVENT_RECORD;bKeyDown 如果按下该键,则该成员为TRUE。否则,此成员为FALSE(密钥已释放)。
wRepeatCount 重复计数,表示正在按住某个键。例如,当按下某个键时,您可能会获得五个事件,该成员等于1,一个事件的成员等于5,或者此成员的多个事件大于或等于1。
wVirtualKeyCode 虚拟键码识别在设备无关的方式给定的键。
wVirtualScanCode 给定键的虚拟扫描代码,表示键盘硬件生成的与设备相关的值。
uChar 以下成员的联盟。
UnicodeChar 翻译的Unicode字符。
AsciiChar 翻译的ASCII字符。
dwControlKeyState 控制键的状态。该成员可以是以下一个或多个值。
值含义CAPSLOCK_ON 0x0080大写锁定被打开ENHANCED_KEY 0x0100扩展键被按下LEFT_ALT_PRESSED 0x0002按下左ALT键。LEFT_CTRL_PRESSED 0x0008按下左CTRL键。NUMLOCK_ON 0x0020数字锁定被打开RIGHT_ALT_PRESSED 0x0001按下右ALT键。RIGHT_CTRL_PRESSED 0x0004按下右CTRL键。SCROLLLOCK_ON 0x0040滚动锁定被打开SHIFT_PRESSED 0x0010按下SHIFT键。虚拟键值码表
下表显示了系统使用的虚拟键代码的符号常量名称,十六进制值以及鼠标或键盘等效项。代码按数字顺序列出。
恒/值描述VK_LBUTTON 0×01鼠标左键VK_RBUTTON 0×02鼠标右键VK_CANCEL 0×03控制中断处理VK_MBUTTON 0×04鼠标中键(三键鼠标)VK_XBUTTON1 0×05X1鼠标按钮VK_XBUTTON2 0×06X2鼠标按钮**- **0×07未定义VK_BACK0x08的BACKSPACE键VK_TAB×09TAB键**-**0x0A至0B保留的VK_CLEAR0x0C清除键VK_RETURN0X0D回车键**-**为0x0E-0F未定义VK_SHIFT为0x10SHIFT键VK_CONTROL为0x11CTRL键VK_MENU0×12ALT键VK_PAUSE0×13暂停键VK_CAPITAL0×14CAPS LOCK键**-**0x1A的未定义VK_ESCAPE0x1BESC键VK_CONVERT为0x1CIME转换VK_NONCONVERT0x1DIME非转换VK_ACCEPT0X1EIME接受VK_MODECHANGE为0x1FIME模式更改请求VK_SPACE为0x20空格键VK_PRIOR为0x21PAGE UP键VK_NEXT为0x22PAGE DOWN键VK_END0×23结束键VK_HOME0X24Home键VK_LEFT0x25左箭头键VK_UP0×26向上箭头键VK_RIGHT0×27右箭头键VK_DOWN0×28向下箭头键VK_SELECT0x29SELECT键VK_PRINT0x2A打印键VK_EXECUTE0x2B访问执行键VK_SNAPSHOT0x2c上PRINT SCREEN键VK_INSERT0x2DINS键VK_DELETE0x2E之间DEL键VK_HELP值为0x2F帮助键的0x300键0X311键0x322键0x333键0x344键0x355键0x366键0×377键0x388键0x399键**-**0x3A-40未定义的0x41关键的0x42B键0x43中C键0×44D键0×45E键0×46F键0X47G键0x48H键×49我关键0x4AJ键0x4BK键0x4CL键送出0x4dM键0x4EN键0x4F哦关键为0x50P键0x51Q键0×52R键0x53S键0x54T键0x55的U键0x56储存V键的0x57W键将0x58X键0×59Y键0x5AZ键VK_LWIN0x5B左键Windows键(自然键盘)VK_RWIN0x5C右键Windows键(自然键盘)VK_APPS0x5D应用键(自然键盘)**-**0x5E保留的VK_SLEEP0x5F的电脑睡眠键VK_NUMPAD00X60数字小键盘0键VK_NUMPAD10x61数字小键盘1键VK_NUMPAD20X62数字小键盘2键VK_NUMPAD30x63数字小键盘3键VK_NUMPAD40x64数字键盘4键VK_NUMPAD50x65数字键盘5键VK_NUMPAD60x66数字小键盘6键VK_NUMPAD70×67数字小键盘7键VK_NUMPAD80x68数字小键盘8键VK_NUMPAD90×69数字小键盘9键VK_MULTIPLY的0x6A乘以键VK_ADD0x6B添加密钥VK_SEPARATOR0x6C分隔键VK_SUBTRACT0x6D减去关键VK_DECIMAL0x6E十进制键VK_DIVIDE0x6F划分密钥VK_F10x70F1键VK_F20x71F2键VK_F30x72F3键VK_F40x73F4键VK_F50x74F5键VK_F60x75F6键VK_F70x76F7键VK_F80x77F8键VK_F90x78F9键VK_F100x79的F10键VK_F110x7AF11键VK_F120x7BF12键VK_F130x7CF13键VK_F140x7DF14键VK_F15的0x7EF15键VK_F160x7F的F16键VK_F170x80的F17键VK_F180×81F18键VK_F19为0x82F19键VK_F200×83F20键VK_F21的0x84F21键VK_F220x85F22键VK_F230x86可以F23键VK_F2487H的F24键**-**0x88-8F未分配VK_NUMLOCK的0x90NUM LOCK键VK_SCROLL0x91滚动锁定键0x92-96OEM特定**-**0x97-9F未分配VK_LSHIFT0XA0左SHIFT键VK_RSHIFT0xA1右SHIFT键VK_LCONTROL0xA2左控制键VK_RCONTROL0xA3执行右控制键VK_LMENU0xA4左MENU键VK_RMENU的0xA5右键MENUVK_BROWSER_BACK0xA6浏览器返回键VK_BROWSER_FORWARD0xA7浏览器转发键VK_BROWSER_REFRESH0xA8浏览器刷新键VK_BROWSER_STOP0xA9浏览器停止键VK_BROWSER_SEARCH和0xAA浏览器搜索键VK_BROWSER_FAVORITES是0xAB浏览器收藏夹键VK_BROWSER_HOME0xAC浏览器开始和主页键VK_VOLUME_MUTE0xAD,将音量静音键VK_VOLUME_DOWN0xAE降低音量键VK_VOLUME_UP0xAF执行提高音量键VK_MEDIA_NEXT_TRACK0XB0下一曲目键VK_MEDIA_PREV_TRACK0xB1上一曲目键VK_MEDIA_STOP0xB2停止媒体键VK_MEDIA_PLAY_PAUSE0xB3播放/暂停媒体键VK_LAUNCH_MAIL0xB4启动邮件密钥VK_LAUNCH_MEDIA_SELECT0xB5执行选择媒体键VK_LAUNCH_APP10xB6启动应用程序1键VK_LAUNCH_APP20xB7启动应用程序2密钥**-**0xB8-B9保留的VK_OEM_10xBA用于杂项字符; 它可以因键盘而异。 对于美国标准键盘,使用’;:'键VK_OEM_PLUS为0xBB对于任何国家/地区,请使用“+”键VK_OEM_COMMA0xBC对于任何国家/地区,请使用“,”键VK_OEM_MINUS0xBD对于任何国家/地区,请使用“ - ”键VK_OEM_PERIOD0xBE对于任何国家/地区,’。’ 键VK_OEM_2为0xBF用于杂项字符; 它可以因键盘而异。 对于美国标准键盘,’/?’ 键VK_OEM_3将0xC0用于杂项字符; 它可以因键盘而异。 对于美国标准键盘,使用’〜'键**-**0xC1-D7保留的**-**0xD8-DA未分配VK_OEM_4位于0xDB用于杂项字符; 它可以因键盘而异。 对于美国标准键盘,’[{'键VK_OEM_5的0xDC用于杂项字符; 它可以因键盘而异。 对于美国标准键盘,’\ |’ 键VK_OEM_60xDD用于杂项字符; 它可以因键盘而异。 对于美国标准键盘,使用’]}'键VK_OEM_7写0xDE用于杂项字符; 它可以因键盘而异。 对于美国标准键盘,“单引号/双引号”键VK_OEM_80xDF用于杂项字符; 它可以因键盘而异。**-**取0xE0保留的0xE1OEM特定VK_OEM_1020xE2RT 102键键盘上的尖括号键或反斜杠键0xE3-E4OEM特定VK_PROCESSKEY为0xE5IME PROCESS键0xE6OEM特定VK_PACKET0xE7用于传递Unicode字符,就像它们是击键一样。VK_PACKET键是用于非键盘输入方法的32位虚拟键值的低位字。有关更多信息,请参阅KEYBDINPUT,SendInput,WM_KEYDOWN和WM_KEYUP中的备注**-**0xE8未分配0xE9-F5OEM特定VK_ATTN0xF6关键VK_CRSEL0xF7CrSel密钥VK_EXSEL0xF8的ExSel密钥VK_EREOF0xF9擦除EOF键VK_PLAY0xFA回应播放键VK_ZOOM0xFB的才能缩放键VK_NONAME0xFC有保留的VK_PA10xFDPA1键VK_OEM_CLEAR0xFE的清除键官方参考手册: https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
从控制台输入缓冲区读取数据并将其从缓冲区中删除。
函数声明:
BOOL WINAPI ReadConsoleInput( _In_ HANDLE hConsoleInput, _Out_ PINPUT_RECORD lpBuffer, _In_ DWORD nLength, _Out_ LPDWORD lpNumberOfEventsRead ); 功能: 从控制台输入缓冲区读取数据并将其从缓冲区中删除。 参数: hConsoleInput 控制台输入缓冲区的句柄。句柄必须具有GENERIC_READ访问权限。 lpBuffer 指向接收输入缓冲区数据的INPUT_RECORD结构数组的指针。 nLength 数组元素中lpBuffer参数 指向的数组大小。 lpNumberOfEventsRead 指向接收读取的输入记录数的变量的指针。 返回值: 如果函数成功,则返回值为非零值。 如果函数失败,则返回值为零。要获取扩展错误信息,请调用GetLastError。官方参考网址:https://docs.microsoft.com/en-us/windows/console/readconsoleinput
示例程序一:
用户按下ESC键,则终端输出ESC
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> #include <Windows.h> #include <conio.h> int main(void) { //定义句柄变量 HANDLE hOut = NULL; HANDLE hIn = NULL; //定义输入事件结构体 INPUT_RECORD keyRecord; //用于存储读取记录 DWORD res; //获取标准输出句柄 hOut = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输入句柄 hIn = GetStdHandle(STD_INPUT_HANDLE); while (1) { //读取输入事件 ReadConsoleInput(hIn, &keyRecord, 1, &res); //如果当前事件是键盘事件 if (keyRecord.EventType == KEY_EVENT) { //单击鼠标左键 if (keyRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) { printf("用户按下了ESC键"); } } } //关闭句柄 CloseHandle(hOut); CloseHandle(hIn); //system("pause"); getchar(); return 0; }在上面的样例程序中,当你按下Esc键后又马上释放,程序会输出两次Esc,因为有两次事件的虚拟键代码都是Esc键的代码,一次是按下,一次是释放。如果要实现按下键后出现反应,释放不出现反应。
代码优化如下:
//如果当前事件是键盘事件 if (keyRecord.EventType == KEY_EVENT) { //单击按键左键 如果是按下就输出, 如果是释放就不输出 if (keyRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE && keyRecord.Event.KeyEvent.bKeyDown == 1) { printf("用户按下了ESC键"); } }示例程序二:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> #include <Windows.h> #include <conio.h> int main(void) { //定义句柄变量 HANDLE hOut = NULL; HANDLE hIn = NULL; //定义输入事件结构体 INPUT_RECORD keyRecord; //用于存储读取记录 DWORD res; //获取标准输出句柄 hOut = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输入句柄 hIn = GetStdHandle(STD_INPUT_HANDLE); while (1) { //读取输入事件 ReadConsoleInput(hIn, &keyRecord, 1, &res); //如果当前事件是键盘事件 if (keyRecord.EventType == KEY_EVENT) { //单击按键左键 如果是按下就输出, 如果是释放就不输出 if (keyRecord.Event.KeyEvent.wVirtualKeyCode == 'B' && keyRecord.Event.KeyEvent.bKeyDown == 1) { if (keyRecord.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) { printf("B"); } else { printf("b"); } } } } //关闭句柄 CloseHandle(hOut); CloseHandle(hIn); //system("pause"); getchar(); return 0; }【注意】
各个控制键状态的的确定并不是使用等于符号==而是按位与&运算符,因为在同一时刻可能有多种控制键状态值,比如各种锁定都被打开且各种控制键也被同时按下。因为使用位操作,方便查询各个控制键的状态而不使之出现冲突。