[Win32]键盘接口简介

本文介绍了Win32环境下键盘输入焦点的原理,包括如何判断窗口是否具有输入焦点,以及系统消息队列和同步机制。详细阐述了击键消息和虚拟键代码,强调了系统击键和非系统击键的区别,并讨论了虚拟键代码的作用。最后,探讨了击键消息的标记信息和如何利用GetKeyState函数检查键的状态,以及击键消息在应用程序中的实际应用,如文本编辑和光标移动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 键盘输入焦点:

    1) 一台电脑只有一个键盘,因此键盘必须为所有应用程序锁共享;

    2) 同样,如果一个应用程序在使用键盘,那么该应用程序的所有窗口也应该共享键盘;

    3) 输入焦点:根据消息循环的机制,当敲击键盘产生键盘消息后只有一个窗口会接收到键盘消息,而该窗口就是具有输入焦点的窗口;

    4) 如何判断一个具有输入焦点的窗口:必定为活动窗口或者是活动窗口的各个子孙窗口中的一个;

    5) 活动窗口及其子孙窗口:活动即顶层窗口(其父指针为NULL),活动窗口的标题栏会高亮(非活动窗口,即被盖在下面的窗口标题栏通常是灰色的),如果没有标题栏,则其边框是高亮的,并且活动窗口最小化到任务栏后也会被凸显(就像一个被按下的按钮一样),子窗口不能是活动窗口(子窗口只能沾活动窗口的光),即活动窗口的子孙窗口可以获得输入焦点,比如对话框中的编辑框就是当前活动窗口对话框中的一个子窗口;

特殊情况:没有窗口但是具有输入焦点(当程序最小化的时候),焦点的含义就是当前正在被使用的那个对象窗口,只要这么简单地理解就行了!

    6) 一个窗口如何判断自己是否获得焦点:如果收到WM_SETFOCUS消息就表明自己获得了输入焦点,如果收到WM_KILLFOCUS消息则表示自己失去了焦点,一般当一个窗口被用户点击被显示在了最顶层时就会收到WM_SETFOCUS消息,当用户点击了另一个窗口而导致另一个窗口处于最顶层而当前窗口被盖在了下面,此时该窗口就会收到一个WM_KILLFOCUS消息;


2. 系统消息队列和同步:

    1) 由于来自键盘和鼠标的消息不一定都是集中在一个窗口的,用户想将一部分来自键盘和鼠标的消息给一个窗口处理,另一部分交给另一个窗口处理,但是用户无法直接干涉消息如何分发,因此这就需要先创建一个系统消息队列来暂时收容来自键盘和鼠标的消息,然后系统根据当前哪个窗口具有焦点来决定将收容的消息分配给哪个应用程序的消息队列;

    2) 系统需要同步:用户可能连续产生若干个消息,比如WM1、WM2、WM3、WM4...,其中1和2是交给当前焦点窗口处理的,而3是一个将焦点转向另一个窗口的消息,而后面的消息都是交由新焦点窗口处理的消息,如果此时一股脑儿将所有消息都先扔给当前焦点窗口则必然会发生错误和混乱,因此系统消息队列最重要的一个特征就是同步,同步就是指只有当上一个消息处理完之后才会继续从系统消息队列中取走下一个消息分发给当前焦点窗口,这样就能避免将消息发送给错误的窗口;


3. 击键消息机器虚拟键代码:

    1) 击键仅仅代表一个物理动作,键按下和放开都是一次击键(也就是两次击键),表示有一个键按下的消息是WM_KEYDOWN消息,而键放开的消息是WM_KEYUP消息;

    2) 通常击键消息是连续追踪的,当按下一个键不放时将会产生连续击键行为,窗口会收到一连串WM_KEYDOWN消息,但是WM_KEYUP是不连续的,一次按键只能对应一个释放动作;

    3) 系统击键和非系统击键:

         i) 击键消息汇总:


         ii) 系统击键通常是指和Alt键组合的击键,系统击键通常对于Windows操作系统来说比对应用程序更加重要,因此这类消息通常应用程序都不处理而直接交由DefWindowProc来处理,它会直接将这些消息交由系统处理完成一些系统任务,如调用程序菜单功能或者是系统菜单功能,其中有些功能是当前应用程序是无法处理的,比如Alt+Tab键是用来切换应用程序的,对于这种功能一般应用程序办不到,只能交由操作系统来完成,因此这类消息直接通过DefWindowProc交由操作系统来处理;

         iii) 当然应用程序如果有需要也可以响应系统击键消息,比如在WM_SYSKEYDOWN下写上消息处理代码,但一般处理完之后还是要将该消息在发送给DefWindowProc处理,以免影响Windows操作系统的运行,当然在某些特殊情况下洗完组织系统处理这样的按键消息,比如某个应用程序想独占Alt+Tab按键作为自己的快捷键而不希望操作系统也响应它(有时也有Windows键),特别是在一些游戏程序中,为了避免玩家误按下这些件而切换到游戏以外的画面,这是就可以使用如下模板来处理:

