Windows控制台输入

本文详细介绍了如何处理Windows控制台中的用户输入,包括KeyEvent、MouseEvent、WindowBufferSizeEvent、MenuEvent和FocusEvent。通过ReadConsoleInput函数,可以读取并响应键盘、鼠标等事件。特别地,针对Ctrl+C/Break的特殊处理方式以及在不同事件下的应用示例被详细阐述。此外,还提出了几个实践任务,如实现彩色画图并支持Ctrl+C退出。
摘要由CSDN通过智能技术生成

在Windows控制台中,我们通常要处理一些用户输入,例如按键,鼠标(不常用,但是有),缓冲区更改等。
Windows系统为了减轻程序员的负担,提供了ReadConsoleInput函数
docs.microsoft.com中这样描述ReadConsoleInput:

Reads data from a console input buffer and removes it from the buffer.
从一个控制台缓冲区读取数据并将其从缓冲区移除。

在头文件中,ReadConsoleInput有两种可能的声明:

#define ReadConsoleInput ReadConsoleInputA
#define ReadConsoleInput ReadConsoleInputW

Unicode被声明时,为下面一种。

ReadConsoleInputAReadConsoleInputW声明如下:

BOOL WINAPI ReadConsoleInput(
  _In_  HANDLE        hConsoleInput,		//控制台输入句柄,由GetStdHandle获得
  _Out_ PINPUT_RECORD lpBuffer,				//指向INPUT_RECORD(可以为数组)的指针
  _In_  DWORD         nLength,				//接收消息的个数
  _Out_ LPDWORD       lpNumberOfEventsRead	//用于存储成功获取消息个数的指针
);

函数成功,则返回非零值,反之为零。
其中,结构体INPUT_RECORD声明如下:

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取值如下:

#define KEY_EVENT 0x0001
#define MOUSE_EVENT 0x0002
#define WINDOW_BUFFER_SIZE_EVENT 0x0004
#define MENU_EVENT 0x0008
#define FOCUS_EVENT 0x0010

1.KeyEvent

这是最常用的输入事件
KEY_EVENT_RECORD结构体声明如下:

typedef struct _KEY_EVENT_RECORD {
   
    BOOL bKeyDown; 			//指示按键是否按下,对于Ctrl+C/Break无效
    WORD wRepeatCount;		//按键重复次数,不累加
    WORD wVirtualKeyCode;	//虚拟键码
    WORD wVirtualScanCode;	//虚拟扫描码
    union {
   
        WCHAR UnicodeChar;	//Unicode码,ReadConsoleInputW使用
        CHAR  AsciiChar;	//ASCII码,ReadConsoleInputA使用
    } uChar;
    DWORD dwControlKeyState;//控制键状态
} KEY_EVENT_RECORD, *PKEY_EVENT_RECORD;

控制键状态dwControlKeyState可由以下值合并:

标识符 说明
RIGHT_ALT_PRESSED 0x0001 右Alt键被按下
LEFT_ALT_PRESSED 0x0002 左Alt键被按下
RIGHT_CTRL_PRESSED 0x0004 右Ctrl键被按下
LEFT_CTRL_PRESSED 0x0008 左Ctrl键被按下
SHIFT_PRESSED 0x0010 Shift键被按下
NUMLOCK_ON 0x0020 Num Lock状态为开
SCROLLLOCK_ON 0x0040 Scroll Lock状态为开
CAPSLOCK_ON 0x0080 Caps Lock状态为开
ENHANCED_KEY 0x0100 指示该键为拓展键

示例:用户输入q键时退出程序

#include <Windows.h>
int main(){
   
	INPUT_RECORD sinfo;
	DWORD recnum;
	HANDLE hIn=GetStdHandle(STD_OUTPUT_HANDLE);
	while (GetConsoleInput(hIn, &sinfo, 1, &recnum)){
   
		if (sinfo.EventType != KEY_EVENT) continue;//无视其他类型输入
		//判断按键状态(以防按键被触发两次)
		//if (!sinfo.Event.KeyEvent.bKeyDown) continue;
		if (sinfo.Event.KeyEvent.uChar.UnicodeChar == 'q') break;
	}
}

在获取键盘事件时,有一点比较特殊:
用户输入Ctrl+C/Break时,ReadConsoleInput会抛出C++错误,C并不接收C++错误(VS会接收),但此时ReadConsoleInput返回的INPUT_RECORDEvent.KeyEvent.bKeyDown为0,即使Ctrl+C在按下状态

虚拟键码低8位为3(A1->B2->C3,以此推例,Break视作C),第10(RIGHT_CTRL_PRESSED)或第11(LEFT_CTRL_PRESSED)位为1
0000xx00 00000011
所以,接收Ctrl+C/Break退出循环的方法如下

#include <stdio.h>
#include <Windows.h>
BOOL ReceiveHandler(DWORD dwCtrlType);
int main() {
   
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值