已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第四讲:键盘事件【事件驱动】所谓的事件驱动其实就是当满足什么样的条件下发生另外一件事情。比如当你按下按钮时就会执行相应的代码一样。由于控制台程序在同一个时刻只能够执行一个任务,这就造成了在处理事件的效率上太过于低下,通常现代的程序都是面向多任务的,也就是说同一个时间段可以完成好几个功能,那么如何才能够做到这一点呢?就依赖于事件驱动机制。理解事件驱动就必须要先理解事件,所谓的事件(Event)其实就是触发某样事情发生的条件,例如键盘按下、单击按钮、双击图标等等。这些称之为事件。而当这些事件发生之后,就会触发另外一件事情。例如当我们点击“百度搜索”按钮时就会跳转到搜索的结果界面一样。当然,采用事件驱动的直接原因就是最大化利用CPU,由于控制台程序的限制,我们不能够完成多任务的操作(早期的DOS操作系统是单用户单任务的,即同一个时刻只能够完成一个任务,效率很慢)故此我们需要事件驱动这样的机制为我们提高效率,为我们最大化利用CPU资源。简而言之,事件驱动就是一个用于提高程序效率的机制。如果上述还没有让你明白过来,你可以看看百度百科上的解释,如下:所谓事件驱动,简单地说就是你点什么按钮(即产生什么事件),电脑执行什么操作(即调用什么函数).当然事件不仅限于用户的操作. 事件驱动的核心自然是事件。从事件角度说,事件驱动程序的基本结构是由一个事件收集器、一个事件发送器和一个事件处理器组成。事件收集器专门负责收集所有事件,包括来自用户的(如鼠标、键盘事件等)、来自硬件的(如时钟事件等)和来自软件的(如操作系统、应用程序本身等)。事件发送器负责将收集器收集到的事件分发到目标对象中。事件处理器做具体的事件响应工作,它往往要到实现阶段才完全确定,因而需要运用虚函数机制(函数名往往取为类似于HandleMsg的一个名字)。对于框架的使用者来说,他们唯一能够看到的是事件处理器。这也是他们所关心的内容。【程序查询方式】通常检测事件有两种方法,一种称为程序查询法,一种称之为程序中断法。由于在控制台中我们无法直接使用系统中断(系统中断只有汇编语言可以直接使用),因此我们无法在高级语言中使用程序中断法检测指令。故此只能够使用程序查询方式进行事件的检测。所谓的程序查询方式实际上是利用一个死循环不停地对事件进行查询,如果事件发生则执行相应的代码,当代码执行结束之后继续开始下一轮的查询,由于CPU的计算速度相当快,你不用担心会有延时的问题。这样一轮一轮查询的方式,我们称之为程序查询方式,也叫轮询法。程序查询法的流程图如下:【键盘按下事件】所谓的键盘事件,是指无论在何时只要键盘按键被按下,即可被程序所截获,并执行相应的功能代码。故此负责监听键盘事件的API函数会一直处于工作状态,在MFC中我们可以通过死循环进行操作,当然也可以通过我们即将接触到的多线程编程进行操作。在这里我们介绍如何利用死循环监听键盘。【DWORD类型】在MFC中,通常会见到DWORD类型,所谓的DWORD类型就是Double Word类型,即双字节类型,MFC中将unsigned long类型使用typedef关键字重新制定为DWROD类型。MFC框架中的声明如下:typedef unsigned long DWORD; 故此,DWROD类型的本质其实是一个无符号的长整型数。在MFC中我们可以使用DWORD类型表示任何双字节的数据。这里笔者将不再重复如何使用DWORD类型的变量的方法。【INPUT_RECORD结构体】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; 当然上述的结构体不像一般的结构体,它有一些复杂,但是也不影响我们的使用,在此要多说一句的是union一词,union也是C/C+语言中的关键字,用于描述“共用体”类型,所谓的共用体实际上是指在进行某些算法编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体。也被称之为“联合体”。它是早期的C语言过渡到C+中的产物。当然这里我们只需要了解一下就行,并不需要做太多的深究。【事件类型】INPUT_RECORD结构体中的EnventType成员用于说明事件的类型,通常取值如下:事件取值相关描述FOCUS_EVENT摄像头事件,控制对摄像头的操作KEY_EVENT键盘事件,控制对键盘的操作MENU_EVENT菜单事件,控制对UI中菜单的操作MOUSE_EVENT鼠标事件,控制对鼠标的操作WINDOW_BUFFER_SIZE_EVENT窗体缓冲事件小提示:EventType 有5种事件,对应五个 RECORD。所以当要使用的是键盘事件时,应该先判断 EventType 是否为 KeyEvent,然后使用 KEY_EVENT_RECORD,判断现在的键盘是什么情况。其他事件也是一样的(一般只使用键盘和鼠标事件)。键盘事件通常有字符事件和按键事件。之所以称为事件,当它们被按下时,事件被激发。【KEY_EVENT_RECORD结构体】KEY_EVENT_RECORD用于记录键盘事件的情况,当有键盘事件发生时,我们就可以使用该结构获取此时键盘的情况。KEY_EVENT_RECORD结构体声明如下;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; 【虚拟键码】接下来为大家介绍一下虚拟键码的概念,由于键盘上的一些特殊键,例如ctrl、alt、shift、enter等键不能够直接被控制台程序所识别,故此在MFC中引入了虚拟键码的概念。虚拟指的是假定存在于思想中而不是现实世界中的一些事物,也只有熟练使用DOS组合语言编写应用程式的程式写作者才有可能指出,为什么对Windows键盘处理如此基本的键码是虚拟的而不是真实的。对於早期的程序员来说,真实的键码由实际键盘硬体产生。在Windows文件中将这些键码称为扫描码(scan codes)。在IBM相容机种上,扫描码16是Q键,17是W键,18是E、19是R,20是T,21是Y等等。这时您会发现,扫描码是依据键盘的实际布局的。Windows开发者认为这些代码过於与设备相关了,於是他们试图通过定义所谓的虚拟键码,以便经由与装置无关的方式处理键盘。其中一些虚拟键码不能在IBM相容机种上产生,但可能会在其他制造商生产的键盘中找到,或者在未来的键盘上找到。提出虚拟键盘码的好处就在于可以兼容不同布局的键盘。(不要忘记即使是笔记本电脑也有小键盘和大键盘之分的哦!)常用的虚拟键盘码如下:十进制十六进制WINUSER.H识别字IBM相容键盘88VK_BACKBackspace99VK_TABTab120CVK_CLEARLock关闭时的数字键盘5130DVK_RETURNEnter1610VK_SHIFTShift1711VK_CONTROLCtrl1812VK_MENUAlt1913VK_PAUSEPause2014VK_CAPITALCaps Lock271BVK_ESCAPEEsc3220VK_SPACESpacebar3321VK_PRIORPage Up3422VK_NEXTPage Down3523VK_ENDEnd3624VK_HOMEHome3725VK_LEFT左箭头3826VK_UP上箭头3927VK_RIGHT右箭头4028VK_DOWN下箭头4129VK_SELECT422AVK_PRINT432BVK_EXECUTE442CVK_SNAPSHOTPrint Screen452DVK_INSERTInsert462EVK_DELETEDelete472FVK_HELP915BVK_LWIN左Windows键925CVK_RWIN右Windows键1066AVK_MULTIPLY数字键盘上的*1076BVK_ADD数字键盘上的+1086CVK_SEPARATOR1096DVK_SUBTRACT数字键盘上的-1106EVK_DECIMAL数字键盘上的.1116FVK_DIVIDE数字键盘上的/上述是在MFC中常用的一些虚拟键码,更多的大家可以到网上进行查询。使用虚拟键码读者需要注意以下的几个要点:1、 Windows下的程序通常不需要监视shift、ctrl或alt键的状态2、 键盘上的字母和数字使用其ASCII码直接表示,而不采用虚拟键码3、 Windows操作系统中使用VK_LWIN以及VK_RWIN两个键打开“开始菜单”或者是启动“工作管理员模式”,故此需要谨慎使用这两个虚拟键码。4、 对于键盘上的功能键(F1 F12)一般不进行处理,当然虚拟键码表中提供了24个功能键的编码。【键盘事件的操作步骤】键盘事件的操作步骤如下:while(1)监听键盘;if(有键盘事件发生)if(键盘上有按键被按下)执行被触发的功能代码;【监听键盘事件】在MFC框架中通常使用ReadConsoleInput函数对键盘事件进行侦听,并通过形参将侦听到的结果保存在INPUT_RECORD结构体中。函数声明如下:BOOL ReadConsoleInput( HANDLE hConsoleInput, / 输入设备句柄 PINPUT_RECORD lpBuffer, / 返回数据记录 DWORD nLength, / 要读取的记录数 LPDWORD lpNumberOfEventsRead / 返回已读取的记录数 ); 【判断是否有键盘事件发生】判断是否有键盘事件发生通常使用INPUT_RECORD结构体中的EnventType进行判断,如果该成员的值与KEY_ENVENT(键盘事件)等价时,则证明发生了键盘事件,即:if(rec.EventType = KEY_EVENT)/如果捕捉到了键盘事件cout发生了键盘事件!endl;【判断是否有键被按下】那么如何判断键盘上是否有键被按下呢?这很简单,我们需要通过判断INPUT_RECORD结构体中的成员Event中的KeyEvent中的成员bKeyDown(即Bool KeyDown)是否为true即可。即:if(rec.Event.KeyEvent.bKeyDown = true)/如果此时有键按下cout”有键被按下!”endl;【判断键盘按下的键值】那么我们怎么才能够知道到底是哪个键被按下呢?此时我们可以通过KeyEvent成员中的uChar成员获取该键的ASCII码或者是Unicode编码,进行判断。获取该键的ASCII码的代码为:char c = rec.Event.KeyEvent.uChar.AsciiChar;/获取该键的ASCII码获取该键的Unicode编码的代码为:WCHAR ch = rec.Event.KeyEvent.uChar.UnicodeChar;通常我们使用ASCII码判断该键。例 键盘事件监听小例子#include #include using namespace std;void main()HANDLE in = GetStdHandle(STD_INPUT_HANDLE);/获取键盘句柄INPUT_RECORD rec;/保存键盘事件结果的结构体DWORD recCount;/已读取的记录数while(1)/始终循环监听ReadConsoleInput(in, &rec, 1, &recCount);/侦听键盘事件if(rec.EventType = KEY_EVENT)/如果捕捉到了键盘事件if(rec.Event.KeyEvent.bKeyDown = true)/如果此时有键按下char c = rec.Event.KeyEvent.uChar.AsciiChar;/获取该键的ASCII码putchar(c);/打印该键运行效果如下:当然,光看图是不行的,还需要读者自己去运行代码体会代码中的含义。【键盘事件综合案例】此处笔者提供一个综合案例供大家练习和参考!该案例是一个简单的文本编辑器,可以模拟打字、按backspace退格删除、空格、按esc退出等功能。#include #include #include using namespace std;void main()HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);/获取控制台输出句柄HANDLE in = GetStdHandle(STD_INPUT_HANDLE);/获取控制台输出句柄DWORD dwRes,dwState = 0;COORD crHome = 0,0,crPos;INPUT_RECORD keyRec;CONSOLE_SCREEN_BUFFER_INFO bInfo;cout欢迎您使用基于控制台的文本编辑器!endl;cout请按任意键继续!endl;getch();system(cls);while(1) ReadConsoleInput(in,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年广西安全工程职业技术学院单招职业适应性测试必刷测试卷附答案
- 2026年郑州轨道工程职业学院单招职业适应性测试题库新版
- 2026年安徽林业职业技术学院单招职业适应性考试题库新版
- 2026年重庆市广元市单招职业适应性考试必刷测试卷及答案1套
- 2026年江西省九江市单招职业适应性考试题库新版
- 2026年三亚市单招职业适应性考试必刷测试卷附答案
- 2026年株洲师范高等专科学校单招职业倾向性测试必刷测试卷及答案1套
- 2026年萍乡卫生职业学院单招职业技能考试题库必考题
- 2026年黑龙江交通职业技术学院单招职业倾向性测试题库新版
- 2026年长沙卫生职业学院单招职业倾向性测试题库及答案1套
- 沥青混凝土供货方案及保障措施
- “苏超”现象:文化破圈、城市崛起与青年力量的融合交响-2026年高考语文作文热点话题素材积累与实战训练
- 内蒙古:行业用水定额(DB15-T 385-2020)
- 2025年人力资源管理考试题及答案电大
- 2025全球汽车供应链核心企业竞争力白皮书
- 拆迁拆除作业人员配置及机械设备安排
- 漳州里民宿管理暂行办法
- 容量规划优化-洞察及研究
- 氨机房安全管理制度
- 口腔医学简答题及答案卫生高级职称考试(副高)
- 爆破保管员复训考试题及答案
评论
0/150
提交评论