case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSCHAR:
	return 0;
暴力阻止所有系统击键的系统响应

case WM_SYSKEYDOWN:
	if ( VK_TAB == wParam ) return 0;

	switch ( wParam )
	{
		...
	}

	return 0;
仅仅阻止Alt+Tab系统击键的系统响应

一般Alt+各种键都会产生系统击键消息,还有就是Windows键以及Windows键和各种键的组合也会产生系统击键消息!


4. 虚拟键代码——键消息的附加消息:

    1) 击键消息只能代表有某一个键按下或者放开,但是不能具体表名是哪个键被按下后者放开,这是没有任何使用意义,因此击键消息的附加参数必须提供这些信息;

    2) 用来标识按键的代码存放在击键消息的wParam中,这就是虚拟按键代码,注意!虚拟按键代码和ASCII码毫不相关!

    3) 虚拟键代码的由来:因为键盘按键的信号只能用一些简单的编码方法进行编码(根据键盘的物理格局以及键盘上键的排列来决定),无法用复杂的ASCII码进行编码,否则这回大大增加键盘电路的复杂度!因此,最早的键盘按键信号的编码仅仅就是由键的物理顺序来决定的,比如Q、W、E、R的编码就是16、17、18和19,完全按照物理位置从左到右递增,但是这对于编程来说非常不方便,编程需要和设备无关的编码方案,因此Windows就要求键盘厂商提供的键盘驱动程序将这些第一手的基于物理位置的编码转换成一种通用的与设备无关的编码方案(现在的键盘都已经统一标准了,接口驱动程序基本由Windows来提供,而厂商负责生产负荷该标准的键盘即可),该通用的设备无关编码方案就是编程中用到的虚拟键代码,比如键盘上的A键对应的虚拟键代码就是65,和A的ASCII码天差地别,同时从键盘上看A键具体代表大写A还是小写a完全取决于你是否按下Shift键以及Caps Lock键;

    4) 使用虚拟键代码而不直接使用ASCII码的原因:一方面刚刚已经提到过构造ASCII码的硬件电路复杂,另一方面,键盘上很多控制键是屏幕无法显示的(即不带表任何字符),仅仅用来完成一些功能,很多键的功能也无法在ASCII编码中表示,再说了,对于数字键来讲还区分主键盘和数字小键盘,如果都用ASCII编码就无法区别是来自主键盘还是来自小键盘,因此Windows为键盘上的每个键都编制了一个虚拟键代码,而对于那些可以用来显示文本的键(如字母键、数字键等)可以通过TranslateMessage为这些击键消息再产生一条对应的字符消息(WM_CHAR消息),然后将对应的字符ASCII码存储在字符消息的附加参数wParam中,这也就是虚拟键代码和ASCII码之间的区别,ASCII属于上层编码,而虚拟键代码更加偏向底层对硬件信号的编码!

    5) 虚拟键代码汇总:


以上的鼠标键消息无法用键盘产生,只能用鼠标产生,VK_CANCEL是指Ctrl+Pause Break键,现在已经不用了!


通常应用程序不需要监控Shift键、Ctrl键或Alt键,因为监控这些件没有意义,一般都是监控和其组合在一起的那个wParam的内容!


用的最多的几个虚拟键代码就是VK_PRIOR表示Page Up键以及前7个键还有就是VK_INSERT和VK_DELETE

接下来是主键盘的数字键和字母键以及数字小键盘上的键:



接下来是Windows键和特殊的Application键:


