4

One of my app's feature is detect keyDown event and do someting for some specific keys.

So, I use CGEventTapCreate to solve my problem and my code is like this:

   if let tap = CGEventTapCreate(.CGHIDEventTap, .HeadInsertEventTap, .Default, CGEventMask(1 << CGEventType.KeyDown.rawValue), callBack, nil) {
       let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)
       CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode)
       CGEventTapEnable(tap, true)
       CFRunLoopRun()
   }

Also, I deal with the process trust like:

let options = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString: false]
let processTrusted = AXIsProcessTrustedWithOptions(options)
if processTrusted {
    // do CGEventTapCreate()
} else {
    // check again 1s later
    performSelector("checkMethod", withObject: nil, afterDelay: 1)
}

It will be called per second until processTrusted is true.

Then strange thing happened:

When I run the app in Xcode and add trust Xcode in Privacy_Accessibility it all work fine. But When I run it with archive the app and Export as a Mac Application to my desktop, CGEventTapCreate() just not work.

After that I found this post Enable access for assistive devices programmatically on 10.9, it notice me that I need to relaunch the app after AXIsTrustedProcess().

You know, it's not a good idea to tell users to relaunch the app themselves. So I try to relaunch it programmatically and add these code into if processTrusted {}:

NSWorkspace.sharedWorkspace().launchApplication(NSProcessInfo.processInfo().processName)
NSApplication.sharedApplication().terminate(nil)

In other words, when I tick the app in Privacy_Accessibility, it will relaunch automatically.

Here comes another strange thing:

The app truly terminate and launch automatically. But when it finish relaunch, the app's Privacy_Accessibility is not tick.

It's really confuse me a lot, I hope someone will tell me the right way to deal with process trust and execute CGEventTapCreate() correctly.

Thanks!

Community
  • 1
  • 1
Duelsol
  • 149
  • 9
  • I'm pretty sure that an application that you launch inherits your current permissions, but don't have references for an official answer. That is, because your app lacks the Accessibility "trust", when it calls `launchApplication`, that process also is not "trusted". – Smilin Brian Feb 25 '16 at 00:51
  • @Smilin Brian It makes sense. According to this, can I refresh the Accessibility programmatically? Or is there a method which will launch the application with it's lastest Accessibility? – Duelsol Feb 25 '16 at 08:35
  • The trick, I think, is to get the system to launch the app so that *it* is the "parent" process. Maybe something like: `[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"sleep 3 ; /usr/bin/open '%@'", [[NSBundle mainBundle] bundlePath]], nil]];` – Smilin Brian Feb 26 '16 at 19:08
  • @SmilinBrian Thanks, you're right! I use you code and then call `NSApplication.sharedApplication().terminate(nil)`, the app then relaunch with the right Accessibility. So, please answer this question and I will set it as the right answer. – Duelsol Feb 28 '16 at 14:12
  • Did you succeed to detect when user allow the app in the System preferences? I am trying to achieve a similar thing but until restarting the app, AXIsProcessTrustedWithOptions always returns false even when it shouldn't. – AP. Sep 16 '16 at 15:39
  • @AP. Yeah, I did. If you run your app by Xcode, you should trust Xcode in Privacy_Accessibility. – Duelsol Sep 20 '16 at 13:14

1 Answers1

4

Polling AXIsProcessTrusted and automatically relaunching is a nice touch. Users are often confused by this process, so anything that helps make it easier for them is good.

I'm pretty sure that an application that you launch inherits your current permissions, but don't have references handy to back that up. I have found that when debugging an application with CGEventTaps, I also have to give Xcode the Accessibility permissions that my app requests/requires.

But you can work around this by getting the system to launch your app for you. Try:

[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"sleep 3 ; /usr/bin/open '%@'", [[NSBundle mainBundle] bundlePath]], nil]];
Smilin Brian
  • 980
  • 8
  • 18