swiftxcodecocoamacos-high-sierracgeventtap

How to post a Quartz Event after Swift application launch?


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.


Solution

  • 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