How to post a Quartz Event after Swift application launch?

孤者浪人 提交于 2019-12-11 07:41:40

问题


I am writing a simple Cocoa app that will be launched from AppleScript just to post a Quartz Event to another app.

There is no need for a user interface so I deleted the window from the Interface Builder and the outlet to it from the Application Delegate. I call a private method postClickEvent() from the method applicationDidFinishLaunching(_:). I initialize leftMouseDown and leftMouseUp CGEvents with nil mouseEventSource at mouseCursorPosition (x: 0, y: 0) and post them at location 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)  
}  

}

I would expect the app as soon as it is launched to click in the top left corner and open the Apple menu but it does not happen.

I can think of several possible solutions.

  • The app that runs in the debugger might need a permission to post a low-level user input event. Does an app need a permission to post a Quartz Event?
  • The method applicationDidFinishLaunching(_:) is sent by the default notification center after the application has been launched and initialized but before it has received its first event. Maybe postClickEvent() should be called from another method of the Application Delegate?
  • The events might need an Event Source at initialization. But passing the Event Source initialized with init(stateID:) for any of the three possible Event Source State IDs does not change it.
  • The events can be posted just when the app receives focus after full screen Xcode so too early to click the Apple menu item. But sleeping the thread for 10 seconds does not change it.

回答1:


Using a sandbox by default is a new feature of Swift Package Manager in Xcode 9.0.

Updated package manifest interpretation and package builds on macOS to use a sandbox, which prevents network access and file system modification. This helps mitigate the effect of maliciously crafted manifests. (31107213)

Xcode Release Notes

But Quartz Events are incompatible with App Sandbox.

You cannot sandbox an app that controls another app. Posting keyboard or mouse events using functions like CGEventPost offers a way to circumvent this restriction, and is therefore not allowed from a sandboxed app.

App Sandbox Design Guide

Running the app leaves a Sandbox Violation log message in the Console that the app was denied Human Interface Device control.

Console

Disabling App Sandbox in the Xcode target editor allows to post a Quartz Event.

Xcode



来源:https://stackoverflow.com/questions/47086375/how-to-post-a-quartz-event-after-swift-application-launch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!