现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

Win32 关键点总结(4):键盘

2012-09-10 12:25 工业·编程 ⁄ 共 4298字 ⁄ 字号 暂无评论

48 键盘基础

Windows程序获得键盘输入的方式:键盘输入以消息的形式传递给程序的窗口过程。

Windows用8种不同的消息来传递不同的键盘事件。

Windows程序使用“键盘加速键”来激活通用菜单项。加速键通常是功能键或字母同ctrl键的组合。Windows将这些键盘加速键转换为菜单命令消息。

程序用来从消息队列中检索消息的MSG结构包括hwnd字段。此字段指出接收消息的窗口句柄。消息循环中的DispatchMessage函数向窗口过程发生该消息,此窗口过程与需要消息的窗口相联系。当按下键盘上的键时,只有一个窗口过程接收键盘消息,并且此消息包括接收消息的窗口句柄。

接收特定键盘事件的窗口具有输入焦点。

窗口过程通过捕获WM_SETFOCUS和WM_KILLFOCUS消息来判定它的窗口何时拥有输入焦点。WM_SETFOCUS指示窗口正在得到输入焦点,WM_KILLFOCUS表示窗口正在失去输入焦点。

当用户按下并释放键盘上的键时,Windows和键盘驱动程序将硬件扫描码转换为格式消息。Windows在“系统消息队列”中保存这些消息。系统消息队列是单消息队列,它由Windows维护,用于初步保存用户从键盘和鼠标输入的信息。只有当Windows应用程序处理完前一个用户输入消息时,Windows才会从系统消息队列中取出下一个消息,并放入应用程序的消息队列。

》》》Win32 关键点总结(3):图形基础

49 击键和字符

应用程序从Windows接受的关于键盘事件的消息可以分为击键和字符两类。

按下键是一次击键,释放键也是一次击键。

对产生可显示字符的击键组合,Windows不仅给程序发送击键消息,而且还发送字符消息。有些键不产生字符,对于这些键,Windows只产生击键消息。

50 击键消息

当按下一个键时,Windows把WM_KEYDOWN或者WM_SYSKEYDOWN消息放入有输入焦点的窗口的消息队列。

当释放一个键时,Windows把WM_KEYUP或者WM_SYSKEYUP消息放入消息队列。

可以有多个KEYDOWN,但相对来说只有一个KEYUP。

通过调用GetMessageTime可以获得按下或者释放键的相对时间。

51 系统击键和非系统击键

WM_SYSKEYDOWN和WM_SYSKEYUP中的“SYS”代表“系统”,它表示该击键对Windows比对Windows应用程序更加重要。

程序通常可以忽略WM_SYSKEYDOWN和WM_SYSKEYUP消息,并将它们传送到DefWindowProc。

如果想在自己的窗口过程中包括捕获系统击键的代码,那么在处理这些消息之后再传送到DefWindowProc,Windows就仍然可以将它们用于通常的目的。

对所有4类击键消息,wParam是虚拟键代码,表示按下或释放的键。而lParam则包含属于击键的其他数据。

52 虚拟键码

虚拟键码保存在WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP消息的wParam参数中。

53 lParam信息

在4个击键消息中,wParam消息参数含有虚拟键码,而lParam消息参数则含有对了解击键非常有用的其他信息。

在lParam的32位中,分为6个域。

0~15:重复计数;

16~23:8位OEM;

24:扩展键标志;

29:环境代码;

30:键的先前状态;

31:转换状态。

(1)重复计数

重复计数是该消息所表示的击键次数。大多数情况下,重复计数设置为1。

在KEYDOWN消息中,重复计数可以大于1,表示该键重复n次。

在KEYUP消息中,重复计数总是1.

(2)OEM扫描码

OEM扫描码是由硬件(键盘)产生的代码。Windows程序能够忽略几乎所有的OEM扫描码,除非它取决于键盘的物理布局。

(3)扩展位标识

如果击键结构来自IBM增强键盘的附加键之一,那么扩展键标志为1.

(4)环境代码

环境代码在按下Alt键后为1。对WM_SYSKEYDOWN和WM_SYSKEYUP消息,这一位总是1;对WM_KEYDOWN和WM_KEYUP消息,这一位总是0;

但是有2个例外:

① 如果活动窗口最小化了,则它没有输入焦点。这时候所有的击键都产生WM_SYSKEYDOWN和WM_SYSKEYUP消息。

② 如果Alt键未按下,则环境代码域被设置为0.

(5)键的先前状态

如果在此之前键是释放的,则键的先前状态为0,否则为1.

对WM_KEYUP或者WM_SYSKEYUP消息,它总是设置为1.

对WM_KEYDOWN和WM_SYSKEYDOWN消息,此位可以是1,也可以是0.

(6)转换状态

如果键正在被按下,则转换状态为0;

如果键正在被释放,则转换状态为1.

对WM_KEYDOWN和WM_SYSKEYDOWN消息,此域为0;

对WM_KEYUP或者WM_SYSKEYUP消息,此域为1.

54 换挡状态

在处理击键消息是,可能需要知道是否按下了换挡键(Shift, Ctrl, Alt)或开关键(Caps Lock, Num Lock, Scroll Lock)。通过调用GetKeyState函数,就能获得此信息。

