Search code examples
swiftmacoscocoa

Is there a way to programmatically change the Emoji Panel on key press in System Settings?


I've been trying to change it trough accessing the plist file but I cant find documentation on how to access it. I'm not sure if it's even possible.

enter image description here


Solution

  • I used fswatch to detect which files changed inside my ~/Library/Preferences folder, while I changed the setting back and forth. Sure enough, ~/Library/Preferences/com.apple.HIToolbox.plist ("Human Interface toolbox") came up as the result.

    Next, I looked at its structured and saw the AppleFnUsageType key, which seemed pretty promising. I changed the setting back and forth in System Preferences again, while monitoring for specific changes to that key with:

    watch -n 1 -d defaults read com.apple.HIToolbox AppleFnUsageType
    

    And I saw the following results:

    • 0 maps to "Do Nothing"
    • 1 maps to "Change Input Source"
    • 2 maps to "Show Emoji & Symbols"
    • 3 maps to "Start Dictation (Press 🌐︎ Twice)"

    So you can set this setting via the terminal with:

    defaults write com.apple.HIToolbox AppleFnUsageType -int 0
    

    You can spawn a process to run defaults from your Swift program, but that's clunky and requires turning the App sandbox off. Ideally we'd just call the UserDefaults APIs, but that won't let us change values in the com.apple.HIToolbox domain (it only lets you change values for your own app's domain, or the global domain).

    We can drop to a lower level and use CFPreferencesSetValue from CoreFoundation, which has lets you do that. It's still fairly straight forward:

    import Foundation
    
    enum FnKeyUsageType: Int {
        case doNothing = 0
        case changeInputSource = 1
        case showEmojiAndSymbols = 2
        case startDictation = 3
    }
    
    CFPreferencesSetValue(
        "AppleFnUsageType" as CFString,
        FnKeyUsageType.doNothing.rawValue as CFNumber,
        "com.apple.HIToolbox" as CFString,
        kCFPreferencesCurrentUser,
        kCFPreferencesAnyHost
    )