Программно вводить текст в любое приложение

Существует ли проверочный файл Objective-C, который вводит некоторый текст в приложение и затем щелкает мышью, используя события Apple, а не AppleScript?

например, AppleScript эквивалент

tell application "System Events"
 tell process "Safari"
  keystroke "Hello World"
  click
 end tell 
end tell

Он должен работать на Mac OS X 10.9, предпочтительно ориентироваться на будущее (обратная совместимость не имеет значения). Контекст заключается в том, что я буду называть код Objective-C с другого языка.

Я говорю это, потому что я прочитал это:

Начиная с Mac OS X 10.7, низкоуровневому API-интерфейсу Какао (NSAppleEventDescriptor) по-прежнему не хватает необходимой функциональности (например, возможности отправлять события Apple), в то время как высокоуровневый API-интерфейс какао (Мост сценариев) слишком несовершенен и ограничен, чтобы быть жизнеспособным основа для оболочки в стиле appscript.

а также:

NSAppleScript может безопасно использоваться только в основном потоке

Итак, мои цели:

  1. любое приложение (по имени или если текущее)
  2. любой клавиатурный ввод или мышь
  3. от C или Objective-C
  4. в течение нескольких сотен миллисекунд

Спасибо!

3 ответа

Вместо использования AppleEvents API CGEvent в среде CoreGraphics < https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html> позволяет публиковать низкоуровневые события мыши и клавиатуры на сервер окна.

#include <CoreGraphics/CoreGraphics.h>

NSArray *launchedApplications = [[NSWorkspace sharedWorkspace] launchedApplications]; // depreciated but I couldn't find a modern way to get the Carbon PSN
NSPredicate *filter = [NSPredicate predicateWithFormat:@"NSApplicationName = \"TextEdit\""];
NSDictionary *appInfo = [[launchedApplications filteredArrayUsingPredicate:filter] firstObject];
ProcessSerialNumber psn;
psn.highLongOfPSN = [[appInfo objectForKey:@"NSApplicationProcessSerialNumberHigh"] unsignedIntValue];
psn.lowLongOfPSN = [[appInfo objectForKey:@"NSApplicationProcessSerialNumberLow"] unsignedIntValue];

CGEventRef event1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, true); // 'z' key down
CGEventRef event2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, false); // 'z' key up

CGEventPostToPSN(&psn, event1);
CGEventPostToPSN(&psn, event2);

Вы также можете написать "Сервис" < https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/SysServices/introduction.html>, который позволяет предоставлять функциональность другим приложениям через меню "Сервис" в приложении. меню. Обратите внимание, что вы даже можете назначить сочетания клавиш для пунктов меню Сервис. Сервисы работают через системный картон; этот подход может быть проще, чем работа с необработанными событиями сервера окон, если вам просто нужно вставить некоторые консервированные или сгенерированные данные в другое приложение.

Лучший способ достичь вашего результата - использовать Automator,

См. https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/AutomatorConcepts/AutomatorConcepts.pdf

Если вы хотите достичь этого с помощью ObjectiveC, вам необходимо понимать "архитектуру распределенных объектов". Соединяя NSPort и NSInvocation, вы можете делать удивительные вещи, такие как кросс-процессный и кросс-машинный вызов методов.

Вот руководство для этого
https://developer.apple.com/librarY/prerelease/mac/documentation/Cocoa/Conceptual/DistrObjects/Concepts/architecture.html

Я не уверен, что это то, что вы ищете, но вас может заинтересовать настройка объекта NSInvocation:

- (void)invokeWithTarget:(id)anObject

Если вы хотите запустить некоторый код и "смоделировать" среду UX, может быть полезно сохранить вызов и запустить его.

(Automator?)

Другие вопросы по тегам