用日志钩子处理键盘消息时的一个注意事项
2014-12-01 12:07
281 查看
发现问题:
在日志钩子中调用GetKeyState或GetKeyboardState函数获取键盘状态信息,接着用OutputDebugString输出发现结果不正常。但是可以用ToAscii函数获取正确的字符信息,包括安下shift或Capital键的输出结果。
试着解释出现问题的原因:
Windows系统有一个系统消息队列,这个消息队列里的所有消息是输入设备动作产生的。
另外Windows为每个线程维护一个消息队列(如果有必要),Windows会检查系统消息队列里的所有消息,然后将系统消息队列里的消息派送到相应的线程消息队列,每个线程各自从自己的线程消息队列中获取消息处理。
JOURNALRECORD钩子只能是全局钩子,其对应的钩子函数记录系统消息队列中移除的所有消息:”The function records messages the system removes from
the systemmessage queue.”
WH_KEYBOARD钩子可以是全局的或者局部的,其对应的钩子函数在线程从线程消息队列中取相关消息时被Windows调用:”
The system calls this function whenever an application calls the GetMessageor
PeekMessagefunction and there
is a keyboard message (WM_KEYUPor
WM_KEYDOWN)to be processed.”
所以对同一个消息,日志钩子的调用更先于键盘钩子,这造成了一些不同:
在键盘钩子函数里处理收到的WM_KEYUP消息时,如果调用GetKeyState或GetKeyboardState函数,查看返回值,会发现触发WM_KEYUP消息的按键的状态是按下的(返回值对应高位为1)。
但是在日志钩子里进行同样的处理,处理收到的WM_KEYUP消息时调用GetKeyState或GetKeyboardState函数,查看返回值,会发现触发WM_KEYUP消息的按键的状态是之前的,若是第一次按下此键,则返回值状态是释放状态(返回值对应高位为0)。
也就是说,用GetKeyState或GetKeyboardState函数检索虚拟键的状态,这个状态的变化发生在按键消息从系统消息队列中移除之后,消息到达应用程序之前。MSDN中有这样的描述:”
The key status returned from this function changes as a threadreads key messages from its message queue.”
日志钩子函数的lParam参数说明:
lParam是一个EVENTMSG结构:
EVENTMSG STRUCT
message DWORD ? ;系统消息队列中将要移去的消息ID
paramL DWORD ? ;消息的wParam参数
paramH DWORD ? ;消息的lParam参数
time DWORD ? ;消息发生的时间
hwnd DWORD ? ;消息对应的窗口句柄
EVENTMSG ENDS
.if message>= WM_KEYFIRST and message <= WM_KEYLAST
paramLand 00FFh
为虚拟键码
paramLand 0FF00h为扫描码
paramHand 00FFh
为扫描码
.endif
罗云彬老师的《windows环境下的32位汇编语言程序设计》日志钩子程序此处可能有问题,请看的同学注意。
题外话:这个问题困扰了我好几天,最近算是弄明白了点,但是并不是完全清楚,所以请看这篇文章的读者只做下参考。我以前完全没有Windows编程基础,最近学习Windows编程一直靠看罗老师的书和上网查资料,看了不到一个月,很多地方看的并不是明白,理解也不到位。
在日志钩子中调用GetKeyState或GetKeyboardState函数获取键盘状态信息,接着用OutputDebugString输出发现结果不正常。但是可以用ToAscii函数获取正确的字符信息,包括安下shift或Capital键的输出结果。
试着解释出现问题的原因:
Windows系统有一个系统消息队列,这个消息队列里的所有消息是输入设备动作产生的。
另外Windows为每个线程维护一个消息队列(如果有必要),Windows会检查系统消息队列里的所有消息,然后将系统消息队列里的消息派送到相应的线程消息队列,每个线程各自从自己的线程消息队列中获取消息处理。
JOURNALRECORD钩子只能是全局钩子,其对应的钩子函数记录系统消息队列中移除的所有消息:”The function records messages the system removes from
the systemmessage queue.”
WH_KEYBOARD钩子可以是全局的或者局部的,其对应的钩子函数在线程从线程消息队列中取相关消息时被Windows调用:”
The system calls this function whenever an application calls the GetMessageor
PeekMessagefunction and there
is a keyboard message (WM_KEYUPor
WM_KEYDOWN)to be processed.”
所以对同一个消息,日志钩子的调用更先于键盘钩子,这造成了一些不同:
在键盘钩子函数里处理收到的WM_KEYUP消息时,如果调用GetKeyState或GetKeyboardState函数,查看返回值,会发现触发WM_KEYUP消息的按键的状态是按下的(返回值对应高位为1)。
但是在日志钩子里进行同样的处理,处理收到的WM_KEYUP消息时调用GetKeyState或GetKeyboardState函数,查看返回值,会发现触发WM_KEYUP消息的按键的状态是之前的,若是第一次按下此键,则返回值状态是释放状态(返回值对应高位为0)。
也就是说,用GetKeyState或GetKeyboardState函数检索虚拟键的状态,这个状态的变化发生在按键消息从系统消息队列中移除之后,消息到达应用程序之前。MSDN中有这样的描述:”
The key status returned from this function changes as a threadreads key messages from its message queue.”
日志钩子函数的lParam参数说明:
lParam是一个EVENTMSG结构:
EVENTMSG STRUCT
message DWORD ? ;系统消息队列中将要移去的消息ID
paramL DWORD ? ;消息的wParam参数
paramH DWORD ? ;消息的lParam参数
time DWORD ? ;消息发生的时间
hwnd DWORD ? ;消息对应的窗口句柄
EVENTMSG ENDS
.if message>= WM_KEYFIRST and message <= WM_KEYLAST
paramLand 00FFh
为虚拟键码
paramLand 0FF00h为扫描码
paramHand 00FFh
为扫描码
.endif
罗云彬老师的《windows环境下的32位汇编语言程序设计》日志钩子程序此处可能有问题,请看的同学注意。
题外话:这个问题困扰了我好几天,最近算是弄明白了点,但是并不是完全清楚,所以请看这篇文章的读者只做下参考。我以前完全没有Windows编程基础,最近学习Windows编程一直靠看罗老师的书和上网查资料,看了不到一个月,很多地方看的并不是明白,理解也不到位。
相关文章推荐
- 键盘消息处理(按下某个键,响应一个函数)
- C++ 关于MFC多线程编程中的一些注意事项 及自定义消息的处理
- WINCE中使用键盘钩子的注意事项
- VC HOOK 键盘钩子 注意事项
- C++ IO操作API及注意事项(包含一个日志类的实现)
- 一个SoapExcept异常的处理以及.NET平台下WebService应用的一点注意事项
- 使用日志钩子实现键盘消息勾挂的例子
- 批处理中日志打印注意事项
- Android Handler处理消息注意事项
- 设置全局键盘钩子 和 注意事项
- ON_MESSAGE消息处理程序注意事项
- 一个能够检查Windows传递给窗口消息处理程序的键盘内容和字符消息的程序
- 使用日志钩子实现键盘消息勾挂的例子[z]
- Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项
- 做一个网站搜索引擎优化项目的注意事项
- TfxSleep,一个可以在等待超时期间处理Windows消息的函数,防止卡死
- 一个简单的键盘钩子程序
- FC 5 中samba服务设置的一个注意事项
- 一个通用的键盘快捷键处理JS
- 请教一个KEYDOWN的处理,想实现输入符A,但面界面上出现B(想实现在英文键盘输入其它语言的字符),重载了CEdit,但不会没出现我要的效果?