zoukankan      html  css  js  c++  java
  • 【C语言】控制台窗口图形界面编程(八):键盘事件

    00. 目录

    01. INPUT_RECORD结构

    描述控制台输入缓冲区中的输入事件。可以使用ReadConsoleInputPeekConsoleInput函数从输入缓冲区读取这些记录,也可以使用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成员指定的事件类型。

    02. KEY_EVENT_RECORD结构

    描述控制台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×05 X1鼠标按钮
    VK_XBUTTON2 0×06 X2鼠标按钮
    **- **0×07 未定义
    VK_BACK0x08的 BACKSPACE键
    VK_TAB×09 TAB键
    -0x0A至0B 保留的
    VK_CLEAR0x0C 清除键
    VK_RETURN0X0D 回车键
    -为0x0E-0F 未定义
    VK_SHIFT为0x10 SHIFT键
    VK_CONTROL为0x11 CTRL键
    VK_MENU0×12 ALT键
    VK_PAUSE0×13 暂停键
    VK_CAPITAL0×14 CAPS LOCK键
    -0x1A的 未定义
    VK_ESCAPE0x1B ESC键
    VK_CONVERT为0x1C IME转换
    VK_NONCONVERT0x1D IME非转换
    VK_ACCEPT0X1E IME接受
    VK_MODECHANGE为0x1F IME模式更改请求
    VK_SPACE为0x20 空格键
    VK_PRIOR为0x21 PAGE UP键
    VK_NEXT为0x22 PAGE DOWN键
    VK_END0×23 结束键
    VK_HOME0X24 Home键
    VK_LEFT0x25 左箭头键
    VK_UP0×26 向上箭头键
    VK_RIGHT0×27 右箭头键
    VK_DOWN0×28 向下箭头键
    VK_SELECT0x29 SELECT键
    VK_PRINT0x2A 打印键
    VK_EXECUTE0x2B访问 执行键
    VK_SNAPSHOT0x2c上 PRINT SCREEN键
    VK_INSERT0x2D INS键
    VK_DELETE0x2E之间 DEL键
    VK_HELP值为0x2F 帮助键
    的0x30 0键
    0X31 1键
    0x32 2键
    0x33 3键
    0x34 4键
    0x35 5键
    0x36 6键
    0×37 7键
    0x38 8键
    0x39 9键
    -0x3A-40 未定义
    的0x41 关键
    的0x42 B键
    0x43中 C键
    0×44 D键
    0×45 E键
    0×46 F键
    0X47 G键
    0x48 H键
    ×49 我关键
    0x4A J键
    0x4B K键
    0x4C L键
    送出0x4d M键
    0x4E N键
    0x4F 哦关键
    为0x50 P键
    0x51 Q键
    0×52 R键
    0x53 S键
    0x54 T键
    0x55的 U键
    0x56储存 V键
    的0x57 W键
    将0x58 X键
    0×59 Y键
    0x5A Z键
    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_F10x70 F1键
    VK_F20x71 F2键
    VK_F30x72 F3键
    VK_F40x73 F4键
    VK_F50x74 F5键
    VK_F60x75 F6键
    VK_F70x76 F7键
    VK_F80x77 F8键
    VK_F90x78 F9键
    VK_F100x79的 F10键
    VK_F110x7A F11键
    VK_F120x7B F12键
    VK_F130x7C F13键
    VK_F140x7D F14键
    VK_F15的0x7E F15键
    VK_F160x7F的 F16键
    VK_F170x80的 F17键
    VK_F180×81 F18键
    VK_F19为0x82 F19键
    VK_F200×83 F20键
    VK_F21的0x84 F21键
    VK_F220x85 F22键
    VK_F230x86可以 F23键
    VK_F2487H的 F24键
    -0x88-8F 未分配
    VK_NUMLOCK的0x90 NUM LOCK键
    VK_SCROLL0x91 滚动锁定键
    0x92-96 OEM特定
    -0x97-9F 未分配
    VK_LSHIFT0XA0 左SHIFT键
    VK_RSHIFT0xA1 右SHIFT键
    VK_LCONTROL0xA2 左控制键
    VK_RCONTROL0xA3执行 右控制键
    VK_LMENU0xA4 左MENU键
    VK_RMENU的0xA5 右键MENU
    VK_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 保留的
    0xE1 OEM特定
    VK_OEM_1020xE2 RT 102键键盘上的尖括号键或反斜杠键
    0xE3-E4 OEM特定
    VK_PROCESSKEY为0xE5 IME PROCESS键
    0xE6 OEM特定
    VK_PACKET0xE7 用于传递Unicode字符,就像它们是击键一样。VK_PACKET键是用于非键盘输入方法的32位虚拟键值的低位字。有关更多信息,请参阅KEYBDINPUTSendInputWM_KEYDOWNWM_KEYUP中的备注
    -0xE8 未分配
    0xE9-F5 OEM特定
    VK_ATTN0xF6 关键
    VK_CRSEL0xF7 CrSel密钥
    VK_EXSEL0xF8的 ExSel密钥
    VK_EREOF0xF9 擦除EOF键
    VK_PLAY0xFA回应 播放键
    VK_ZOOM0xFB的才能 缩放键
    VK_NONAME0xFC有 保留的
    VK_PA10xFD PA1键
    VK_OEM_CLEAR0xFE的 清除键

    官方参考手册: https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes

    03. ReadConsoleInput函数

    从控制台输入缓冲区读取数据并将其从缓冲区中删除。

    函数声明:

    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

    04. 示例程序

    示例程序一:

    用户按下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;
    }
    
    
    

    【注意】

    各个控制键状态的的确定并不是使用等于符号==而是按位与&运算符,因为在同一时刻可能有多种控制键状态值,比如各种锁定都被打开且各种控制键也被同时按下。因为使用位操作,方便查询各个控制键的状态而不使之出现冲突。

    宝剑锋从磨砺出,梅花香自苦寒来。
  • 相关阅读:
    Unity AnimatorController注意事项
    OpenGL ES入门详解
    手游性能优化之深入理解Texture Compression
    Unity2016 Unity3D开发VR游戏的经验
    U3D手游《苍穹变》性能优化经验谈
    unity5之代码创建状态机,玩的666
    Unity IK(反向运动学)初探
    根运动 (Root Motion) – 工作原理
    一些传感器相关的文章
    陀螺仪与加速传感器数据的融合算法解析
  • 原文地址:https://www.cnblogs.com/szitcast/p/10924434.html
Copyright © 2011-2022 走看看