为了把这件事情搞明白,我们需要了解一下WM_MOUSEMOVE这一消息的来源(它是如何产生的)。
仅仅是设置一个标志位
当鼠标被用户移动的时候,鼠标会向操作系统上报一个中断,操作系统会判断当前哪个线程应该接收这一鼠标移动消息,然后会在这个线程的硬件输入队列里设置一个标志,来通知线程:”嘿,用户刚刚移动了鼠标,得注意啦”。(其实,在这个时候,通常还会有其他事情发生,不过,我们现在先忽略它们。特别是,如果发生鼠标按钮点击事件,操作系统会维护一大波状态信息来保持虚拟输入状态。)
当线程调用GetMessage来获取下一条消息的时候,如果”鼠标已移动”这一标志被设置了,Windows会检查鼠标的位置并执行通常被认为是鼠标移动的一部分的工作:判断是哪个窗口应该获取消息,然后修改光标并判断应该生成哪种消息(可能是WM_MOUSEMOVE,也有可能是WM_NCMOUSEMOVE)。
如果你了解了上面所讲述的内容,则你应该可以回答这个问题:”为什么当我的鼠标快速移动的时候,我的程序并没有接收到所有的鼠标移动消息?”如果你的程序调用GetMessage的速度很慢的话,则会有多个鼠标中断在调用GetMessage将消息取走之前到达。因为当发生鼠标中断的时候,操作系统仅仅是设置了一个标志位,如果连续发生两个中断而没有调用消息获取函数,则第二个中断也只是设置一个已经被设置过的标志,这毫无疑问是没有任何效果的。最终结果是,第一个中断的行为就好像它已经”丢失”了一样,因为没人会”理会”它。
同时,你也应该可以得到这个问题的答案:”Windows传递鼠标移动消息的速度有多快?”答案是,”你想它有多快,它就有多快”。如果你频繁地调用GetMessage,则你会得到更多的消息。如果你不经常调用GetMessage,则你得到的消息也会非常少。
关于假的WM_MOUSEMOVE消息
接下来,让我们回到本文最初提到的问题:”为什么我总是得到假的WM_MOUSEMOVE消息?”请注意,鼠标消息的传递包括许多工作,通常认为这是鼠标移动的一部分。通常,即使鼠标实际上没有移动,Windows仍希望执行后续工作。最明显的一个例子是,当显示,隐藏或移动一个窗口时,鼠标光标可能会位于与之前所经过的窗口不同的窗口上方(或者在移动的情况下,可能会位于同一窗口的不同部分上方)。Windows需要重新计算鼠标光标(例如,旧窗口可能需要一个箭头光标,而新窗口需要一个手型光标),因此它人为地设置了”鼠标已移动”的标志。这将导致所有后续工作发生,其副作用就是生成了一个假的WM_MOUSEMOVE消息。
如何判断鼠标是否移动过?
因此,如果你的程序想检测鼠标是否移动过,需要做的是:在WM_MOUSEMOVE消息处理例程中添加一个检查,如果鼠标位置与上一个WM_MOUSEMOVE消息报告的位置不同,则表明鼠标已经移动。
![225639dc8b893c5732798acfda71310b.png](https://i-blog.csdnimg.cn/blog_migrate/ccaa8eb664d091794f7a5c382d1e84f7.jpeg)