最近在玩WTL的时候,需要处理到回车和ESC键的问题,于是和以前在MFC的时候,老样子,直接写PreTranslateMessage来抓键盘消息(其实我比较喜欢在OnOK或者OnCancel中处理,毕竟很多时候,重载这2个方法,已经能满足要求了) ,结果发现WTL 的PreTranslateMessage 中居然过滤不到按“Enter”和“ESC“键的时候WM_KEYDOWN消息,这会儿傻了~~
于是翻看资料,找信息,终于找到一点资料,故整理了一下,再加上自己的一点实践中获得的知识,写一个小心得吧。
建个Dialog Based(Modal)的工程,编译运行起来,用Spy++抓窗口消息,会发现,如下的一段记录:
<00077> 000E0E26 P WM_KEYDOWN nVirtKey:VK_RETURN cRepeat:1 ScanCode:1C fExtended:1 fAltDown:0 fRepeat:0 fUp:0
<00078> 000E0E26 S WM_GETDLGCODE
<00079> 000E0E26 R WM_GETDLGCODE fuDlgCode:0000
<00080> 000E0E26 S WM_GETDLGCODE
<00081> 000E0E26 R WM_GETDLGCODE fuDlgCode:0000
<00082> 000E0E26 S DM_GETDEFID
<00083> 000E0E26 R DM_GETDEFID wHasDef:DC_HASDEFID wDefID:0001
<00084> 000E0E26 S WM_COMMAND wNotifyCode:0 (从菜单发送) wID:1
<00085> 000E0E26 R WM_COMMAND
<00086> 000E0E26 P WM_KEYUP nVirtKey:VK_RETURN cRepeat:1 ScanCode:1C fExtended:1 fAltDown:0 fRepeat:1 fUp:1
可以看到载WM_KEYDOWN和WM_KEYUP之间有一段处理,注意看DM_GETDEFID 这个消息,这个消息是系统查询某Dialog默认的按钮的,若有则返回值的高字是DC_HASDEFID,低字控件ID;否则返回0。而在这个消息之后,随即系统发了一个WM_COMMAND消息,表示是IDOK的一个COMMAND消息,之后才是WM_KEYUP消息。
那看到这儿就可以明白一些事情了:
1.Enter键按下的时候,OS有做一些特殊的动作来转换这个事件,那至于为什么要这么做,我想这个可能只能问MS的前辈了。
2.要想修改Enter的行为,不一定要在OnOK中处理,也可以在消息DM_GETDEFID中动手脚,用偷梁换柱的方式来做,这样还可以做的更彻底,更灵活。
3.WTL和MFC在消息处理上有不同,因为测试例子可以看到当按Enter的时候,WTL的PreTranslateMessage是拦截不到WM_KEYDOWN消息的,但是MFC可以哦。但是WTL中可以拦截到按Enter的时的WM_KEYUP消息。我想这个和ATL(或者WTL),MFC的实现机制上不同造成的。不过很可惜限于本人对ATL和WTL的运行机制上的知识实在是很优先,这个问题并没有做更深入的研究。
4.按ESC的时候,WTL中也是转换成WM_COMMAND消息来处理的,而且也是一样,可以拦截到WM_KEYUP消息,没有WM_KEYDOWN消息,然后我用Spy++来追踪窗口消息的时候,却发现Spy++挂了,然后导致系统停机一样的表现,只能用Ctrl+Atl+Del来进行暴力动作,尝试了几次之后,终于放弃了,没想到Spy++还有这样的问题,汗~~~~这个估计要换个其他工具来追可能才比较能知道细节了,但是可以看的出来,和Enter上的一些处理原理应该一样。
问题列表:
1.WTL(或者是ATL)和MFC2个框架对消息的处理机制,要去研究一下。
2.想办法解决Spy++在追踪ESC的时候,导致程序停止运行的问题。换追踪工具??换什么?