2

I have a menubar application without a dock icon or global menu, it's just a StatusItem and a Window.

I've got it wired up to a hotkey which activates the window and upon deactivating the window I am able to send focus back to the previously active application.

How can I send an NSString to the active textarea in the other application, as if the user had typed it directly?

I think it might be possible using accessibility features. I'd like to avoid using AppleScript if at all possible.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
johndbritton
  • 2,652
  • 1
  • 19
  • 20

2 Answers2

1

From the focused UI element, you'll need to get two things:

Now, the straightforward approach would be to just get those two attributes, but that's actually the wrong solution.

The problem is that the value of the value attribute is a plain string. If the element is a rich text view, you'll lose any formatting or embedded objects that the user might have. That would be bad.

So the correct way to get the value is to get the element's number of characters, construct a range starting at zero with that number as its length, and then get the attributed string for that range. If that fails, then you get the plain value.

Once you have both the value (as either an attributed string or a plain string) and the selected range, replace the selected text range within the value with the text you want to insert. If the user has nothing selected, the range will be an empty range (length zero) at the position of the insertion point, and the replacement will effectively be an insertion.

Then, set the element's value to your amended string. (I can only hope that setting it to an attributed string will work.)

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
0

I ended up using the pasteboard and CGEventCreateKeyboardEvent() to mimic the [cmd+v] keyboard shortcut for pasting.

Before activating my window, I record the previous application:

_previousApplication = [[notification userInfo] objectForKey:NSWorkspaceApplicationKey];

After I dismiss my window, I activate the previous application:

[_previousApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps];

Then paste the NSString:

#define KEY_CODE_v ((CGKeyCode)9)

void DCPostCommandAndKey(CGKeyCode key) {
    CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);

    CGEventRef keyDown = CGEventCreateKeyboardEvent(source, key, TRUE);
    CGEventSetFlags(keyDown, kCGEventFlagMaskCommand);
    CGEventRef keyUp = CGEventCreateKeyboardEvent(source, key, FALSE);

    CGEventPost(kCGAnnotatedSessionEventTap, keyDown);
    CGEventPost(kCGAnnotatedSessionEventTap, keyUp);

    CFRelease(keyUp);
    CFRelease(keyDown);
    CFRelease(source);
}

DCPostCommandAndKey(KEY_CODE_v);
johndbritton
  • 2,652
  • 1
  • 19
  • 20