当前课程知识点:VC++面向对象与可视化程序设计(上):Windows编程基础 > 第4章 Windows应用程序中的键盘与鼠标 > 4-1 Windows 应用程序中的键盘与鼠标 > 4-1
返回《VC++面向对象与可视化程序设计(上):Windows编程基础》慕课在线视频课程列表
返回《VC++面向对象与可视化程序设计(上):Windows编程基础》慕课在线视频列表
大家好!
我们现在开始新的一讲内容
Windows的应用程序中的键盘与鼠标的应用
这个也是在应用程序编写过程中
经常会碰到的问题
大家知道 你们现在
在应用程序操作过程中
鼠标是不离手的
所以我们就要讲
鼠标的怎么响应的问题
键盘,肯定是少不了的
你们要从键盘里输入命令
进行相应的操作
所以键盘是不可少的
所以我们这一讲
就介绍键盘与鼠标的应用
首先 我们说键盘在应用程序中的应用
大家知道键盘上的键
它对应着唯一的标识值
这个标识值呢它是一个扫描码
是按下或者释放某一个键的时候
要有这个值标识,这一按键以及状态
所以的话
这个扫描码会在按下或释放键的时候产生
那么扫描码是什么呢?
或者说标识值是什么?
扫描码是依赖于具体设备的
为了达到设备无关性的要求
往往使用与具体设备无关的虚拟码
虚拟码是由Windows系统定义的与设备无关的键的标识
关于虚拟码的问题,我们在第二讲里面
曾经给大家做过介绍
那么具体说
设备驱动程序截取键的扫描码
然后翻译成虚拟码
那么由于键盘的输入
这时候它就会产生一条消息
这个消息,就是字符消息
以及按下或放开的动作消息
它就包含了扫描码
虚拟码和其他按键相关的消息
然后,这个消息
就通过设备驱动程序把消息放到系统的消息队列中
Windows就从系统消息队列中取出信息
然后 发送到相应的线程消息队列当中
这样 窗口过程就WndProc了
就取出键盘消息进行处理
那么从这个页面里面
大家就可以看到键盘它所扮演的角色
以及它的执行的过程
虚拟码是一种与设备无关的键盘编码
它的值就存放在键盘消息的字参数wParam中
用来标识哪一个键被按下或者释放
最常用的虚拟码已经在Windows.h中都给了定义
那么在这里面,我列出常用的虚拟码
比如Vitual key就是VK开头的虚拟码
就是鼠标左键LeftButton
比如右键中键还有退格键
这是键盘上的退格键BackSpace
那么这Return就是键盘上的回车键
以及Control、Pause这些
那么大家可以发现
你在键盘上按下了这些键它是实现某一个的功能
并不能在屏幕上显示你按下键的字符信息
而是完成某一个功能的
那么这个时候
这些键都定义成了是虚拟键
那么这样虚拟键
你在消息响应过程中
就可以对这些键
设置相应的消息响应机制
那么操作系统
在接收到键盘的输入之后
就把消息发送给具有输入焦点的窗口
哪一些窗口具有输入焦点呢?
大家知道Windows它是一个多任务的操作系统
也就是说
根据程序执行的需要
它可以在屏幕上出现多个窗口
应用程序,也就是说一般有几个窗口
但当按下某一个键的时候
只有一个窗口能接收到这个键盘的消息
我们说接收这个键盘消息的窗口就称为
具有“输入焦点”的窗口
有“输入焦点”的窗口
应该是活动窗口或者说是活动窗口的子窗口
那窗口函数,就通过捕捉SETFOCUS和KILLFOCUS这个消息
来确定当前的窗口是否具有输入焦点
那么如果是捕获了SETFOCUS消息
说明这个窗口,正在接收输入
那么如果是KILLFOCUS就失去了输入焦点
也就是说这个窗口不能接收输入了
那我们再说键盘消息
键盘消息实际上包含了字符消息和按键消息
一个按键的组合产生了一个可以显示的字符时
就产生了一个字符消息
那么按键消息是什么?
是按下或者松开一个键时产生的按键消息
那么按键消息有非系统的按键消息和系统的按键消息
非系统的按键消息
是不使用Alt键组合的按键消息
而系统键消息是Alt键与相关输入键的组合产生的消息
这些键,一般由Windows系统内部直接处理
应用程序不处理
如果应用程序处理了这些消息
那么还要调用DefWindowsProc()函数
以便不影响系统对它们的处理
那么消息里面呢
系统键消息和非系统消息
比如系统是SYSKEYDOWN和SYSKEYUP这两个都是系统消息
那么按下系统键消息
KEYUP和KEYDOWN的话,是非系统键消息
那么按键消息,它有两个变量
一个变量是字参数wParam
一个变量是lParam
wParam它包含了识别按下键的虚拟码
而lParam它是一个32位的变量
它包含了按键的重复计数位
OEM的扫描码
扩展键的标识
保留位关联码
键的先前状态以及转化状态等等等等
关于这32位标量里包含了哪一些码的问题
哪一些标志的问题
这个大家不用去管它
这个系统会处理
我们只是把这个机制给大家做个介绍
关键是大家要掌握字参数
因为它识别了案件的虚拟码
那么在WinMain函数中呢
消息循环里面包含了TranslateMessage
这个 在前面构架里面
只是告诉大家有TranlateMessage和DispatchMessage
我们还没讲
按键消息的时候只是告诉大家构架里必须有这一个
那么到了今天,大家就知道了为什么要有这个
因为有了TranlateMessage这个函数
它功能是什么?
是把按键消息转化为字符消息
但只有当键盘驱动程序把键盘字符映射成ASCII码后
才能产生字符消息
那么也就是说
我们从键盘上输入相应的字符
为什么系统会接收我们的字符并进行相应的操作呢?
很重要的是TranlateMessage在起作用
那么我们说系统键字符消息里面,也有系统字符消息
和非系统字符消息
这个比如说
CHAR就是非系统的消息
SYSCHAR就是系统消息
还有一些死字符消息
那么SYSDEADCHAR
那么死字符消息是什么呢
这里面给出了MSDN的解释
因为,大家知道在某些非美式的英语键盘上
有些键是给字母加上音调的
因为它们本身不产生字元
所以称为死键
比如说德语键盘
德语键盘的话,对美式键盘上的这个加号和等号键
德语键盘上对应的就是一个死键
那么没有按下shift键时它标识锐音
按下shift键时,这标识抑音
那么这个是不同语种为了实现相应字符的输出
它设置的一些特殊的字符
我们平常用的是这个英语的键盘,不会用到死字符
那么也就是说当使用者按下这个死字符
系统接收到wParam等于音调本身的ASCII码
或UNICODE代码的死字符DEADCHAR消息
当使用者再按下时,可以带有此音调的字母键
关于死字符的一些知识
我们就简单的和大家说一下
大家如果有兴趣
去看MSDN上面相应网址的内容
因为在我们的中文里面不会遇到
好了下面
我们通过一个例子来介绍一下字符的使用
这个例子是这样的
设计一个窗口
在这个窗口中练习键盘的响应
我们要求是这样的
单击键盘上向上箭头时
窗口中显示“You had hit the UP key”
单击shift键时
窗口中显示“You had hit the SHIFT key”
单机Ctrl键时
窗口中显示“You had hit the CTRL key”
当单击Ctrl+A键的时候
窗口中显示“You had hit the CTRL A key”
单击Shift+B时候呢
窗口中显示“You had hit the SHIFT B key”
那么对于这个应用程序
我们呢也是重点介绍一下WndProc函数
WndProc函数里面呢我们同样定义了一个DC
一个PAINTSTRUCT
这个大家都很清楚
然后,我们定义了画笔跟画刷
由于我们要用到一系列的消息提示
我们把需要提示的消息都做成字符串的
比如说Up key
那么当单击向上箭头的时候
提示信息“You had hit the UP key”
我们放在cUp这个字符数组里面
同样呢cCtrl
那么我们已经预设了五个需要显示的字符串
然后,我们在WndProc里面
要定义几个标志的变量
好了定义什么呢
就是nUpKeyDown
就是向上箭头刚开始没有按下的时候状态一定是FALSE
shift键初始也是FALSE
Ctrl键初始也是FALSE
Ctrl+A键Shift+B键初始也是FALSE
那么就是说刚开始的时候所有按下键的状态都是FALSE
也就是都没按下
因为我们程序刚刚运行时
不可能你是按照某一个键去运行的
所以刚开始所有的按键都是FALSE
那么进入消息循环
首先,我们考虑KEYDOWN
KEYDOWN里面,按下键
按下键的字参数
我们说识别它的字参数
识别它的字参数
如果遇到了向上箭头的虚拟键
这个case 那么就是说按下了这个键
如果按下这个键后我们就把nUpKeyDown给设成TRUE
因为我们的初值都是FALSE
如果shift键按下了
我们就把nShiftKeyDown变成TRUE
如果Ctrl按下了就把nCtrlKeyDown变成TRUE
那么这是按键消息
那么对于按下键我们识别是按下的是什么键
箭头键shift键Ctrl键
那么KeyUp呢 松开键
一旦这个键按下后 松开了
我们就要在屏幕上看到我们的操作效果
这个时候,为了看到效果
我们就要对屏幕进行刷新
那么这时候,就是进行用户区的刷新
好!那么刚才我们识别是KEYDOWN
那么这是非系统键
这是非系统键的消息
和KEYUP
我们识别的都是这两个非系统键消息
所以我们识别的是非系统的UP键
向上箭头
Shift键和Ctrl键
我们下面要识别什么呢?
字符
因为我们有Ctrl+A
Shift+B等等等等
我们如果要判断按下的是Ctrl+A
这时候Ctrl+A是Ctrl+A还是Ctrl+a
所以这个时候
我们说对字符键我们要识别
这个65、97实际上是A的大写的ASCII码和小写的ASCII码
那么这时候按下Ctrl+A或者
这个是或的关系
或者是Ctrl+a
那么这个时候
如果nCtrlKeyDown是TRUE
那么就是按下Ctrl Key
这个时候,仍然是把nCtrlAKeyDown变成TRUE
那这个时候,就是说
我们由于这里有A的ASCII码的字符
A、a都可以
只是按下A、Ctrl+A
那么也就是说,如果先前按下的Ctrl键
我们给它变为nCtrlAKeyDown为TRUE
那么这时候,单纯的Ctrl键给它变成FALSE
这样来标识他按的是Ctrl+A而不是Ctrl和A
两个分别按的
不作为组合键的
Ctrl+A是认为Ctrl和A是一个组合键
如果是把A变成TRUE
Ctrl变成TRUE
那么实际上是分别上是两个键
而不是Ctrl+A的组合键
所以这个地方大家要注意
else if呢,如果字参数是98或者66
那么就按下了B键
如果这个时候
nShiftKeyDown原来是TRUE的
给它改成nShiftBDown是TRUE的
而单纯的Shift是FALSE
那么这个和Ctrl+A应该是如出一辙的
那么这里面
大家可能会说
你Ctrl+A时候,是用65跟Ctrl的或者是97跟Ctrl的
那你下面Shift+B的时候为什么不用
shift跟98或者66跟shift
实际上这两种写法都是可以的
我只是用不同的写法给大家表示一个不同的编程方法而已
这个第一个写法,是同时考虑Ctrl和A
而第二种写法是考虑B之前考虑有没有Shift
如果有的话认为是Shift、B同时按
是这么个意思
好了那么我们已经处理了字符消息
也处理了Up、Ctrl、Shift消息
然后,我们就要看我们到底接收了什么消息
然后进行刷新
那么进入PAINT里面 刷新里面
我们首先仍然通过BeginPaint创建一个DC
然后,我们用系统定义的白画刷
所以大家看到应用程序的背景是白的
大家如果感兴趣的话,可以把这个画刷变成别的颜色
大家可以试一下,把这个程序改一改
那么笔的话,我们用了这个WHITE_PEN
那么白笔的话,大家可能会说这个笔是白的
怎么写字呢?
我们先把这个笔选入
然后再设置它的颜色
所以把这个笔和画刷都选入当前的设备环境之后
我们把这个字体的颜色变成红的
所以这样
写出来字就是红的
所以大家看到我们的提示
通过应用程序的运行大家看到我们的提示
是红色的
那么这个时候,我们就要对输入的字符信息进行判断
如果nUpKeyDown就是向上的箭头为TRUE的话
在这个用户区里面输出我们的关于cUp的提示
nUpKeyDown为TRUE的时候
当你显示完之后
你的nUpKeyDown应该马上变为FALSE了
你不能老在那里是TRUE
然后,如果是nCtrlAKeyDown是TRUE
我们仍然在矩形区域里面
输出关于Ctrl+A按下的时候它的提示内容
那么输出之后,我们要把nCtrlAKeyDown状态变成FALSE
当然也得把nCtrlKeyDown变成FALSE
那么如果nCtrlKeyDown是TRUE而nCtrlAKeyDown是FALSE
那么这个时候
显示是当前按下时Ctrl键
那么Ctrl键完了你这个nCtrlKeyDown马上又变FALSE了
所以,每一次要注意,就是说你做完之后
相应的键都得给它变成FALSE
否则的话,总认为某一个键是按下的
因为我们有对Ctrl的消息响应
有对Ctrl+A的消息响应
那么Ctrl+A里面也包含了Ctrl
所以这个时候
这就是为什么我们前边在做对Ctrl+A判断的时候
Ctrl和A同时按下的时候,我们把Ctrl+A变成TRUE
而单纯把Ctrl变成FALSE
因为Ctrl和Ctrl+A是不一样的
所以它是两个不同的按键消息
同样,如果nShiftBKeyDown是TRUE的情况下
我们仍然在指定的区域输出关于按下Shift+B的消息
然后,我们要把nShiftBKeyDown变成FALSE
也得把nShiftKeyDown变成FALSE
相关键都得变成FALSE
如果nShiftBKeyDown是FALSE
那么就是说没有按下Shift+B
但是你单纯按下Shift的时候
我们就说在这个地方
在指定的位置输出了关于按下Shift键的消息提示之后
再把Shift键变成FALSE
最后,我们把画笔画刷都删除掉后
再EndPaint就结束了
所以,这个DESTROY跟以前一样
所以这个例子
关键大家要掌握一个问题
就是复合键
Ctrl和Ctrl+A
Shift跟Shift+B
他们的区别
所以也就是说,你按Ctrl+A的时候要把Ctrl的状态去掉
不要以为说Ctrl+A里面包含了Ctrl
一定要把Ctrl+A和Ctrl明确区分为两个不同的消息
不要变成包含关系
Ctrl+A消息里面包含了Ctrl消息
或者Shift+B里面包含了Shift消息
那这样
变成消息包含关系就没法处理 会有歧义
到底是Shift还是Shift+B
或者是Ctrl还是Ctrl+A
所以一定要把Ctrl+A和Ctrl分开
Shift+B和Shift分开
也就是说它的这个BOOL变量在Shift+B跟Shift这个地方
或者前边的Ctrl+A和Ctrl这个地方
都要进行相应的设置
不要变成包含关系 而是并列关系
好了,那么这个例子我们就介绍到这
-讨论实录
--0-0
-1-1 Windows应用程序的特点
--1-1
-1-2 可视化编程
--1-2
-1-3 关于API
--1-3-1
--1-3-2
-1-4 Windows应用程序组成及编程步骤
--1-4-1
--1-4-2
-1-5 应用程序举例
--1-5-1
--1-5-2
--1-5-3
-02-1 Windows图形设备接口
-02-2 绘图工具与颜色
-02-3 常用绘图函数
-02-4 例题和作业
-第2章源代码
--外部链接
--外部链接
-3-1 设置文本的设备环境
-3-2 文本的输出过程
-3-3 例题和作业
-第3章源代码
--外部链接
-4-1 Windows 应用程序中的键盘与鼠标
--4-1
-4-2 键盘的操作应用举例
--4-2
-4-3 例题
--4-3
-4-3 鼠标在应用程序中的应用
--4-3
-4-4 例题4-4
--4-4
-第4章源代码
--外部链接
-5-1 菜单和加速键资源及其应用
--5-1
-5-1(例1)
--5-1(例1)
-5-2 位图资源及其应用
--5-2
-5-3 对话框资源及其应用
--5-3-1
--5-3-2
-5-4 图标资源的应用
--5-4
-第5章源代码
--外部链接
-第一次作业
--第一次作业--作业
-第二次作业
--第二次作业--作业
-第三次作业
--第三次作业--作业