模拟鼠标点击而不移动光标

2021-12-18 00:00:00 function windows button winapi c++

我编写了一个应用程序来检测所有活动的 Windows 并将它们放入一个列表中.

I wrote an application that detects all active Windows and puts them into a list.

有没有一种方法可以在不实际移动光标的情况下模拟在屏幕上相对于 Windows 位置的某个点上的鼠标单击?

Is there a way to simulate a mouseclick on a spot on the screen relative to the Windows location without actually moving the cursor?

我无权访问应该点击的按钮句柄,只能访问窗口的句柄

I don't have access to the buttons handle that is supposed to be clicked, only to the handle of the window

推荐答案

有没有一种方法可以在不实际移动光标的情况下模拟在屏幕上相对于 Windows 位置的某个点上的鼠标单击?

Is there a way to simulate a mouseclick on a spot on the screen relative to the Windows location without actually moving the cursor?

要回答您的具体问题 - 否.鼠标单击只能指向单击时鼠标光标实际所在的位置.模拟鼠标输入的正确方法是使用 SendInput()(或 mouse_event() 在旧系统上).但是这些函数将模拟事件注入到实际鼠标驱动程序发送到的相同输入队列中,因此它们将对鼠标光标产生物理影响 - 即在屏幕上移动它等.

To answer your specific question - NO. Mouse clicks can only be directed where the mouse cursor actually resides at the time of the click. The correct way to simulate mouse input is to use SendInput() (or mouse_event() on older systems). But those functions inject simulated events into the same input queue that the actual mouse driver posts to, so they will have a physical effect on the mouse cursor - ie move it around the screen, etc.

如何在没有 SendInput 的情况下模拟输入?

SendInput 在输入堆栈的底层运行.它只是键盘和鼠标驱动程序使用的相同输入机制的一个后门来告诉窗口管理器用户已生成输入.SendInput 函数不知道输入会发生什么.这是由更高级别的窗口管理器处理的,例如点击测试鼠标输入以查看消息最初应该传递到哪个窗口的组件.

SendInput operates at the bottom level of the input stack. It is just a backdoor into the same input mechanism that the keyboard and mouse drivers use to tell the window manager that the user has generated input. The SendInput function doesn't know what will happen to the input. That is handled by much higher levels of the window manager, like the components which hit-test mouse input to see which window the message should initially be delivered to.

当某些内容被添加到队列时,它需要时间从队列的前面出来

当您调用 SendInput 时,您将输入数据包放入系统硬件输入队列.(注意:不是官方术语.这正是我今天所说的.)这与物理设备报告事件时硬件设备驱动程序堆栈使用的输入队列相同.

When you call Send-Input, you're putting input packets into the system hardware input queue. (Note: Not the official term. That's just what I'm calling it today.) This is the same input queue that the hardware device driver stack uses when physical devices report events.

消息进入硬件输入队列,原始输入线程在那里接收它们.原始输入线程以高优先级运行,因此它可能会非常快地接收它,但是在多核机器上,您的代码可以在第二个核心运行原始输入线程时继续运行.并且原始输入线程在事件出列后需要做一些事情.如果有低级输入钩子,它必须调用这些钩子中的每一个,看看是否有任何一个想要拒绝输入.(而那些钩子可能需要谁知道多长时间才能决定.)只有在所有低级钩子在输入上签字后,原始输入线程才允许修改输入状态并导致 GetAsyncKeyState 报告关键是向下.

The message goes into the hardware input queue, where the Raw Input Thread picks them up. The Raw Input Thread runs at high priority, so it's probably going to pick it up really quickly, but on a multi-core machine, your code can keep running while the second core runs the Raw Input Thread. And the Raw Input thread has some stuff it needs to do once it dequeues the event. If there are low-level input hooks, it has to call each of those hooks to see if any of them want to reject the input. (And those hooks can take who-knows-how-long to decide.) Only after all the low-level hooks sign off on the input is the Raw Input Thread allowed to modify the input state and cause Get-Async-Key-State to report that the key is down.

实现您所要求的唯一真正方法是找到位于所需屏幕坐标处的 UI 控件的 HWND.然后你可以:

The only real way to do what you are asking for is to find the HWND of the UI control that is located at the desired screen coordinates. Then you can either:

  1. 发送WM_LBUTTONDOWNWM_LBUTTONUP 直接向它发送消息.或者,对于标准的 Win32 按钮控件,发送一个 BM_CLICK 消息.

使用AccessibleObjectFromWindow()功能> 访问控件的IAccessible 接口,然后调用它的 accDoDefaultAction() 方法,对于按钮将点击它.

use the AccessibleObjectFromWindow() function of the UI Automation API to access the control's IAccessible interface, and then call its accDoDefaultAction() method, which for a button will click it.

话虽如此,...

我无权访问应该点击的按钮句柄.

I don't have access to the buttons handle that is supposed to be clicked.

您可以访问任何具有 HWND 的内容.看看 WindowFromPoint(),例如.您可以使用它来查找占据所需屏幕坐标的按钮的 HWND(当然有警告:WindowFromPoint、ChildWindowFromPoint、RealChildWindowFromPoint,什么时候结束?).

You can access anything that has an HWND. Have a look at WindowFromPoint(), for instance. You can use it to find the HWND of the button that occupies the desired screen coordinates (with caveats, of course: WindowFromPoint, ChildWindowFromPoint, RealChildWindowFromPoint, when will it all end?).

相关文章