如何以编程方式获取 Mac OS X 保留的快捷键

Lyn*_*son 5 macos macos-carbon

我正在使用一个应用程序,该应用程序允许客户自定义分配的快捷键。我想做的一件事是警告是否选择了 Mac OS X 已在使用的快捷键。

我正在尝试使用 CopySymbolicHotKeys,但我不确定我是否正确使用它,因为它列出了被保留的命令,即使我没有看到它列在“键盘快捷键”选项卡窗格中& 鼠标”系统偏好设置。我希望能够获得那些“保留”供系统使用的快捷方式,这是要使用的 API 吗?

我在下面包含了我的代码示例,请查看它并提供您可能想到的任何建议。

CFArrayRef hotkeyArray = NULL;
OSStatus status = CopySymbolicHotKeys(&hotkeyArray);

if (noErr == status && NULL != hotkeyArray) {

    CFIndex hotKeyCount = CFArrayGetCount(hotkeyArray);

    for (CFIndex i = 0; i < hotKeyCount; i++) {
        CFDictionaryRef hotKeyDict = (CFDictionaryRef) CFArrayGetValueAtIndex(hotkeyArray, i);
        if (hotKeyDict && CFGetTypeID(hotKeyDict) == CFDictionaryGetTypeID()) {
            if (kCFBooleanTrue == (CFBooleanRef) CFDictionaryGetValue(hotKeyDict, kHISymbolicHotKeyEnabled)) {

                SInt32 keyModifiers = 0;

                CFNumberRef cfkeyModifers = (CFNumberRef) CFDictionaryGetValue(hotKeyDict, kHISymbolicHotKeyModifiers);
                CFNumberGetValue(cfkeyModifers, kCFNumberSInt32Type, &keyModifiers);

                bool keyIsCommandOnly = (keyModifiers == (keyModifiers & cmdKey));
                bool keyIsCommandAndOption = (keyModifiers == (keyModifiers & (cmdKey | optionKey)));

                CFNumberRef cfKeyCode = (CFNumberRef) CFDictionaryGetValue(hotKeyDict, kHISymbolicHotKeyCode);

                short keyCode = 0;
                CFNumberGetValue(cfKeyCode, kCFNumberShortType, &keyCode);

                CFStringRef keyString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%C"), keyCode);

                const char* commandOnlyStr = "Command";
                const char* commandAndOptionStr = "Command-Option";
                const char* otherStr = "Other Modifier Key";

                char* modifierStr = otherStr;

                if (keyIsCommandOnly) {
                    modifierStr = commandOnlyStr;
                }
                else if (keyIsCommandAndOption) {
                    modifierStr = commandAndOptionStr;
                }

                CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Mac OS X Reserved Key: %s %@"), modifierStr, keyString);
                CFShow(debugString); // Command-O, Command-W and other apparently non-reserved keys are output
                CFRelease(debugString);
                CFRelease(keyString);
            }
        }
    }
}
CFRelease(hotkeyArray);
Run Code Online (Sandbox Code Playgroud)

Lyn*_*son 1

我认为这是不可能的。

链接还讨论了 CopySymbolicHotKeys 的使用。但是,该功能列出了键盘快捷键系统偏好设置中未列出的键盘快捷键。如果有某种方法可以区分实际保留的键和标准键,那将是理想的。

最好的答案似乎是解析实际的 plist 文件“com.apple.symbolichotkeys.plist”,我在 Apple 的 Carbon 电子邮件讨论列表中找到了该文件。但是,这个答案假设您知道每个键是什么(我不知道)。

我还找到了一个描述修饰键值的链接。

以下是发布的用于禁用系统快捷键首选项中的已知键的代码:

#include <CoreServices/CoreServices.h>

static CFStringRef gApplicationID = CFSTR("com.apple.symbolichotkeys");

static CFStringRef gKeyASHK =       CFSTR("AppleSymbolicHotKeys");
static CFStringRef gKey73 =         CFSTR("73");
static CFStringRef gKeyEnabled =    CFSTR("enabled");

