Swift macOS: how to paste into another application

I am writing a helper application for Mac OS 10.10+ using swift. I need to be able to embed content from a shared NSPasteboard into an application that was previously active.

Just to make it clear: I need to paste into another application.

It should work as follows:

  • User is using a random application.

  • Since the user cannot press cmd + v due to disability, they make a gesture that activates my application (this part is completed and is beyond the scope of this question).

  • My application becomes active, and now I need to simulate the Paste action in the application that the user used in advance. This is a bit that I do not know how to do.

  • Finally, the active active application must be activated again.

Please note that the application must be sent to the AppStore.

+5
source share
3 answers

In the simplest case, you need to do two things:

However, the bad news is that, as you say, you need to do this in the App Store application, your application must be inside the sandbox and requires temporary permission com.apple.security.temporary-exception.apple-events to send Events in System Events directly refer to Apple documentation :

requesting the necessary temporary exceptions for apple-events for Finder and system events is likely to lead to a rejection during the viewing process of the application, since providing access to these processes gives your application full support for most of the operating system. For tasks at the system level, use other methods, as discussed above.

There is also a way to take step # 2 using assistive technologies, but this will also not work inside the sandbox. In fact, what you are trying to do (activate an external arbitrary application and control it) has a significant effect on the fact that an isolated program is designed to prevent you from doing it.

Fortunately, since macOS 10.8 now hosts NSUserAppleScriptTask , which runs outside of the sandbox.

There is an NSUserAppleScriptTask twist: scripts executed with NSUserAppleScriptTask must be placed in the script application directory, and your application cannot write to it, but only read from it.

This objc.io article shows an example of how you can request write access to a security directory for a script directory to be able to write your script to it; Annoying for yourself and your user, you should open an open dialog for the first time, therefore, and you need to save a bookmark with a security area so that you do not need to repeat the exercise, but so that you can best perform inside the sandbox.

Your only other route besides jumping with NSUserAppleScriptTask hoops, as far as I know, is to convince Apple that it is really a good idea to accept your application with a temporary right that allows it to script System Events (I will not use my breath).

+4
source

I'm sure you can do this using Apple Events, but be sure to set up a temporary exception to be able to send messages to other applications.

0
source

I found these commands to simulate cut / copy / paste using Foundation:

func pastematchstyle () {

 let event1 = CGEvent(keyboardEventSource: nil, virtualKey: 0x09, keyDown: true); // opt-shft-cmd-v down event1?.flags = [CGEventFlags.maskCommand, CGEventFlags.maskShift, CGEventFlags.maskAlternate] event1?.post(tap: CGEventTapLocation.cghidEventTap); let event2 = CGEvent(keyboardEventSource: nil, virtualKey: 0x09, keyDown: false); // opt-shf-cmd-v up 

//event2?.flags = [CGEventFlags.maskCommand, CGEventFlags.maskShift, CGEventFlags.maskAlternate] event2? .post (tap: CGEventTapLocation.cghidEventTap);

}

func paste () {

 let event1 = CGEvent(keyboardEventSource: nil, virtualKey: 0x09, keyDown: true); // cmd-v down event1?.flags = CGEventFlags.maskCommand; event1?.post(tap: CGEventTapLocation.cghidEventTap); let event2 = CGEvent(keyboardEventSource: nil, virtualKey: 0x09, keyDown: false) // cmd-v up 

//event2?.flags = CGEventFlags.maskCommand event2? .post (tap: CGEventTapLocation.cghidEventTap)

}

func pasteresults () {

 let event1 = CGEvent(keyboardEventSource: nil, virtualKey: 0x09, keyDown: true); // shft-cmd-v down event1?.flags = [CGEventFlags.maskCommand, CGEventFlags.maskShift] event1?.post(tap: CGEventTapLocation.cghidEventTap); let event2 = CGEvent(keyboardEventSource: nil, virtualKey: 0x09, keyDown: false); // shf-cmd-v up 

//event2?.flags = [CGEventFlags.maskCommand, CGEventFlags.maskShift]; event2? .post (tap: CGEventTapLocation.cghidEventTap);

}

func cut () {

 let event1 = CGEvent(keyboardEventSource: nil, virtualKey: 0x07, keyDown: true); // cmd-x down event1?.flags = CGEventFlags.maskCommand; event1?.post(tap: CGEventTapLocation.cghidEventTap); let event2 = CGEvent(keyboardEventSource: nil, virtualKey: 0x07, keyDown: false); // cmd-x up 

//event2?.flags = CGEventFlags.maskCommand; event2? .post (tap: CGEventTapLocation.cghidEventTap);

}

func copy () {

 let event1 = CGEvent(keyboardEventSource: nil, virtualKey: 0x08, keyDown: true); // cmd-c down event1?.flags = CGEventFlags.maskCommand; event1?.post(tap: CGEventTapLocation.cghidEventTap); let event2 = CGEvent(keyboardEventSource: nil, virtualKey: 0x08, keyDown: false); // cmd-c up 

//event2?.flags = CGEventFlags.maskCommand; event2? .post (tap: CGEventTapLocation.cghidEventTap);

}

func copystyle () {

 let event1 = CGEvent(keyboardEventSource: nil, virtualKey: 0x08, keyDown: true); // opt-cmd-c down event1?.flags = [CGEventFlags.maskCommand, CGEventFlags.maskAlternate]; event1?.post(tap: CGEventTapLocation.cghidEventTap); let event2 = CGEvent(keyboardEventSource: nil, virtualKey: 0x08, keyDown: false); // opt-cmd-c up // event2?.flags = CGEventFlags.maskCommand; event2?.post(tap: CGEventTapLocation.cghidEventTap); 

}

func pastestyle () {

 let event1 = CGEvent(keyboardEventSource: nil, virtualKey: 0x07, keyDown: true); // opt-cmd-v down event1?.flags = [CGEventFlags.maskCommand, CGEventFlags.maskAlternate]; event1?.post(tap: CGEventTapLocation.cghidEventTap); let event2 = CGEvent(keyboardEventSource: nil, virtualKey: 0x07, keyDown: false); // opt-cmd-v up // event2?.flags = CGEventFlags.maskCommand; event2?.post(tap: CGEventTapLocation.cghidEventTap); 

}

0
source

Source: https://habr.com/ru/post/1258369/


All Articles