Delphi - 识别鼠标点击源(硬件与虚拟点击)

Delphi - identify mouse click source (hardware vs virtual click)

这次我很难找到标题...

我正在使用 windows 挂钩 ( TMOUSEHOOKSTRUCT ~ WH_MOUSE ) 来跟踪鼠标移动和鼠标按钮点击...

一切正常,但是,我想知道是否有办法确定鼠标 move/click 来源?

是否可以通过设备 ID 或源类型(鼠标、轨迹球、触摸屏...)识别它,或者至少它是否是从硬件源发送的(又名,它是硬件或一些鼠标记录器宏,或其他应用程序的 "SetCursor" 程序)。

我在这里寻找的主要目标是找到一种方法来阻止使用鼠标记录器在我的应用程序中进行点击的能力(所以在聚焦时,我会启动一个鼠标钩子,以防万一移动/点击是由软件完成的,我会忽略所做的任何操作..)

这可能会被问为 "How to block mouse recorder macros in my app",但我更希望看到一个实际的解决方案来识别来源(以及主要答案),因为它也可能有其他用途。

谢谢。

编辑: 一种方法是检查鼠标移动是快速还是缓慢(就像实际移动鼠标一样)。但是,这里的问题仍然存在于触摸屏上。 虽然,另一方面 - Windows 确实检测到何时使用了触摸(光标被更改为屏幕上的点),所以肯定有一种方法至少可以将鼠标与触摸事件分开 -> 并且知道这已经解决了很多,加起来仅在鼠标上下降 snap-actions...

Raymond Chen 总结在 this blog post

There's no point discussing the possibility that the sender of the message is playing tricks and lying to you because (1) your program should just go along with the ruse and respond to fake [menu] messages as if they were real [menu] messages, because (2) there's no way to tell that you're being lied to anyway.

而他的this blog post表明所有的输入最终都经过同一个队列,所以即使Windows也不知道真实输入和模拟输入的区别

您应该考虑直接从硬件使用 Raw Input API to receive WM_INPUT 消息。 SetCursor()SendInput()、宏播放器等无法模拟这些消息。并且您将能够区分来自不同设备的输入,但如果使用多个鼠标设备则不需要 type 鼠标。虽然,由于轨迹球可能比标准鼠标具有更多功能,它可能将自己表示为 HID 设备而不是鼠标设备。

至于触摸屏,这种类型的输入会生成 WM_TOUCH 消息,也无法模拟。

因此,在 WM_INPUTWM_TOUCH 之间,您至少可以区分硬件鼠标输入和触摸屏输入。除此之外,模拟输入将生成标准 WM_MOUSE...WM_(L|M|R|X)BUTTON... 消息,这些消息无法区分硬件输入和模拟输入,即使在较低级别的鼠标挂钩中也是如此。您可能需要跟踪 WM_INPUT/WM_TOUCH 消息并将它们与其他消息进行匹配,如果找不到匹配项,则假设正在模拟输入。