macOS: simulated mouse event only works when launching binary, not application bundle

大兔子大兔子 提交于 2021-02-16 14:28:05

问题


I have the following code which moves the mouse cursor on a Mac:

void moveCursorPos()
{
  CGPoint ppos;
  ppos.x = 100;
  ppos.y = 100;

  CGEventRef e = CGEventCreateMouseEvent(nullptr, kCGEventMouseMoved, ppos, kCGMouseButtonLeft);
  CGEventPost(kCGHIDEventTap, e);
  CFRelease(e);
}

It works when I run my software directly from its binary - e.g. ./foo.app/Contents/MacOS/foo . It does not not work when I start it through open foo.app. Doing open ./foo.app/Contents/MacOS/foo works.

The first time I launched it and called that function, macOS asked me for the permission to use accessibility APIs (or something in that vein), which I granted - if I go to the "Accessibility > Privacy" pane of the security settings of macOS, all checkboxes are checked, everything is granted to foo, etc...

  • How do I fix it on my machine ?
  • What can I do in terms of code so that the users of my software do not ever encounter that issue as it breaks a core UI interaction of my software ?

回答1:


How do I fix it on my machine?

It really depends on what you did. I usually broke these things when I run an app from Xcode directly, distribution, ... and all of them have same bundle identifier (one entry in System Preferences, but more binaries around).

To reset Accessibility for your app just run:

sudo tccutil reset Accessibility com.your.bundle.Identifier

It will reset Accessibility settings for all occurrences of your binaries and you can start again.

What can I do in terms of code so that the users of my software do not ever encounter that issue as it breaks a core UI interaction of my software?

Do the following in your AppDelegate.applicationDidFinishLaunching:

acquireAccessibilityPrivileges(acquired: {
    self.moveCursorPos()
}, nope: {
    NSApp.terminate(self)
})

Other functions:

func acquireAccessibilityPrivileges(acquired: @escaping () -> Void, nope: @escaping () -> Void) {
    let options = [kAXTrustedCheckOptionPrompt.takeUnretainedValue(): true]
    let enabled = AXIsProcessTrustedWithOptions(options as CFDictionary)

    if enabled {
        acquired()
    } else {
        let alert = NSAlert()
        alert.messageText = "Enable XYZ"
        alert.informativeText = "Click OK once you enabled XYZ in System Preferences - ..."
        alert.beginSheetModal(for: self.window, completionHandler: { response in
            if AXIsProcessTrustedWithOptions(options as CFDictionary) {
                acquired()
            } else {
                nope()
            }
        })
    }
}

func moveCursorPos() {
    let event = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: CGPoint(x: 100, y: 100), mouseButton: .left)
    event?.post(tap: .cghidEventTap)
}

open foo.app vs ./foo

There's also one thing to be aware of - the difference between open foo.app, ./foo.app/Contents/MacOS/foo, ...

open Foo.app:

  • Foo.app needs this accessibility permissions
-+= 00001 root /sbin/launchd
 |--= 83677 zrzka /Users/zrzka/Desktop/Foo.app/Contents/MacOS/Foo

Foo.app/Contents/MacOS/Foo:

  • Iterm.app needs this accessibility permissions
-+= 00001 root /sbin/launchd
 |-+= 53984 zrzka /Applications/iTerm.app/Contents/MacOS/iTerm2
 | |-+= 53986 zrzka /Applications/iTerm.app/Contents/MacOS/iTerm2 --server /usr/bin/login -fpl zrzka /Applications/iTerm.app/Contents/MacOS/iTerm2 --launch_shell
 | | \-+= 53987 root /usr/bin/login -fpl zrzka /Applications/iTerm.app/Contents/MacOS/iTerm2 --launch_shell
 | |   \-+= 53988 zrzka -zsh
 | |     \--= 84461 zrzka Foo.app/Contents/MacOS/Foo

open Foo.app/Contents/MacOS/Foo:

  • Terminal.app is launched and Foo in it
  • That's because I do use iTerm, but the default one is Terminal
  • Terminal.app needs this accessibility permissions
-+= 00001 root /sbin/launchd
 |-+= 73320 zrzka /System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal
 | \-+= 75674 root login -pf zrzka
 |   \-+= 75679 zrzka -zsh
 |     \--= 75717 zrzka /Users/zrzka/Desktop/Foo.app/Contents/MacOS/Foo

More tips

It happens, from time to time, that my app no longer appears in the System Preferences - Security & Privacy - Accessibility. I don't know why, but it's somehow connected with my tccutil resets. Open Finder and drag & drop the Foo.app into the pane.



来源:https://stackoverflow.com/questions/61843481/macos-simulated-mouse-event-only-works-when-launching-binary-not-application-b

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