5

I am new to working in Swift, and am currently working on a small messaging application for macOS. The basic application is complete, but I'm trying to add an emoji picker.

I want to add a button that brings up the "Emoji & Symbols" window. This is automatically added to the "Edit" Menu upon starting the application, but I was hoping to have it pop-up via an NSButton press (like in the native Mac Messages app).

Is there a way to call a system function to show the emoji picker, or perhaps a way to simulate the keyboard shortcut(ctrl+cmd+space)? And if so, what steps would I need to take to implement it?

  • While I haven't found a way to trigger the Emoji and Symbols way, take a look at this: http://stackoverflow.com/questions/36375080/cocoa-simulating-commandtab-in-cgevent – Ezekiel Jul 27 '16 at 11:59
  • Definitely put me on the right track. Thanks for you help! –  Jul 28 '16 at 03:35

3 Answers3

5

sussed it out thanks to the suggestion to use keyboard shortcuts.

Included below is the code I used. I had trouble simulating two modifier keys being pressed, so the solution was to create a custom CGEventFlags item.

// Setup a custom CGEventFlags Item with value of .MaskControl and .MaskCommand
    let commandControlMask = (CGEventFlags.MaskCommand.rawValue | CGEventFlags.MaskControl.rawValue)
    let commandControlMaskFlags = CGEventFlags(rawValue: commandControlMask)!

    // Press Space key once
    let space = CGEventSourceCreate(.HIDSystemState)
    let keyDown = CGEventCreateKeyboardEvent(space, 49 as CGKeyCode, true)
    CGEventSetFlags(keyDown, commandControlMaskFlags)
    CGEventPost(.CGHIDEventTap, keyDown)
    let keyUp = CGEventCreateKeyboardEvent(space, 49 as CGKeyCode, false)
    CGEventSetFlags(keyUp, commandControlMaskFlags)
    CGEventPost(.CGHIDEventTap, keyUp)
  • Note that posting these events won't work when the app is running in a sandbox. I'm not aware of any other API that can accomplish the task within the confines of the app sandbox. – chockenberry May 02 '17 at 22:40
  • 11
    Turns out you can use [NSApp orderFrontCharacterPalette:nil] to accomplish this: http://twitter.com/lapcatsoftware/status/859539614373117952 – chockenberry May 02 '17 at 22:55
  • @chockenberry How did you return a character from the character palette back to your application? – Clifton Labrum Jan 10 '19 at 23:22
  • ...and how do you force the popup to appear as a popover on a specific `NSTextField`? I've made it the first responder, but the character palette still shows up as a floating window. – Clifton Labrum Jan 11 '19 at 04:03
  • 1
    @CliftonLabrum returning the character is all automatic. Just pass your textView as the sender. so [NSApp orderFontCharacterPalette:textView], just make sure you call becomeFirstResponder on the textView before. –  Amerino Jun 13 '20 at 00:12
2

Simple example using IBOutlets

class ViewController: NSViewController {

    @IBOutlet weak var textView: NSTextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    @IBAction func buttonTapped(_ sender: Any) {
        textView.becomeFirstResponder()
        NSApp.orderFrontCharacterPalette(textView)
    }
}
Amerino
  • 389
  • 1
  • 5
  • You can also just pass nil - NSApp.orderFrontCharacterPalette(nil) Just make sure your textView is first responder. You can easily bridge orderFrontCharacterPalette for use in catalyst apps. –  Amerino Jun 15 '20 at 21:27
0
let commandControlMask = (CGEventFlags.maskCommand.rawValue | CGEventFlags.maskControl.rawValue)
let commandControlMaskFlags = CGEventFlags(rawValue: commandControlMask)

 // Press Space key once
let space = CGEventSource(stateID: .hidSystemState)
let keyDown = CGEvent(keyboardEventSource: space, virtualKey: 49 as CGKeyCode, keyDown: true)
keyDown?.flags = commandControlMaskFlags
keyDown!.post(tap: .cghidEventTap)
let keyUp = CGEvent(keyboardEventSource: space, virtualKey: 49 as CGKeyCode, keyDown: false)
keyUp?.flags = commandControlMaskFlags
keyUp?.post(tap: .cghidEventTap)

Updated for Swift 5.1. Requires user to give accessibility rights though.

cvb
  • 1,715
  • 18
  • 22