Программно вводить текст в любое приложение
Существует ли проверочный файл 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 может безопасно использоваться только в основном потоке
Итак, мои цели:
- любое приложение (по имени или если текущее)
- любой клавиатурный ввод или мышь
- от C или Objective-C
- в течение нескольких сотен миллисекунд
Спасибо!
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,
Если вы хотите достичь этого с помощью ObjectiveC, вам необходимо понимать "архитектуру распределенных объектов". Соединяя NSPort и NSInvocation, вы можете делать удивительные вещи, такие как кросс-процессный и кросс-машинный вызов методов.
Вот руководство для этого
https://developer.apple.com/librarY/prerelease/mac/documentation/Cocoa/Conceptual/DistrObjects/Concepts/architecture.html
Я не уверен, что это то, что вы ищете, но вас может заинтересовать настройка объекта NSInvocation:
- (void)invokeWithTarget:(id)anObject
Если вы хотите запустить некоторый код и "смоделировать" среду UX, может быть полезно сохранить вызов и запустить его.
(Automator?)