模拟鼠标点击而不移动光标
Posted
技术标签:
【中文标题】模拟鼠标点击而不移动光标【英文标题】:Simulate mouse click without moving the cursor 【发布时间】:2016-01-18 01:58:39 【问题描述】:我编写了一个应用程序来检测所有活动的 Windows 并将它们放入一个列表中。
有没有一种方法可以模拟鼠标点击屏幕上相对于 Windows 位置的位置而不实际移动光标?
我无权访问应该被点击的按钮句柄,只能访问窗口的句柄
【问题讨论】:
错误的问题。这是您应该问的问题的答案:UI Automation。如需现场演示,请查看 SDK 随附的 Inspect 工具。 你想在一些随机的窗口列表中按下按钮似乎很奇怪。也许你正在寻找SetForegroundWindow
@Barmak Shemirani,我有多个需要在屏幕上同时监控的客户端窗口,该程序应该将每个具有特定标题的窗口放在一个列表中并放置在每个屏幕上以特定模式显示 12 个。到目前为止,这是可行的,我只需要一个附加功能,即每 n 分钟单击一次 3rd 方应用程序中的一个按钮即可首先打开这些窗口。
【参考方案1】:
有没有一种方法可以模拟鼠标点击屏幕上相对于 Windows 位置的位置而不实际移动光标?
回答您的具体问题 - 否。鼠标点击只能指向点击时鼠标光标实际所在的位置。模拟鼠标输入的正确方法是使用SendInput()
(或在旧系统上使用mouse_event()
)。但是这些函数将模拟事件注入到实际鼠标驱动程序发布到的同一输入队列中,因此它们将对鼠标光标产生物理影响 - 即在屏幕上移动它等等。
How do I simulate input without SendInput?
SendInput 在输入堆栈的底层运行。 它只是进入键盘和鼠标驱动程序使用的相同输入机制的后门,告诉窗口管理器用户已生成输入。 SendInput 函数不知道输入会发生什么。这是由更高级别的窗口管理器处理的,例如命中测试鼠标输入以查看消息最初应该传递到哪个窗口的组件。
When something gets added to a queue, it takes time for it to come out the front of the queue
当您调用 SendInput 时,您将输入数据包放入系统硬件输入队列。 (注意:不是官方术语。这就是我今天所说的。)这与物理设备报告事件时硬件设备驱动程序堆栈使用的输入队列相同。
消息进入硬件输入队列,由原始输入线程提取。原始输入线程以高优先级运行,因此它可能会很快启动它,但在多核机器上,您的代码可以在第二个核心运行原始输入线程时继续运行。原始输入线程在将事件出列后需要做一些事情。如果有低级别的输入钩子,它必须调用这些钩子中的每一个,看看它们中是否有任何一个想要拒绝输入。 (而这些钩子可能需要谁知道多长时间才能决定。)只有在所有低级钩子在输入上签字后,原始输入线程才允许修改输入状态并导致 GetAsyncKeyState 报告密钥是向下。
执行您要求的唯一真正方法是找到位于所需屏幕坐标处的 UI 控件的HWND
。然后你可以:
直接向它发送WM_LBUTTONDOWN
和WM_LBUTTONUP
消息。或者,在标准 Win32 按钮控件的情况下,改为发送单个 BM_CLICK
消息。
使用UI Automation API 的AccessibleObjectFromWindow()
函数访问控件的IAccessible
接口,然后调用其accDoDefaultAction()
方法,按钮会点击它。
话虽如此,...
我无权访问应该被点击的按钮句柄。
您可以访问任何具有HWND
的内容。例如,看看WindowFromPoint()
。您可以使用它找到占据所需屏幕坐标的按钮的HWND
(当然需要注意的是:WindowFromPoint, ChildWindowFromPoint, RealChildWindowFromPoint, when will it all end?)。
【讨论】:
谢谢,不知道获取按钮手柄这么简单,我试试看! @ColdZer0:如果有支持按钮控件的本机窗口,那就很容易了。通常情况并非如此。 Web 浏览器通常不使用本机控件。 Qt 应用程序也不行。不过,它们都支持 UI 自动化。 @IInspectable:是的。如果坐标处的实际HWND
不是Win32 按钮,则不能使用BM_CLICK
。但是,您仍然会有一个真正的HWND
,并且在这些坐标处向它发送WM_LBUTTON...
会根据需要向下传递到它碰巧持有的任何非窗口控件。但是,如果它支持 UI 自动化,那也有帮助,因为您将能够枚举其无法访问的子控件。以上是关于模拟鼠标点击而不移动光标的主要内容,如果未能解决你的问题,请参考以下文章