本文为转载文档,原文链接为:http://blog.csdn.net/bnb45/article/details/8035346
读取键盘操作指的是,当我们输入什么的时候,控制台可以通过函数截获,这时候可以在里面写下要进行的操作。因为键盘的操作是连续的,读取键盘操作的函数也要一直处于监听的状态,而不同的程序所需要的操作代码又不一样,所以暂时没打算封装在类当中。
打开的时候在第一行显示电脑当前三个灯的状态,关着还是亮着的。当状态改变,内容也会改变。光标停在第二行开端,可以输入字母,可以按回车,可以输空格,可以删除当前行字母。
键盘事件通常有字符事件和按键事件。之所以称为事件,当它们被按下时,事件被激发。相关的API函数为:ReadConsoleInput。
[cpp] view plaincopy
- BOOL ReadConsoleInput(
- HANDLE hConsoleInput, // 输入设备句柄
- PINPUT_RECORD lpBuffer, // 返回数据记录
- DWORD nLength, // 要读取的记录数
- LPDWORD lpNumberOfEventsRead // 返回已读取的记录数
- );
关键结构 INPUT_RECORD 如下:
[cpp] view plaincopy
- 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 ----
- FOCUS_EVENT
- KEY_EVENT // 键盘事件
- MENU_EVENT
- MOUSE_EVENT // 鼠标事件
- WINDOW_BUFFER_SIZE_EVENT
EventType 有5种事件,对应下面的五个 RECORD。所以当要使用的是键盘事件时,应该先判断 EventType 是否为 KeyEvent,然后使用 KEY_EVENT_RECORD,判断现在的键盘是什么情况。其他事件也是一样的(一般只使用键盘和鼠标事件)。键盘记录结构如下:
[cpp] view plaincopy
- typedef struct _KEY_EVENT_RECORD
- {
- BOOL bKeyDown; // TRUE表示键按下,FALSE表示键释放
- WORD wRepeatCount; // 按键次数
- WORD wVirtualKeyCode; // 虚拟键代码
- WORD wVirtualScanCode; // 虚拟键扫描码
- union {
- WCHAR UnicodeChar; // 宽字符
- CHAR AsciiChar; // ASCII字符
- } uChar; // 字符
- DWORD dwControlKeyState; // 控制键状态
- }
- KEY_EVENT_RECORD;
bKeyDown 为 TRUE,代表此次事件中有按键被按下;wVirtualKeyCode 为虚拟键代码,在VC++中,最常用的虚拟键代码已被定义在Winuser.h中。例如:VK_SHIFT 代表 SHIFT 键,VK_F1 表示 F1 等(更多参照虚拟键码表)。如果键盘按下的是字符,可以从 uChar 里取出,这里的字符也可以是宽字符。最后一个 dwControlKeyState 为控制键状态,可以是以下中的一个或者多个值的组合:
控制键状态码 | 说明 |
CAPSLOCK_ON | CAPS LOCK 灯亮 |
NUMLOCK_ON | NUM LOCK 灯亮 |
SCROLLLOCK_ON | SCROLL LOCK 灯亮 |
ENHANCED_KEY | 按下扩展键 |
LEFT_ALT_PRESSED | 按下左 ALT 键 |
LEFT_CTRL_PRESSED | 按下左 CTRL 键 |
RIGHT_ALT_PRESSED | 按下右 ALT 键 |
RIGHT_CTRL_PRESSED | 按下右 CTRL 键 |
SHIFT_PRESSED | 按下 SHIFT 键 |
[cpp] view plaincopy
- #include <windows.h>
- #include <stdio.h>
- int main(void)
- {
- // 获取标准输入输出设备句柄
- HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
- HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
- DWORD dwRes, dwState=0;
- INPUT_RECORD keyRec;
- COORD crHome={0, 0}, crPos;
- bool bCaps, bNum, bScroll;
- char ch;
- CONSOLE_SCREEN_BUFFER_INFO bInfo;
- // 输出三个灯的初始状态
- printf("状态:CAPS LOCK:CLOSE NUM LOCK:CLOSE SCROLL LOCK:CLOSE\n");
- while (1) // 消息循环
- {
- ReadConsoleInput(hIn, &keyRec, 1, &dwRes);
- if (keyRec.EventType == KEY_EVENT)
- {
- // 只在按下时判断,弹起时不判断
- if (keyRec.Event.KeyEvent.bKeyDown)
- {
- // 当三个灯的状态发生改变
- if (dwState != keyRec.Event.KeyEvent.dwControlKeyState)
- {
- dwState = keyRec.Event.KeyEvent.dwControlKeyState;
- bCaps = bNum = bScroll = false;
- // 判断三个灯是否有亮
- if (dwState & CAPSLOCK_ON)
- {
- bCaps = true;
- }
- if (dwState & NUMLOCK_ON)
- {
- bNum = true;
- }
- if (dwState & SCROLLLOCK_ON)
- {
- bScroll = true;
- }
- // 得到控制台信息(包括输出前光标的位置)
- GetConsoleScreenBufferInfo(hOut, &bInfo);
- SetConsoleCursorPosition(hOut,crHome);
- // 输出三个灯的状态
- printf("状态:CAPS LOCK:%s NUM LOCK:%s SCROLL LOCK:%s\n",
- bCaps?"OPEN ":"CLOSE",
- bNum?"OPEN ":"CLOSE",
- bScroll?"OPEN ":"CLOSE");
- // 还原光标位置
- SetConsoleCursorPosition(hOut, bInfo.dwCursorPosition);
- }
- // -- 基础功能键
- switch(keyRec.Event.KeyEvent.wVirtualKeyCode)
- {
- case VK_RETURN: // 按回车时跳到下一行
- printf("\n");
- break;
- case VK_SPACE: // 按空格时输出一个空格
- printf(" ");
- break;
- case VK_BACK: // 按删除时删掉一个字符(只能当前行操作)
- GetConsoleScreenBufferInfo(hOut, &bInfo);
- crPos = bInfo.dwCursorPosition;
- if (crPos.X!=0)
- {
- crPos.X -= 1;
- }
- SetConsoleCursorPosition(hOut,crPos);
- printf(" ");
- SetConsoleCursorPosition(hOut,crPos);
- break;
- case VK_ESCAPE: // 按ESC键时退出
- CloseHandle(hOut); // 关闭标准输出设备句柄
- CloseHandle(hIn); // 关闭标准输入设备句柄
- return 0;
- default:
- break;
- }
- // -- 打印字符
- ch = keyRec.Event.KeyEvent.uChar.AsciiChar;
- // 输出可以打印的字符(详参ASCII表)
- if (ch>0x20 && ch<0x7e)
- {
- putchar(ch);
- }
- }
- }
- }
- return 0;
- }