Отправлять нажатия клавиш в самое ближайшее приложение из песочницы cocoa.

Мне нужно отправить нажатия клавиш для большинства приложений из моего приложения для cooca.

У меня уже есть рабочий код для него с помощью CGEventCreateKeyboardEvent() и AXUIElementPostKeyboardEvent(), но он работает только в том случае, если приложение не изолировано.

Я искал google для этого же, но не нашел никакого рабочего решения.

Я видел, что текстовое приложение и несколько других делают то же самое в изолированной среде, поэтому мне интересно, если кто-то поможет мне понять, что как aText.app и другие могут отправлять нажатия клавиш в среде песочницы.

Спасибо,

Ответ 1

Это действительно возможно. Я сделал пример приложения, доступного здесь - SendKey at GitHub

Я взял легкий путь и начал с простого AppleScript:

delay 5

tell application "System Events"
    repeat 10 times
        keystroke "#"
    end repeat
end tell

"Задержка" в script просто дает мне достаточно времени, чтобы сделать текстовый редактор самым передним приложением. Я бы предложил начать с этого script, чтобы увидеть, что он делает.

Затем я создал проект Xcode с использованием шаблона приложения по умолчанию и написал:

- (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 );
}

Я протестировал это, не включив песочницу, чтобы проверить, работает ли она, и это произошло. Затем я включил песочницу и, разумеется, сломался. Но, к счастью, есть способ обойти это. На данный момент Apple предоставляет временное право, называемое com.apple.security.temporary-exception.apple-events. И вы можете запросить исключение для "com.apple.systemevents". Вот как выглядит мой файл прав:

<?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>

Как только я добавил это право на свое изолированное приложение и подписал его, он снова работал как ожидается.

Теперь, если вы хотите отправить другие ключи, этот вопрос и ответ продемонстрируют, как построить ваш script на лету - Передача переменных в applescript.

Конечно, как только у вас все эти работы, вы, вероятно, можете обратиться к NSAppleEventDescriptor и связанным с ним классам, чтобы построить событие в коде, но я не играл с этой техникой.

Обратите внимание, что Apple предлагает вам сделать следующее при использовании временного права:

Если вы решили не добавлять в песочницу приложение или использовать временную исключение, используйте систему отчетов об ошибках Apple, чтобы Apple узнайте о проблеме, с которой вы сталкиваетесь. Apple считает, что функция когда разрабатывается платформа OS X. Кроме того, обязательно используйте В разделе "Примечания" в iTunes Connect объясните, почему исключение необходимо.