1

我正在编写一个简单的 Cocoa 应用程序,该应用程序将从 AppleScript 启动,只是为了将 Quartz 事件发布到另一个应用程序。

不需要用户界面,因此我从 Interface Builder 中删除了窗口,并从 Application Delegate 中删除了它的出口。postClickEvent()我从方法中调用私有方法applicationDidFinishLaunching(_:)。我用 nil mouseEventSource at初始化leftMouseDown和CGEvents并将它们发布在 location 。leftMouseUpmouseCursorPosition (x: 0, y: 0)cghidEventTap

import Cocoa  
  
@NSApplicationMain  
class AppDelegate: NSObject, NSApplicationDelegate {  
  
    func applicationDidFinishLaunching(_ aNotification: Notification) {  
        postClickEvent()  
    }  
  
    func applicationWillTerminate(_ aNotification: Notification) {  
    }  
  
    private func postClickEvent() {  
        let point = CGPoint(x: 0, y: 0)  
  
        let leftMouseDownEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDown, mouseCursorPosition: point, mouseButton: .left)  
        let leftMouseUpEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseUp, mouseCursorPosition: point, mouseButton: .left)  
  
        leftMouseDownEvent?.post(tap: .cghidEventTap)  
        leftMouseUpEvent?.post(tap: .cghidEventTap)  
    }  
}

我希望该应用程序在启动后立即单击左上角并打开 Apple 菜单,但它没有发生。

我可以想到几种可能的解决方案。

  • 在调试器中运行的应用程序可能需要发布低级用户输入事件的权限。应用程序是否需要获得发布 Quartz 事件的权限?
  • 该方法applicationDidFinishLaunching(_:)由默认通知中心在应用程序启动和初始化之后但在收到第一个事件之前发送。也许 postClickEvent()应该从 Application Delegate 的另一个方法调用?
  • 这些事件在初始化时可能需要一个事件源。但是为三个可能的事件源状态 ID 中的任何一个传递初始化的init(stateID:)事件源都不会改变它。
  • 事件可以在应用程序在全屏 Xcode 后获得焦点时发布,太早而无法单击 Apple 菜单项。但是让线程休眠 10 秒并不会改变它。
4

1 回答 1

3

默认使用沙盒是 Xcode 9.0 中 Swift 包管理器的一个新特性。

更新了 macOS 上的包清单解释和包构建以使用沙箱,从而防止网络访问和文件系统修改。这有助于减轻恶意制作的清单的影响。(31107213)

Xcode 发行说明

但是 Quartz Events 与 App Sandbox 不兼容。

您不能沙盒控制另一个应用程序的应用程序。使用 CGEventPost 之类的函数发布键盘或鼠标事件提供了一种规避此限制的方法,因此不允许从沙盒应用程序中发布。

应用沙盒设计指南

运行应用程序会在控制台中留下沙盒违规日志消息,表明应用程序被拒绝人机界面设备控制。

安慰

在 Xcode 目标编辑器中禁用 App Sandbox 允许发布 Quartz 事件。

Xcode

于 2017-11-10T00:31:09.003 回答