int main(int argc, const char *argv[]) {
    #pragma unused (argc, argv)

    CFPropertyListRef hotkeysCFPropertyListRef = CFPreferencesCopyAppValue(gKeyASHK, gApplicationID);
    if ( !hotkeysCFPropertyListRef ) {
        fprintf(stderr,
                "%s, CFPreferencesCopyAppValue(\"AppleSymbolicHotKeys\", \"com.apple.symbolichotkeys.plist\" returned NULL.\n",
                __PRETTY_FUNCTION__);
        return (-1);
    }
    // make sure it's a dictionary
    if ( CFGetTypeID(hotkeysCFPropertyListRef) != CFDictionaryGetTypeID() ) {
        fprintf(stderr, "%s, CFGetTypeID(hotkeysCFPropertyListRef) != CFDictionaryGetTypeID().\n", __PRETTY_FUNCTION__);
        return (-1);
    }

    // get the "73" value from that dictionary
    CFPropertyListRef hotkey73CFPropertyListRef = NULL;
    if ( !CFDictionaryGetValueIfPresent(hotkeysCFPropertyListRef, gKey73, &hotkey73CFPropertyListRef) ) {
        fprintf(stderr, "%s, CFDictionaryGetValueIfPresent(...,\"73\",...) returned FALSE.\n", __PRETTY_FUNCTION__);
        return (-1);
    }
    //CFShow(hotkey73CFPropertyListRef);
    // make sure it's a dictionary
    if ( CFGetTypeID(hotkey73CFPropertyListRef) != CFDictionaryGetTypeID() ) {
        fprintf(stderr, "%s, CFGetTypeID(hotkey73CFPropertyListRef) != CFDictionaryGetTypeID().\n", __PRETTY_FUNCTION__);
        return (-1);
    }

    // get the "73" value from that dictionary
    CFPropertyListRef hotkey73EnabledCFPropertyListRef = NULL;
    if ( !CFDictionaryGetValueIfPresent(hotkey73CFPropertyListRef, gKeyEnabled, &hotkey73EnabledCFPropertyListRef) ) {
        fprintf(stderr, "%s, CFDictionaryGetValueIfPresent(...,\"enabled\",...) returned FALSE.\n", __PRETTY_FUNCTION__);
        return (-1);
    }
    //CFShow(hotkey73EnabledCFPropertyListRef);
    // make sure it's a boolean
    if ( CFGetTypeID(hotkey73EnabledCFPropertyListRef) != CFBooleanGetTypeID() ) {
        fprintf(stderr, "%s, CFGetTypeID(hotkey73EnabledCFPropertyListRef) != CFBooleanGetTypeID().\n", __PRETTY_FUNCTION__);
        return (-1);
    }

    // get its value
    Boolean value = CFBooleanGetValue(hotkey73EnabledCFPropertyListRef);

    CFBooleanRef hotkey73EnabledCFBooleanRef = value ? kCFBooleanFalse : kCFBooleanTrue;    // note: toggle value

    // create a mutable copy of the hot key 73 dictionary
    CFMutableDictionaryRef newHotkey73CFCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0,  hotkey73CFPropertyListRef);
    if ( !newHotkey73CFCFMutableDictionaryRef ) {
        fprintf(stderr, "%s, CFDictionaryCreateMutableCopy(..., hotkey73CFPropertyListRef) returned NULL.\n", __PRETTY_FUNCTION__);
        return (-1);
    }

    // set the new value for the "enabled" item
    CFDictionarySetValue(newHotkey73CFCFMutableDictionaryRef, gKeyEnabled, hotkey73EnabledCFBooleanRef);
    //CFShow(newHotkey73CFCFMutableDictionaryRef);

    // create a mutable copy of the hot key dictionary
    CFMutableDictionaryRef newHotkeysCFPropertyListRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, hotkeysCFPropertyListRef);
    if ( !newHotkeysCFPropertyListRef ) {
        fprintf(stderr, "%s, CFDictionaryCreateMutableCopy(...,hotkeysCFPropertyListRef) returned NULL.\n", __PRETTY_FUNCTION__);
        return (-1);
    }

    // set the new value for the "73" item
    CFDictionarySetValue(newHotkeysCFPropertyListRef, gKey73, newHotkey73CFCFMutableDictionaryRef);
    CFRelease(newHotkey73CFCFMutableDictionaryRef);
    //CFShow(newHotkeysCFPropertyListRef);

    CFPreferencesSetAppValue(gKeyASHK, newHotkeysCFPropertyListRef, gApplicationID);
    if ( !CFPreferencesAppSynchronize(gApplicationID) ) {
        fprintf(stderr, "%s, CFPreferencesAppSynchronize returned false.\n", __PRETTY_FUNCTION__);
        return (-1);
    }

    // note: value is opposite of what we just set (so invert logic)
    printf("%s, /AppleSymbolicHotKeys/73/enabled set to %s.\n", __PRETTY_FUNCTION__, value ? "FALSE" : "TRUE");

    return (0);
} // main
Run Code Online (Sandbox Code Playgroud)