《Windows API每日一练》5.3 字符消息

在本章前面讲过,通过转义状态信息可把击键消息转换为字符消息。并且提到,仅仅利用转义状态信息是不够的。还必须知道与国家/地区相关的键盘配置。其实不必担心这个问题。Windows程序主程序中的消息循环可以完美的解决这个问题。

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

{

       TranslateMessage (&msg) ;

       DispatchMessage (&msg) ;

}

这是WinMain函数中典型的消息循环。GetMessage函数从消息队列中取出下一条消息,填入msg结构的字段。DispatchMessage函数调用此消息的窗口过程。

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

本节必须掌握的知识点:

        四类字符消息

        消息排序

        控制字符的处理

        死字符处理

5.3.1 四类字符消息

字符消息可分为四类。      

字符

死字符

非系统字符

WM_CHAR

WM_DEADCHAR

系统字符

WM_SYSCHAR

WM_SYSDEADCHAR

WM_CHAR消息和WM_DEADCHAR消息来自于WM_KEYDOWN消息。而 WM_SYSCHAR 消息和 WM_SYSDEADCHAR 消息来自于 WM_SYSKEYDOWN 消息。

大多数情况下,Windows程序会忽略其他三种字符消息,仅处理 WM_CHAR消息。四类字符消息中的lParam参数和产生此字符码消息的按键消息(WM_KEYDOWN)中的 IParam参数是一样的(重复计数、扫描代码、扩展键标志、上下文代码、上一个键状态标志和转换状态标志)。但是,WM_CHAR消息的wParam参数不是虚拟键代码。实际上,它是ANSI或Unicode 字符码。

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

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

(TCHAR) wParam

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

fUnicode = IsWindowUnicode(hvmd);

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

5.3.2 消息排序

因为 TranslateMessage 函数从 WM_KEYDOWN 和 WM_SYSKEYDOWN 消息产生字符消息,所以字符消息夹在击键消息中传给窗口过程。例如,如果CapsLock键没有锁定, 则在你按下再释放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)。其中的某些控制码也可由下表中的按键产生(win10系统环境下已经不同于winNT或98):

按键

字符码

产生方法

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键和字母键的组合作为菜单快捷键(我们将在第九章中讨 论)。在这种情况下,字母键不能转换为字符消息。

5.3.3 控制字符的处理

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

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

通常我们更偏向把Tab键、回车键、空格键 和Esc键看作控制字符,而不是虚拟键。我通常这样处理WM_CHAR消息:

case WM_CHAR:

       //其他行程式

       switch (wParam)

       {

       case '\b': // backspace

              //其他行程式

              break ;

       case '\t': // tab

              //其他行程式

              break ;

       case '\n': // linefeed

              //其他行程式

              break ;

       case '\r': // carriage return

              //其他行程式

              break ;

       default: // character codes

              //其他行程式

              break ;

       }

       return 0 ;

5.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码。

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

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值