6.3 字符消息

来源:互联网 发布:域名和ip地址的关系 编辑:程序博客网 时间:2024/06/06 09:39

        摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P176

        在本章前面讲过,通过转义状态信息可把击键消息转换为字符消息。并且提到,仅仅利用转义状态信息是不够的:还必须知道与国家/地区相关的键盘配置。由于这个原因,你不应该自己完成从击键消息到字符消息的转换。Windows 将为你完成这一任务。在前面你已经看到过下面的代码:

while (GetMessage (&msg, NULL, 0, 0)){      TranslateMessage (&msg) ;      DispatchMessage (&msg) ;}
这是 WinMain 函数中典型的消息循环。GetMessage 函数从消息队列中取出下一条消息,填入 msg 结构的字段。DispatchMessage 函数调用此消息的窗口过程。

        在这两个函数之间是 TransalteMessage 函数,它负责把击键消息转换为字符消息。如果击键消息是 WM_KEYDOWN 或 WM_SYSKEYDOWN,且击键和转义状态组合产生了一个字符,则 TranslateMessage 函数把字符消息放入应用程序的消息队列。这个字符消息将被放在击键消息之后,GetMessage 函数可从消息队列中获取此字符消息。

6.3.1  四类字符消息

        字符消息可分为四类。

 字符死字符 非系统字符 WM_CHAR WM_DEADCHAR 系统字符 WM_SYSCHAR WM_SYSDEADCHARWM_CHAR 消息和 WM_DEADCHAR 消息来自于 WM_KEYDOWN 消息。而 WM_SYSCHAR 消息和 WM_SYSDEADCHAR 消息来自于 WM_SYSKEYDOWN 消息。

        有一个好消息:大多数情况下,Windows 程序会忽略其他三种字符消息,仅处理 WM_CHAR 消息。四类字符消息中的 lParam 参数和产生此字符码消息的击键消息中的 lParam 参数是一样的。但是,wParam 参数不是虚拟键代码。实际上,它是 ANSI 或 Unicode 字符码。

        这些字符消息是我们遇到的将文本传递给窗口过程的第一个消息。但它们绝不是唯一的一个。其他字符消息是将以零结束的文本串传递给窗口过程的消息。窗口过程怎么知道哪些字符数据是 8 位的 ANSI 字符编码,哪些是 16 位的 Unicode 字符编码呢?很简单,任何窗口过程,只要包含用 RegisterClassA(RegisterClass 的 ANSI 版本)注册的窗口类,就得到包含 ANSI 字符编码的消息。若包含用 RegisterClassW(RegisterClass 的宽字符版本)注册的窗口类,则得到 Unicode 字符编码的消息。如果你的程序用 RegisterClass 注册窗口类,且 Unicode 标识符被定义,则你使用的实际是 RegisterClassW;否则为 RegisterClassA。

        除非你明确地对窗口过程做了 ANSI 和 Unicode 函数的混合编码,否则 WM_CHAR 消息(以及其他三个字符消息)所传递的字符码是:

(TCHAR) wParam

        同一个窗口过程可能会用到两个窗口类,一个用 RegisterClassA 注册,另一个用 RegisterClassW 注册。这意味着窗口过程会接收到用 ANSI 字符编码的消息和用 Unicode 字符编码的消息。如果你的窗口过程需要确认是哪种字符编码,它能调用:

fUnicode = IsWindowUnicode(hwnd);
如果 hwnd 的窗口过程获得 Unicode 消息,则 fUnicode 变量为 TRUE。这意味着此窗口基于用 RegisterClassW 注册的窗口类。

6.3.2  消息排序

        因为 TranslateMessage 函数从 WM_KEYDOWN 和 WM_SYSKEYDOWN 消息产生字符消息,所以字符消息夹在击键消息中传给窗口过程。例如,如果 Caps Lock 键没有锁定,则在你按下再释放 A 键时,相应的窗口过程会接收以下三个消息:

消息击键或代码 WM_KEYDOWN ‘A’的虚拟键代码 (0x41) WM_CHAR ‘a’的字符编码 (0x61) WM_KEYUP ‘A’的虚拟键代码 (0x41)如果你通过以下几步输入大写字母 A:按下 Shift 键,再按下 A 键,释放 A 键,再释放 Shift 键,则窗口过程接收五个消息:

