【C语言】控制台窗口图形界面编程(八):键盘事件
00. 目录
01. INPUT_RECORD结构
描述控制台输入缓冲区中的输入事件。可以使用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成员指定的事件类型。
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位虚拟键值的低位字。有关更多信息,请参阅KEYBDINPUT,SendInput,WM_KEYDOWN和WM_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;
}
【注意】
各个控制键状态的的确定并不是使用等于符号==而是按位与&运算符,因为在同一时刻可能有多种控制键状态值,比如各种锁定都被打开且各种控制键也被同时按下。因为使用位操作,方便查询各个控制键的状态而不使之出现冲突。
【C语言】控制台窗口图形界面编程(八):键盘事件的更多相关文章
- C语言控制台窗体图形界面编程(总结)
本系列文章是笔者通过学习<C语言控制台窗体界面编程(修正版)>而写(关于此文档的很多其它信息请看本系列文章第一篇),旨在让大家更加清晰简洁easy地学习C语言控制台窗体界面的编程. 通过本 ...
- 【C语言】控制台窗口图形界面编程(二)窗口信息和填充缓冲区
目录 00. 目录 01. COORD结构体 02. SMALL_RECT结构 03. CONSOLE_SCREEN_BUFFER_INFO结构体 04. GetConsoleScreenBuffer ...
- C语言控制台窗体图形界面编程(八):鼠标事件
上次讲的是键盘事件,这次我们介绍鼠标事件. 以下先介绍下鼠标事件的结构体以及相关信息. typedef struct _MOUSE_EVENT_RECORD //鼠标事件结构体 { CO ...
- 【C语言】控制台窗口图形界面编程(七):鼠标事件
目录 00. 目录 01. INPUT_RECORD结构 02. MOUSE_EVENT_RECORD结构 03. ReadConsoleInput函数 04. 示例程序 00. 目录 01. INP ...
- 【C语言】控制台窗口图形界面编程(一)句柄和文本属性
目录 00. 目录 01. 句柄 02. GetStdHandle函数 03. CloseHandle函数 04. SetConsoleTextAttribute函数 05. 十进制颜色对照表 06. ...
- 【C语言】控制台窗口图形界面编程(五):文本移动
目录 00. 目录 01. CHAR_INFO结构 02. ScrollConsoleScreenBuffer函数 03. 程序示例 04. 官方参考程序 00. 目录 01. CHAR_INFO结构 ...
- 【C语言】控制台窗口图形界面编程(四):文本输出
目录 00. 目录 01. FillConsoleOutputAttribute函数 02. FillConsoleOutputCharacter函数 03. WriteConsoleOutputCh ...
- 【C语言】控制台窗口图形界面编程(六):光标设置
目录 00. 目录 01. CONSOLE_CURSOR_INFO结构 02. GetConsoleCursorInfo函数 03. SetConsoleCursorInfo函数 04. SetCon ...
- Linux C 程序 GTK+图形界面编程(22)
GTK+图形界面编程 Linux大多是在字符界面,但也可以开发图形界面 目前已经存在多种Linux下开发图形界面的程序开发包:最常用的是Qt和GTK+ Qt是一个跨平台的图形界面开发库,不仅仅支持Li ...
随机推荐
- Java语法基础练习2
---恢复内容开始--- 1.仔细阅读示例:EnumTest.java分析结果 代码: 运行结果: 分析:枚举类型就是一个类,枚举中的常量就是枚举类型中的实例,可把字符串转化为枚举:而且他本身是一个类 ...
- Python sklearn Adaboost
1. Adaboost类库概述 scikit-learn中Adaboost类库比较直接,就是AdaBoostClassifier和AdaBoostRegressor两个,从名字就可以看出AdaBoos ...
- P2093 [国家集训队]JZPFAR(KDTree)
传送门 类似于p4357 不过因为距离相等的时候要优先选择序号小的,所以要重载一下运算符 //minamoto #include<bits/stdc++.h> #define R regi ...
- [App Store Connect帮助]七、在 App Store 上发行(1)App 发行流程概述
在 App Store 上发行 App 的一般流程如下. 第 1 步:选择您的构建版本 每个 App 都可以有多个版本,且每个版本也可以有多个构建版本.若要在 App Store 上发行您的 App, ...
- Ocelot(一)- .Net Core开源网关
Ocelot - .Net Core开源网关 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10857688.html 源码地 ...
- VI/VIM修改Tab为4个空格
配置方法 在当前用户目录下创建或修改~/.vimrc Root用户下修改/etc/virc 和 /etc/vimrc set ts= set softtabstop= set expandtab se ...
- linux 正确的关机方法
正确的关机方法 1. 查看系统的使用状态 执行who命令或者netstat -a ,要查看后台执行的程序可以执行“ps -aux” 2. 正确的关机命令 1)将内存中数据同步写入磁盘:sync,这个命 ...
- flask请求访问数据
flask请求访问数据 在flask框架中,访问请求数据由全局的request对象来提供,在flask框架中,request对象具有 全局作用域: from flask import request ...
- [POI2012]Vouchers
Description 考虑正整数集合,现在有n组人依次来取数,假设第i组来了x人,他们每个取的数一定是x的倍数,并且是还剩下的最小的x个. 正整数中有m个数被标成了幸运数,问有哪些人取到了幸运数. ...
- [POI2007]大都市meg
Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了.不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1..n ...