I need to send keystrokes to front most app from my cooca app.
I already have working code for it by using CGEventCreateKeyboardEvent()
and AXUIElementPostKeyboardEvent()
, but it only works if app is not sandboxed.
I have searched google for the same, but didn't find any working solution.
I saw that a Text app and few others doing the same thing in sandboxed environment, so i am wondering, if someone help me to figure out, that how aText.app and others are able to send keystrokes in sandbox environment.
Thanks,
This is actually possible. I have made an example app available here - SendKey at GitHub
I took the easy road and started with a simple AppleScript:
delay 5
tell application "System Events"
repeat 10 times
keystroke "#"
end repeat
end tell
The 'delay' in the script simply gives me enough time to make a text editor the frontmost application. I would suggest starting with just running this script to see what it does.
Then, I created an Xcode project using the default Application template and wrote:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSString* scriptPath = [[NSBundle mainBundle] pathForResource:@"sendkey" ofType:@"scpt"];
NSURL* scriptURL = [NSURL fileURLWithPath:scriptPath];
NSDictionary* errors;
NSAppleScript* script = [[NSAppleScript alloc] initWithContentsOfURL:scriptURL error:&errors];
NSLog( @"%@", errors );
[script executeAndReturnError:&errors];
NSLog( @"%@", errors );
}
I tested this without turning on sandboxing to verified it works and it did. Then I turned on Sandboxing and, of course, it broke. But, fortunately, there is a way around that. For now, Apple is providing a temporary entitlement called com.apple.security.temporary-exception.apple-events. And, you can request the exception be granted for 'com.apple.systemevents'. This is what my entitlements file looks like:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.temporary-exception.apple-events</key>
<array>
<string>com.apple.systemevents</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true />
</dict>
</plist>
Once I added this entitlement to my sandboxed app and signed it, it worked as expected again.
Now, if you want to send other keys, this question & answer will demonstrate how to build your script on the fly - Passing variables to an applescript.
Of course, once you have all of these working, you can probably turn to NSAppleEventDescriptor and related classes to build the event in code, but I haven't played with that technique.
Please note that Apple does suggest you do the following when using a temporary entitlement:
If you choose not to sandbox your app now or to use a temporary
exception entitlement, use Apple’s bug reporting system to let Apple
know about the issue you are encountering. Apple considers feature
requests as it develops the OS X platform. Also, be sure use the
Review Notes field in iTunes Connect to explain why the exception is
needed.