消息击键或代码 WM_KEYDOWN 虚拟键代码 VK_SHIFT (0x10) WM_KEYDOWN ‘A’的虚拟键代码 (0x41) WM_CHAR ‘A’的字符编码 (0x41) WM_KEYUP ‘A’的虚拟键代码 (0x41) WM_KEYUP 虚拟键代码 VK_SHIFT (0x10)        Shift 键本身不会产生字符消息。

        如果你持续按住 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_KEYDOWN ‘A’的虚拟键代码 (0x41)  WM_CHAR ‘a'的字符编码 (0x61) WM_KEYUP ‘A’的虚拟键代码 (0x41)如果某些 WM_KEYDOWN 消息的重复计数大于 1,则相应的 WM_CHAR 消息将具有同样的重复计数值。

        Ctrl 键和字母键的组合会产生 ASCII 控制字符,范围从 0x01(Ctrl-A)到 0x1A(Ctrl-Z)。其中某些控制码也可由下表中的击键产生:

击  键字  符  码产生方法ANSI C 转义码 空格键 0x08 Ctrl-H \b Tab 键 0x09 Ctrl-I \t Ctrl+回车 0x0A Ctrl-J \n 回车键 0x0D Ctrl-M \r Esc 键 0x1B Ctrl-[ 最后面一列显示了在 ANSI C 中定义的转义码,用来表明这些键的字符码。

        Windows 程序有时采用 Ctrl 键和字母键的组合作为菜单快捷键。在这种情况下,字母键不能转换为字符消息

6.3.3  控制字符的处理

        我们按照以下的基本规则来处理击键和字符消息:如果你需要读取输入到窗口中的键盘字符,就处理 WM_CHAR 消息;如果你需要读取光标键、功能键、Delete 键、Insert 键、Shift 键、Ctrl 键和 Alt 键,则处理 WM_KEYDOWN 消息。

        但是 Tab 键怎么办?回车键、空格键、Esc 键呢?从传统意义上讲,这些键产生 ASCII 控制字符,像上表所显示的那样。但是在 Windows 中,它们也产生虚拟键代码。这些键应该在处理 WM_CHAR 消息或者在处理 WM_KEYDOWN 消息时被处理吗?

        经过十年的考虑(回顾我写过的 Windows 程序),我更偏向把 Tab 键、回车键、空格键和 Esc 键看作控制字符,而不是虚拟键。我通常这样处理 WM_CHAR 消息:

case WM_CHAR:    [other program lines]    switch(wParam)    {    case '\b':        // backspace         [other program line]         break;    case '\t':        // tab            [other program lines]         break;    case '\n':        // linefeed         [other program lines]         break;    case '\r':        // carriage return         [other program lines]         break;    default:    // character codes         [other program liens]         break;   }   return 0;

6.3.4  死字符消息

        Windows 程序通常忽略 WM_DEADCHAR 和 WM_SYSDEADCHAR 消息,但是你应该明确地了解什么是死字符和它们怎样工作的。

        在一些非美国英语的键盘上,某些键可以给字母加上音调。这些键称为“死键”,因为它们自己不产生字符。例如,当安装了德语键盘时,对于美国式键盘上的+/=键,德语键盘上相应的位置为一个死键:当按下 Shift 键时,它为沉音符(ˋ );释放 Shift 键时,它为尖音符()。

        当用户按下此键时,相应的窗口过程会接收到 wParam 参数等于音调本身的 ASCII 或 Unicode 码的 WM_DEADCHAR 消息。若接着按下可带有音调的字母键时(例如 A 键),窗口过程接收到的将是 wParam 参数等于带有音调的字母“a”的 ANSI 码的 WM_CHAR 消息。

        因而,你的程序不必去处理 WM_DEADCHAR 消息,因为WM_CHAR 消息已经包含了程序所需要的所有信息。Windows 逻辑甚至有内置的差错处理:如果你按下死键,接着按下不能携带音调的字母键(如 ‘s’ 键),那么窗口过程会连续接收到两个 WM_CHAR 消息——第一个消息的 wParam 参数等于音调本身的 ASCII 码(与传递给 WM_DEADCHAR 消息的 wParam 参数相同),第二个消息的 wParam 参数等于字母“s”的 ASCII 码。

        当然,理解它的最好方式就是实际操作。你需要加载使用死键的非英语键盘,比如我前面描述过的德国键盘。你可在控制面板中通过选择【键盘】中的【语言】选项卡来设置。然后你需要一个应用程序,它能显示程序接收的每一个键盘消息的细节。

1 0
原创粉丝点击