剩下的就是功能键F键等键:



5. 击键消息的标记信息:

    1) 击键消息的虚拟键代码存储在wParam中,而其标记信息则存储在lParam中,32位的lParam被分成了六段如图:


    2) 重复计数字段:通常情况下被设为1,只有在相同消息连续堆积的情况下才会进行计数,也就是窗口过程处理速率跟不上输入速率的时候才会出现这种情况,在这种情况下连续的多个WM_KEYDOWN或者WM_SYSKEYDOWN消息会合并成一个消息,只不过就是该字段变成了一个计数值而已;

    3) OEM扫描码:现在已经不用了;

    4) 扩展键标记:是指一些大键盘(通常超过100个键)上的一些比正常标准键盘多出来一些键的按键标记,比如右侧Alt和Ctrl,数字小键盘上的Num Lock键以及Enter键等,这些键的击键消息,该位会被置为1;

    5) 内容代码:击键的同时按下Alt键该位就会被置为1,因此所有WM_SYSKEYDOWN和WM_SYSKEYUP的该位都是1,而WM_KEYDOWN和WM_KEYUP该位都是0,但是某些和Alt键组合的击键消息不一定是系统击键消息,比如一些非英语键盘通过Alt键的组合产生一些带重音符号的字符;

    6) 键的先前状态:先前处于释放则为0,处于按下则为1,因此WM_KEYUP和WM_SYSKEYUP的该标记始终为1,而对于WM_SYSKEYDOWN和WM_KEYDOWN则可能为1也可能为0,为1表示连续按着键;

    7) 转换状态:如果当前正在被按下则为0,正在被释放则为1,因此DOWN始终为0而UP始终为1;


6. 利用GetKeyState函数检查转义状态:

    1) 转义键是指Shift、Ctrl、Alt、Caps Lock等键,和它们组合的键的含义将会别转变,特别是大小写输入的时候;

    2) 函数原型为:SHORT GetKeyState( int nVirtKey );

    3) 参数即为虚拟键代码,如果改建被按下则返回一个负值(最高位为1),否则就表示被释放(最高位为0),当然最高位用来表示一个键按下和释放者两种状态;

    4) 返回值的最低位标志一个键的功能是否被锁定,这常用于具有指示灯的按键,诸如Caps Lock、Num Lock、Scroll Lock的各种Lock键,当这些键被锁定(即响应的指示灯亮),则返回值最低位为1,否则为0,因此诸如Shift、Alt、Ctrl等的判断只用最高位,而那些Lock键的状态只用最低位来判断,而上述这些键的虚拟键代码也只能用于该函数以及GetAsyncKeyState函数;

    5) GetKeyState只能检查当前状态而不能检查当前实时状态,比如在判断组合键Shift + Tab的时候,按照标准习惯都是先按Shift再按Tab(即功能键优先按,还有Ctrl、Alt等,而字符键之后按,包括字母键、空格、Tab等),因此就在处理Tab的WM_KEYDOWN消息中调用GetKeyState( VK_SHIFT )来判断这一组合键,这是你只能知道按Tab之前Shift先被按下了,之后是两个一起按下的,而此时此刻Shift有没有释放我们不知道,这很合理很方便;

小结:先被按下的是用GetKeyState检查的,外面的包含他的WM_KEYDOWN响应一定是后按下的,这是Windows的内部机制,只要遵守该原则就行了!

因此如果想获得实时的状态就必须调用GetAsyncKeyState函数了;


7. 如何使用击键消息:

    1) 通常击键消息很少使用,应用程序用的最多的是字符消息,即能产生字符的按键都监控它们的字符消息,因为单单一个按键动作没有任何意义;

    2) 因此通常是能产生字符的按键监控其字符消息,而不能产生字符的按键则监控其击键消息,但是真正值得应用程序去监控的击键消息也是少得可怜的;

    3) 关于菜单快捷键命令:很多人喜欢大量监控Alt、Ctrl、Shift、Delete、Insert等的击键消息来定义自己的快捷键,但是Windows不支持这样做,通常这些键的组合通常用于重复应用程序的菜单命令,如果定义大量这些快捷键将不利于用户快速学习你的程序,因此这些键的击键消息通常也是直接交由DefWindowProc处理(即由操作系统自动处理);

    4) 击键消息监控的真正用途:主要用在文本编辑、查看中的光标移动,也只有这些情况下Windows是没有默认的功能的,Shift、Ctrl键和Insert、Delete、光标键的组合可以扩大文本处理的范围,比如Ctrl和左右键组合可以选中一个单词等,Shift和上下键组合可以翻页等,而具体移动多少范围等意义可以由应用程序自己按照需求定义;