int iState;

iState = GetKeyState(VK_SHIFT);

如果按下了Shift,则iState值为负。(高位被置1)。

55 字符消息

在WinMain中,有这样一个消息循环:

while (GetMessage(&msg, NULL, 0, 0))

{

    TranslateMessage(&msg);

    DispatchMessage(&msg);

}

GetMessage函数用队列中的下一个消息填充msg结构的字段。

DispatchMessage以此消息为参数调用适当的窗口过程。

TranslateMessage函数将击键消息转换为字符消息。如果消息为WM_KEYDOWN或WM_SYSKEYDOWN,并且击键与换挡状态相结合产生一个字符,则TranslateMessage把字符消息放入消息队列中。此字符消息将是GetMessage从消息队列中得到的击键消息之后的下一个消息。

56 四类字符消息

字符消息可以分为四类:WM_CHAR、WM_DEADCHAR和WM_SYSCHAR、WM_SYSDEADCHAR。

其中,WM_CHAR、WM_DEADCHAR是从WM_KEYDOWN消息得到的。WM_SYSCHAR、WM_SYSDEADCHAR是从WM_SYSKEYDOWN消息得到的。

大多数情况下,Windowns程序会忽略除WM_CHAR消息之外的任何消息。

伴随四个字符消息的lParam参数与产生字符代码消息的击键消息的lParam参数相同。不过,参数wParam不是虚拟键码,而是ANSI或Unicode字符代码。

57 消息顺序

因为TranslateMessage函数从WM_KEYDOWN和WM_SYSKEYDOWN消息产生了字符消息,所以字符消息是夹在击键消息之间传递给窗口过程的。

(1)如果按下A键,再释放A键,将产生3个消息。

① WM_KEYDOWN   “A”的虚拟键码(0x41)

② WM_CHAR        “a”的字符代码(0x61)

③ WM_KEYUP       “A”的虚拟键码(0x41)

(2)如果按下Shift键和A键,然后释放,将产生5个消息。

① WM_KEYDOWN    虚拟键码VK_SHIFT

② WM_KEYDOWN   “A”的虚拟键码(0x41)

③ WM_CHAR        “a”的字符代码(0x61)

④ WM_KEYUP       “A”的虚拟键码(0x41)

⑤ WM_KEYUP        虚拟键码VK_SHIFT

(3)如果按住A键不释放,将自动重复产生一系列的击键,那么对每个WM_KEYDOWN消息,就会得到一个字符消息。

① WM_KEYDOWN   “A”的虚拟键码(0x41)

② WM_CHAR        “a”的字符代码(0x61)

③ WM_KEYDOWN   “A”的虚拟键码(0x41)

④ WM_CHAR        “a”的字符代码(0x61)

⑤ WM_KEYDOWN   “A”的虚拟键码(0x41)

⑥ WM_CHAR        “a”的字符代码(0x61)

⑦ WM_KEYUP       “A”的虚拟键码(0x41)

58 处理控制字符

处理击键和字符消息的基本规则是:如果需要读取输入到窗口的键盘字符,那么可以处理WM_CHAR消息。如果需要读取光标键、功能键、Delete键、Insert键、Shite键、Ctrl键、以及Alt键,那么可以处理WM_KEYDOWN消息。

对于删除、制表、回车、退出键,它们产生WM_CHAR消息和WM_KEYDOWN消息,应该将这些按键处理成控制字符而不是虚拟键码。

case WM_CHAR:

{

  case ‘/b’:    删除键←

      …..

      break;

  case ‘/t’:     制表键tab

       …..

      break;

  case ‘/n’:      回车

      …..

      break;

case ‘/r’:      换行

      …..

      break;

default:

      …..

      break;

}

59 插入符函数(鼠标闪烁)

主要有8个插入符函数:

① CreateCaret 创建与窗口相关的插入符;

② SetCaret 在窗口中设置插入符的位置

③ ShowCaret 显示插入符

④ HideCaret 隐藏插入符

⑤ DestroyCaret 撤销插入符

⑥ GetCaretPos 获取插入符位置

⑦ GetCaretBlinkTime 获取插入符闪烁时间

⑧ SetCaretBlinkTime 设置插入符闪烁时间

在Windows中,插入符定义为水平线、与字符大小相同的方框,或者与字符等高的竖线。

只有当窗口有输入焦点时,窗口内显示插入符才有意义。

通过处理WM_SETFOCUS和WM_KILLFOCUS消息,程序就可以确定它是否有输入焦点。窗口过程在有输入焦点的时候接受WM_SETFOCUS消息,失去输入焦点的时候接受WM_KILLFOCUS消息。

使用插入符的规则:窗口过程在WM_SETFOCUS消息期间调用CreateCaret,在处理WM_KILLFOCUS消息期间调用DestroyCaret。

插入符刚创建的时候是隐蔽的,必须显式使用ShowCaret函数将插入符设为可见。

当窗口过程处理一个非WM_PAINT消息而且希望在窗口内绘制某些东西时,必须调用HideCaret隐藏插入符。在绘制完毕之后,再调用ShowCaret显式插入符。

给我留言

留言无头像?