【问题标题】:Simulating mouse-down event on another window from CGWindowListCreate从 CGWindowListCreate 在另一个窗口上模拟鼠标按下事件
【发布时间】:2017-04-09 21:51:11
【问题描述】:

您可以使用CGWindowListCreate列出当前打开的窗口,例如:

CFArrayRef windowListArray = CGWindowListCreate(kCGWindowListOptionOnScreenOnly|kCGWindowListExcludeDesktopElements, kCGNullWindowID);
NSArray *windows = CFBridgingRelease(CGWindowListCreateDescriptionFromArray(windowListArray));

// stuff here with windows array

CFRelease(windowListArray);

有了这个你可以得到一个特定的窗口,例如Chrome 的一个窗口,位于当前工作区的背景中,但未最小化。我还发现您可以使用 CGEventCreateMouseEvent 在屏幕上的任意位置模拟鼠标点击:

CGEventRef click_down = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, point, kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, click_down);

除了将此事件发送到屏幕上此点下方的最前面的窗口之外,我可以将其发送到后台窗口吗?或者是暂时切换到该窗口(将其置于前面)、单击并切换回前一个最前面的窗口的唯一方法?

这篇文章表明后者是可能的: Cocoa switch focus to application and then switch it back

虽然我很想知道是否可以避免这种情况,但我们是否可以将鼠标点击直接发送到后台的特定窗口而不将其显示出来。我可以为此考虑任何 Objective-C、C 或 C++ 选项。

【问题讨论】:

  • 您的意思是要模拟点击被其他窗口遮挡的窗口部分?如果它没有被遮挡,那么就没有问题。将鼠标放在窗口显示部分上方的位置将导致它被路由到该窗口。否则,您可以尝试 CGEventPostToPSN() 将其直接发布到拥有应用程序的进程,尽管它仍会转到该应用程序内事件位置最前面的窗口。
  • 这里的想法是它被遮蔽了。这样我就可以自动执行一项任务(在当前窗口遮挡的窗口中单击一些 UI),而不会中断我的主要任务。我正在调查 CGEventPostToPSN。看起来 GetProcessForPID 已被弃用?是否有其他方法可以获取进程的 ProcessSerialNumber?
  • 我认为没有现代替代品。我只会使用GetProcessForPID(),如果你发现它有效并且你依赖它,请向 Apple 提交一个错误,要求适当替换 CGEventPostToPSN()
  • CGEventPostToPSN 运行良好,但我觉得 GetProcessForPID 已被弃用。 NSWorkspace launchApplications 还提供了对 PSN 结构所需的 serialnumberLow 和 High 值的访问权限,但该方法也已被弃用,取而代之的是 runningApplications,它没有该信息
  • 应用是否处理后台点击?我不知道 Chrome,但 Safari 和 FireFox 不知道。

标签: objective-c macos


【解决方案1】:

在找到已弃用的 GetPSNForPID 函数的替代方法后,终于可以正常工作了:

NSEvent *customEvent = [NSEvent mouseEventWithType: NSEventTypeLeftMouseDown
                                          location: point
                                     modifierFlags: NSEventModifierFlagCommand
                                         timestamp:[NSDate timeIntervalSinceReferenceDate]
                                      windowNumber:[self.windowID intValue]
                                           context: nil
                                       eventNumber: 0
                                        clickCount: 1
                                          pressure: 0];

CGEvent = [customEvent CGEvent];
CGEventPostToPid(PID, CGEvent);

没有意识到有一个 CGEventPostToPid 方法而不是 CGEventPostToPSN。不需要 ProcessSerialNumber 结构。

【讨论】:

  • 您是否能够真正将鼠标事件发送到非焦点应用?
  • 不可靠,但我不知道我的问题是否是我的目标应用程序是浏览器窗口中基于 Flash 的应用程序。我正在使用内置在 javascript 中的绘图应用程序进行测试,并且在后台绘图时效果很好,但是一旦我尝试使用基于 Flash 的应用程序对其进行测试,我就无法让它触发背景点击。 @user1768741
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多