0

I want to use Swift (Xcode 13.2.1) to send a Cmd-C and Cmd-V to copy selected text in macOS 11.6 (Big Sur) as described in several StackOverflow posts (e.g. How to obtain the selected text from the frontmost application in macOS?).

I was carefully following the existing recommendations to set the right options for the macOS Security & Privacy framework:

  • Disabled App Sandbox:
     <key>com.apple.security.app-sandbox</key>
     <false/>
    
  • Added "Hardened Runtime" and enabled "Apple Events"
  • Added to Info.plist:
     <key>NSAppleEventsUsageDescription</key>
     <string>NSApplication</string>
    
  • Disabled and enabled the apps checkbox in "Security & Privacy" -> "Accessibility" after every build.

But, no luck. The interesting thing is, when I'm using the same code in a "Command Line Tool" project (no GUI) everything works fine.

Here is my code:


    let pasteboard = NSPasteboard.general
    
    pasteboard.clearContents()
    
    let source = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)
    
    let cmdKey: UInt16 = 0x38
    let cKey: UInt16 = 0x08
    
    let cmdDown = CGEvent(keyboardEventSource: source, virtualKey: cmdKey, keyDown: true)
    let cmdUp = CGEvent(keyboardEventSource: source, virtualKey: cmdKey, keyDown: false)
    let keyCDown = CGEvent(keyboardEventSource: source, virtualKey: cKey, keyDown: true)
    let keyCUp = CGEvent(keyboardEventSource: source, virtualKey: cKey, keyDown: false)
    
    let loc = CGEventTapLocation.cghidEventTap
    
    cmdDown?.flags = CGEventFlags.maskCommand
    cmdUp?.flags = CGEventFlags.maskCommand
    keyCDown?.flags = CGEventFlags.maskCommand
    keyCUp?.flags = CGEventFlags.maskCommand
    
    cmdDown?.post(tap: loc)
    keyCDown?.post(tap: loc)
    cmdUp?.post(tap: loc)
    keyCUp?.post(tap: loc)
    
    sleep(1)
    
    print("clipboard:")
    let content = pasteboard.string(forType: .string) ?? "" // Default to empty string
    print(content)

Any ideas or suggestions or ideas?

Best,

floek

floek
  • 31
  • 4
  • Is the keystroke not working or the pasteboard? Does keystroke c without Command work? Does the Finder see the copied text on the pasteboard? Try this order: Command down, c down, c up, Command up. – Willeke Jan 21 '22 at 15:29
  • Thanks for your reply. I have no issues with the pasteboard. If I copy text manually it works. But, the copied text does not show up in the pasteboard. I don't know how to verify if a keystroke has worked. When the text is copied, it is seen as usual in any app (Finder also). A change of the order has no effect. But I do not think, the root cause can be found in the code, because the same code works in a Command Line App.I think I'm missing to set something in the macOS security framework, because I've found the following error in the macOS console, when the virtual keys should be pressed. – floek Jan 21 '22 at 18:20
  • `WindowServer Sender is prohibited from synthesizing events` – floek Jan 21 '22 at 18:21
  • Okay, when I try to send several c keystrokes in an input field, it doesn't work either. So, I assume keystrokes can't be sent in general. – floek Jan 21 '22 at 18:30

1 Answers1

0

I've found the issue: TCC denied the request, because an older version of the app was installed in the systems Application folder and TCC had stored it's "fingerprint" for the given rights under "Accessibility" (somehow). I had to delete the older version and delete the TCC entry. Then, rebuild, restarted the app and allowed "Accessibility" again: --> It worked.

Interesting for the community may be, how I found the issue. I used the following command to get on track by inspecting the relevant logs:

log stream --debug --predicate \
  'subsystem == "com.apple.TCC" AND eventMessage CONTAINS "<my.app.bundle.id>"'
floek
  • 31
  • 4