还有就是Page Up、Page Down等用来滚条的翻页,基本上都是跟文本显示有关的!


作为Microsoft 32位平台的应用程序编程接口, Win32 API是从事Windows应用程序开发所必备的。 首先对Win32 API函数做完整的概述;然后收录五大类函数: 窗口管理、图形设备接口、系统服务、国际特性以及网络服务; 在附录部分,讲解如何在Visual Basic和Delphi中对其调用。 本书是从事Windows应用程序开发的软件工程师的必备参考手册。 控件与消息函数 共91个函数 硬件与系统函数 共98个函数 设备场景函数 共73个函数 绘图函数 共105个函数 位图、图标和光栅运算函数 共39个函数 菜单函数 共37个函数 文本和字体函数 共41个函数 打印函数 共66个函数 文件处理函数 共118个函数 进程和线程函数 共40个函数 Windows消息函数 共11个函数 网络函数 共14个函数 目 录 第一章 Win32 API概论…………………………………………………………………………1 1.1 为什么使用Win32 API …………………………………………………………………1 1.2 Win32 API简介 …………………………………………………………………………1 1.3 综述………………………………………………………………………………………11 第二章 窗口管理函数(Windows Control Function) ……………………………………13 2.1 易用特性函数(Accessibility Features)…………………………………………13 2.2 按钮函数(Button)……………………………………………………………………20 2.3 插入标记(^)函数(Caret)…………………………………………………………21 2.4 组合框函数(Combo box) ……………………………………………………………24 2.5 通用对话框函数(Common Dialog Box) ……………………………………………25 2.6 标函数(Cursor)………………………………………………………………………36 2.7 对话框函数(Dialog Box)……………………………………………………………40 2.8 编辑控制函数(Edit Control)………………………………………………………54 2.9 图标函数(Icon)………………………………………………………………………54 2.10 键盘加速器函数(Keyboard Accelerator)……………………………………… 61 2.11 键盘输入函数(Keyboard InPut) …………………………………………………63 2.12 列表框函数(List box) ……………………………………………………………75 2.13 菜单函数(Menu) ……………………………………………………………………76 2.14 消息消息队列函数(Message and Message Queue)……………………………90 2.15 鼠标输入函数(Mouse Input) ……………………………………………………100 2.16 多文档接口函数(Multiple Document Interface) ……………………………103 2.17 资源函数(Resource)………………………………………………………………105 2.18 滚动条函数(Scroll Bar)…………………………………………………………113 2.19 窗口函数(Window)…………………………………………………………………119 2.20 窗口类函数(Window Class)………………………………………………………144 2.21 窗口过程函数(Window Procedure)………………………………………………150 2.22 窗口属性函数(Window Property) ………………………………………………152 第三章 图形设备接口函数(Graphic Device Interface Function) …………………155 3.1 位图函数(Bitmap) …………………………………………………………………155 3.2 笔刷函数(Brush)……………………………………………………………………171 3.3 剪切函数(Clipping) ………………………………………………………………176 3.4 颜色函数(Color)……………………………………………………………………179 3.5 坐标空间与变换函数(Coordinate Space Transformation)……………………186 3.6 设备环境函数(Device Context) …………………………………………………195 3.7 填充形态函数(Filled shape) ……………………………………………………211 3.8 字体和正文函数(Font and Text)…………………………………………………215 3.9 ICM 2.0函数 …………………………………………………………………………238 3.10 线段和曲线函数(Line and Curve)………………………………………………295 3.11 图元文件函数(Metafile)…………………………………………………………300 3.12 多显示器函数(Multiple Display Monitors) …………………………………311 3.13 绘图函数和画图函数(Painting and Drawing)…………………………………313 3.14 路径函数(Path)……………………………………………………………………328 3.15 画笔函数(Pen) ……………………………………………………………………332 3.16 打印及打印假脱机程序函数(Printing and Print Spooler)…………………334 3.17 矩形函数(Rectangle) ……………………………………………………………371 3.18 区域函数(Region)…………………………………………………………………374 第四章 系统服务函数(System Service Function) ……………………………………383 4.1 访问控制函数(Access Control) …………………………………………………383 4.2 原子函数(Atom) ……………………………………………………………………406 4.3 客户/服务器访问控制函数(Client/Server Access Control) ………………409 4.4 剪贴板函数(Clipboard)……………………………………………………………431 4.5 通信函数(Communication)…………………………………………………………436 4.6 控制台函数(Console)………………………………………………………………444 4.7 数据解压库函数(Data Decompression Library) ………………………………463 4.8 调试函数(Debugging)………………………………………………………………466 4.9 设备输入输出函数(Device Input and Output)…………………………………472 4.10 动态数据交换函数(Dynamic Data Exchange) …………………………………474 4.11 动态数据交换管理函数(Dynamic Data Exchange Management)………………476 4.12 动态链接库函数(Dynamic-Link Library)………………………………………489 4.13 错误函数(Error) …………………………………………………………………496 4.14 事件日志函数(Event Logging) …………………………………………………499 4.15 文件函数(File)……………………………………………………………………503 4.16 文件安装库函数(File Installation Library) ………………………………542 4.17 文件映射函数(File Mapping)……………………………………………………546 4.18 文件系统函数 File System)………………………………………………………551 4.19 句柄和对象函数(Handle and Object)………………………………………………556 4.20 挂钩函数(Hook)………………………………………………………………………560 4.21 ImageHlp函数…………………………………………………………………………572 4.22 大整数操作函数(Iarge Integer Operations)……………………………………594 4.23 低层访问控制函数(Low-Level Access Control)………………………………596 4.24 LSAPI函数 …………………………………………………………………………617 4.25 邮槽函数(Mailslot)………………………………………………………………622 4.26 内存管理函数(Memory Management) ……………………………………………623 4.27 管道函数(Pipe) …………………………………………………………………655 4.28 电源管理函数(Power Management) …………………………………………… 663 4.29 进程和线程函数(Process and Thread)…………………………………………666 4.30 注册表函数(Registry)……………………………………………………………700 4.31 字符串操作函数(String Manipulation)……………………………………… 724 4.32 结构化异常处理函数(Structured Exception Handling) ……………………742 4.33 同步函数(Synchronization) ……………………………………………………745 4.34 系统信息函数(System Information)……………………………………………766 4.35 系统消息函数(System Message)…………………………………………………780 4.36 系统关机函数(System Shutdown) ………………………………………………781 4.37 磁带备份函数(Tape Backup) ……………………………………………………783 4.38 时间函数(Time)……………………………………………………………………789 4.39 计时器函数(Timer) ………………………………………………………………795 4.40 工具帮助函数(Tool Help) ………………………………………………………796 4.41 窗口站和桌面函数(Window Station and Desktop)……………………………799 4.42 Windows NT 4.0访问控制函数(Window NT 4.0 Access-Control)……………808 4.43 WinTrust函数(WinTrust)…………………………………………………………814 第五章 国际特性函数(International Peatures Punction)时性…………………………815 5.1 输入方法编辑函数(Input Method Editor)…………………………………………815 5.2 国家语言支持函数(National Language Support)………………………………… 828 5.3 Unicode和字符集函数(Unicode and Character Set)……………………………… 843 第六章 网络服务函数(Networding Service Function)……………………………………849 6.1 数据链路控制函数(DLC)………………………………………………………………849 6.2 网络函数(Net)…………………………………………………………………………849 6.3 NetBIOS函数……………………………………………………………………………896 6.4 网络DDE函数(Networking DDE)……………………………………………………897 6.5 RAS服务器管理函数(RAS Server Administration)………………………………901 6.6 远程访问服务函数(Remote Access Administration)………………………………910 6.7 服务函数(Service)……………………………………………………………………929 6.8 Windows网络函数(Windows Networking)……………………………………………930 附录1 如何在VB中调用DLL API ……………………………………………………………945 1 DLL API的声明……………………………………………………………………………945 2 DLL API的调用……………………………………………………………………………947 附录2 在Delphi中直接调用Windows API…………………………………………………953
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值