在对话框应用程序中是不能直接响应加速键的. 为了使对话框响应加速键, 我选择了 Hook 方法.
我不选注册系统热键的方法, 因为它可能和别的应用程序发生热键冲突. 再者, Hook 方法可以
产生 WM_COMMAND 消息, 这样给编写程序带来方便.
当 Hook 了对话框的消息时, 在消息钩子过程中只拦截对我们有用的 WM_KEYDOWN 消息, 忽略
WM_SYSKEYDOWN 消息. 在 TranslateAccelerator WM_KEYDOWN 消息时, 发出 WM_COMMAND 消息;
而 TranslateAccelerator WM_SYSKEYDOWN 消息时, 发出 WWM_SYSCOMMAND 消息.
消息流程: "GetMessage" --> "Windows 消息等待" --> "用户按加速键产生消息" -->
"GetMsgProc" --> "TranslateAccelerator" --> "发送 WM_COMMAND" -->
"返回 GetMsgProc" --> "返回 GetMessage" --> "TranslateMessage" -->
"DispatchMessage" --> "GetMessage"
TranslateAccelerator 函数不会修改 _GetMsgProc 中的参数 _lParam 所指向的 MSG 结构,
所以可以放心让消息传到 windows 内部对话框的消息循环中, 即 "GetMessage" -->
"TranslateMessage" ...
; 程序代码如下:
; ---------------------------------------------------
; ......
; 资源定义
ACT_MAIN equ 106 ; 加速键表
ACT_F7 equ 2007 ; F7 加速键
ACT_F8 equ 2008 ; F8 加速键
.data?
g_hInst dword ? ; 对话框应用程序句柄
g_hAct dword ? ; 加速键表句柄
g_dwThrdID dword ? ; 对话框线程 ID
g_hHook dword ? ; 钩子句柄
g_hWnd dword ? ; 对话框窗口句柄
.code
; ......
; _GetMsgProc
; ------------------------------------------
; 说明: 监控对话框的消息钩子过程
; ------------------------------------------
_GetMsgProc proc _nCode:dword, _wParam:dword, _lParam:dword
mov edx, _lParam
mov eax, dword ptr[edx+4] ; 获得消息
.if (eax == WM_KEYDOWN)
invoke TranslateAccelerator, g_hWnd, g_hAct, _lParam
.endif
invoke CallNextHookEx, g_hEverHook, _nCode, _wParam, _lParam
ret
_GetMsgProc endp
; ......
; 在对话框的初始化消息 "WM_INITDIALOG" 中添加
invoke LoadAccelerators, g_hInst, ACT_MAIN
mov g_hAct, eax
invoke GetWindowThreadProcessId, g_hWnd, NULL
mov g_dwThrdID, eax
; 创建对话框的 MsgHook
invoke SetWindowsHookEx, WH_GETMESSAGE, addr _GetMsgProc, NULL, eax
mov g_hHook, eax
; ......
; 现在可以在 WM_COMMAND 中获得加速键消息了
mov eax, _wParam
.if (ax == ACT_F7)
; 响应 F7 加速键代码
; ......
.elseif (ax == ACT_F8)
; 响应 F8 加速键代码
; ......
.endif
; ......
; 在 WM_CLOSE 中卸载钩子
invoke UnhookWindowsHookEx, g_hHook
; ......