键盘基础
1、焦点 |
---|
键盘被正在运行的所有程序共享,键盘消息会被当前拥有焦点的窗口接收,窗口获取焦点时窗口过程会收到WM_SETFOCUS消息,而失去焦点时会接收到WM_KILLFOCUS消息。
2、同步 |
---|
键盘消息产生后,首先被暂时存储在系统消息队列中,只有当窗口过程处理完上一条键盘消息后,才会从系统消息队列取出下一条键盘消息放入程序消息队列中。
这一机制是为了避免键盘消息被发送到错误的窗口过程。假如没有系统消息队列:一个特殊的键盘消息可能导致焦点的转移,则其后面的键盘消息应该发送给另一个窗口。但如果用户输入速度比窗口过程处理消息速度快,那么在焦点切换到另一个窗口前,其后键盘消息都被发送到了当前窗口过程。
3、击键消息 |
---|
按下一个键时,会产生WM_KEYDOWN或WM_SYSKEYDOWN消息;释放键时,会产生WM_KEYUP或WM_SYSKEYUP消息。如果按住键不放,会一直产生WM_KEYDOWN或WM_SYSKEYDOWN消息。
WM_SYSKEYDOWN和WM_SYSKEYUP消息是系统击键,一般由alt组合键产生,应用程序通常忽略系统击键消息,将它们交给DefWindowProc处理。
击键消息的wParam参数是虚拟击键码,<winuser.h>中定义了一系列VK_开头的虚拟键宏。
lParam包含击键消息的其他数据,32位被分成6个字段:
-
16位重复计数[0,15]
如果按住一个键不放,并且窗口过程来不及处理产生的击键消息,windows就把这些击键消息合并成一条,并增加其重复计数。KEYUP消息的重复计数总是1。 -
8位OEM扫描码[16, 23]
OEM扫描码是键盘硬件产生的代码,windows程序可以忽略。 -
1位扩展键标记[24]
windows程序可以忽略。 -
1位内容代码[29]
-
1位先前状态[30]
0:键先前处于释放状态。1:键先前处于按下状态。 -
1位转换状态[31]
KEYDOWN消息为0,KEYUP消息为1。
4、GetKeyState |
---|
- 判断按键是否被按下
处理击键消息时,可能需要检查Shitf、Ctrll或Alt键是否按下来实现组合键功能,GetKeyState返回值的最高位表示按键的按下状态。如果按键按下,返回值高位置1,否则置0。 - 判断按键开关状态
键盘个别按键具有开关状态,比如CapsLock、NumLock、Scroll Lock等。GetKeyState返回值的最地位表示这些按键的开关状态。低位置1表示状态打开,否则关闭。
需要注意,GetKeyState不是实时的键盘状态,它反映的是窗口过程处理到当前消息为止的键盘状态(消息队列中可能还有待处理的键盘消息)。如果希望获取键盘的实时状态,可以使用GetAsyncKeyState函数。
字符消息
消息循环代码段中,通常都会调用TranslateMessage函数。TranslateMessage负责把WM_KEYDOWN或WM_SYSKEYDOWN消息转换为字符消息。如果WM_KEYDOWN或WM_SYSKEYDOWN消息产生了一个字符,TranslateMessage就会把字符消息放入应用程序消息队列中。
1、四种字符消息 |
---|
- WM_CHAR
- WM_DEADCHAR
- WM_SYSCHAR
- WM_SYSDEADCHAR
通常,windows程序只需要处理WM_CAHR消息。
字符消息的lParam参数和击键消息的一样。wParam是字符的ANSI码或Unicode码。
wParam的编码依赖于注册窗口类时使用的函数。如果使用RegisterClassA,则wParam的编码是ANSI;如果使用RegisterClassW,则wParam的编码是Unicode。此外,还可以使用IsWindowUnicode来判断窗口使用的字符集。
插入符号
通常,进行文本输入的地方都会有一个闪烁的符号,称为“插入符号”。windows提供了几个处理插入符号的函数:
- CreateCaret
- SetCaretPos
- ShowCaret
- HideCaret
- DestroyCaret
- GetCaretPos
- GetCaretBlinkTime
- SetCaretBlinkTime
一个消息队列中只能有一个插入符号。窗口通常在获取到焦点时才显示插入符号,所以使用插入符号的一般方法是,在WM_SETFOCUS消息处理中CreateCaret,在WM_KILLFOCUS消息处理中DestroyCaret。
此外,还需要注意:
- CreateCaret后,必须ShowCaret才会显示插入符号
- 在非WM_PAINT消息中进行绘制时,必须先HideCaret隐藏插入符号
- HideCaret的效果会叠加,需要调用相同次数ShowCaret才能显示插入符号。