Programmatically enter text into any application

試著忘記壹切 提交于 2019-12-24 02:35:09

问题


Is there a proof-of-concept Objective-C executable that enters some text into an application and then clicks the mouse, using Apple events and not AppleScript?

e.g. the AppleScript equivalent of

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

It should work on Mac OS X 10.9, preferably be future oriented (backwards compatibility doesn't matter). The context is that I will be calling the Objective-C code from another language.

I'm saying this because I read that:

As of Mac OS X 10.7, the low-level Cocoa API (NSAppleEventDescriptor) still lacks essential functionality (e.g. the ability to send Apple events), while the high-level Cocoa API (Scripting Bridge) is too flawed and limited to be a viable foundation for an appscript-style wrapper.

and:

NSAppleScript can safely be used only on the main thread

so, my goals are:

  1. any application (by name or if current)
  2. any keyboard input or mouse
  3. from C or Objective-C
  4. within a few hundred milliseconds

thanks!


回答1:


Rather than using AppleEvents, the CGEvent API in CoreGraphics framework <https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html> lets you post low-level mouse and keyboard events to the window server.

#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);

You might also consider writing a Service <https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/SysServices/introduction.html>, which lets you provide functionality to other applications through the Service menu in the application menu. Note that you can even assign keyboard shortcuts to Service menu items. Services work via the system pasteboard; this approach may be easier than dealing with raw window server events if you simply need to be able to paste some canned or generated data into another application.




回答2:


I'm not sure if this is what you're looking for, but you may be interested in setting up an NSInvocation object:

- (void)invokeWithTarget:(id)anObject

If you're looking to run some code and 'simulate' a UX environment, it may be valuable to save an invocation and run it.

(Automator?)




回答3:


The best way for achieving your result is using Automator,

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

If you want to achieve this through ObjectiveC, you need to understand "Distributed Objects Architecture". By pairing NSPort and NSInvocation, you can do amazing things, like cross-process and cross-machine method calling.

Here is a guide for that
https://developer.apple.com/librarY/prerelease/mac/documentation/Cocoa/Conceptual/DistrObjects/Concepts/architecture.html



来源:https://stackoverflow.com/questions/25858495/programmatically-enter-text-into-any-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!