mousedown mouseup mousemove事件执行先后顺序_关于WM_MOUSEMOVE消息的真实性

为了把这件事情搞明白,我们需要了解一下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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过鼠标移动的方向来判断顺时针还是逆时针。 首,在mousedown事件中记录下鼠标点击时的坐标(x1, y1)。然后,在mousemove事件中计算当前鼠标位置与鼠标点击时的位置之间的向量(vx, vy)。最后,通过计算向量(vx, vy)与上一次鼠标移动时的向量(uvx, uvy)的旋转方向来判断是顺时针还是逆时针。 具体做法如下: 1. 在mousedown事件中记录下鼠标点击时的坐标(x1, y1)。 ``` let x1, y1; element.addEventListener('mousedown', (event) => { x1 = event.clientX; y1 = event.clientY; }); ``` 2. 在mousemove事件中计算当前鼠标位置与鼠标点击时的位置之间的向量(vx, vy)。 ``` let vx, vy; element.addEventListener('mousemove', (event) => { const x2 = event.clientX; const y2 = event.clientY; vx = x2 - x1; vy = y2 - y1; }); ``` 3. 在mousemove事件中计算向量(vx, vy)与上一次鼠标移动时的向量(uvx, uvy)的旋转方向。 ``` let uvx, uvy; let rotationDirection = null; element.addEventListener('mousemove', (event) => { const x2 = event.clientX; const y2 = event.clientY; if (vx !== undefined && vy !== undefined) { uvx = vx; uvy = vy; vx = x2 - x1; vy = y2 - y1; const crossProduct = uvx * vy - uvy * vx; if (crossProduct > 0) { rotationDirection = 'clockwise'; } else if (crossProduct < 0) { rotationDirection = 'counterclockwise'; } else { rotationDirection = null; } } }); ``` 这样,在mousemove事件中就可以通过计算向量旋转方向来判断是顺时针还是逆时针。需要注意的是,为了避免误判,可以在mousemove事件中增加一些条件判断,例如鼠标是否已经按下等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值