5

我正在使用一个允许客户自定义分配的快捷键的应用程序。我想做的一件事是警告是否选择了 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);
4

3 回答 3

4

我想添加有助于以~/Library/Preferences/com.apple.symbolichotkeys.plistLyndsey Ferguson 所代表的方式读取/写入文件的代码,CFPreferencesCopyAppValue()而不是CFDictionaryGetValueIfPresent()from CFPropertyListRef。关键是要知道哪个符号热键标识符与键盘快捷键首选项窗格中的哪个热键相关。这是带有描述性常量的代码,可以帮助您解决这个问题:

/**
 * Apple Symbolic HotKeys Ids
 * To find this symbolic hot keys indices do:
 * 1. open Terminal
 * 2. restore defaults in System Preferences > Keyboard > Shortcuts
 * 3. defaults read com.apple.symbolichotkeys > current.txt
 * 4. enable/disable given symbolic hot key in System Preferences > Keyboard > Shortcuts
 * 5. defaults read com.apple.symbolichotkeys | diff -C 5 current.txt -
 * 6. restore defaults in System Preferences > Keyboard > Shortcuts
 */
enum {
    kSHKMoveFocusToTheMenuBar                   = 7,    // Ctrl, F2
    kSHKMoveFocusToTheDock                      = 8,    // Ctrl, F3
    kSHKMoveFocusToActiveOrNextWindow           = 9,    // Ctrl, F4
    kSHKMoveFocusToTheWindowToolbar             = 10,   // Ctrl, F5
    kSHKMoveFocusToTheFloatingWindow            = 11,   // Ctrl, F6
    kSHKTurnKeyboardAccessOnOrOff               = 12,   // Ctrl, F1
    kSHKChangeTheWayTabMovesFocus               = 13,   // Ctrl, F7
    kSHKTurnZoomOnOrOff                         = 15,   // Opt, Cmd, 8
    kSHKZoomIn                                  = 17,   // Opt, Cmd, =
    kSHKZoomOut                                 = 19,   // Opt, Cmd, -
    kSHKInvertColors                            = 21,   // Ctrl, Opt, Cmd, 8
    kSHKTurnImageSmoothingOnOrOff               = 23,   // Opt, Cmd, Backslash "\"
    kSHKIncreaseContrast                        = 25,   // Ctrl, Opt, Cmd, .
    kSHKDecreaseContrast                        = 26,   // Ctrl, Opt, Cmd, ,
    kSHKMoveFocusToNextWindow                   = 27,   // Cmd, `
    kSHKSavePictureOfScreenAsAFile              = 28,   // Shift, Cmd, 3
    kSHKCopyPictureOfScreenToTheClipboard       = 29,   // Ctrl, Shift, Cmd, 3
    kSHKSavePictureOfSelectedAreaAsAFile        = 30,   // Shift, Cmd, 4
    kSHKCopyPictureOfSelectedAreaToTheClipboard = 31,   // Ctrl, Shift, Cmd, 4
    kSHKMissionControl                          = 32,   // Ctrl, Arrow Up
    kSHKApplicationWindows                      = 33,   // Ctrl, Arrow Down
    kSHKShowDesktop                             = 36,   // F11
    kSHKMoveFocusToTheWindowDrawer              = 51,   // Opt, Cmd, `
    kSHKTurnDockHidingOnOrOff                   = 52,   // Opt, Cmd, D
    kSHKMoveFocusToStatusMenus                  = 57,   // Ctrl, F8
    kSHKTurnVoiceOverOnOrOff                    = 59,   // Cmd, F5
    kSHKSelectThePreviousInputSource            = 60,   // Ctrl, Space bar
    kSHKSelectNextSourceInInputMenu             = 61,   // Ctrl, Opt, Space bar
    kSHKShowDashboard                           = 62,   // F12
    kSHKShowSpotlightSearch                     = 64,   // Cmd, Space bar
    kSHKShowFinderSearchWindow                  = 65,   // Opt, Cmd, Space bar
    kSHKLookUpInDictionary                      = 70,   // Shift, Cmd, E
    kSHKHideAndShowFrontRow                     = 73,   // Cmd, Esc
    kSHKActivateSpaces                          = 75,   // F8
    kSHKMoveLeftASpace                          = 79,   // Ctrl, Arrow Left
    kSHKMoveRightASpace                         = 81,   // Ctrl, Arrow Right
    kSHKShowHelpMenu                            = 98,   // Shift, Cmd, /
    kSHKSwitchToDesktop1                        = 118,  // Ctrl, 1
    kSHKSwitchToDesktop2                        = 119,  // Ctrl, 2
    kSHKSwitchToDesktop3                        = 120,  // Ctrl, 3
    kSHKSwitchToDesktop4                        = 121,  // Ctrl, 4
    kSHKShowLaunchpad                           = 160,  //
    kSHKShowAccessibilityControls               = 162,  // Opt, Cmd, F5
    kSHKShowNotificationCenter                  = 163,  //
    kSHKTurnDoNotDisturbOnOrOff                 = 175,  //
    kSHKTurnFocusFollowingOnOrOff               = 179,  //
};


struct symbolic_hot_keys {
    int shk_id;                 // symbolic hot keys identifier
    int enabled;
    char *type;                 // usually "standard"
    int64_t ASCII_code;             // ASCII code of the character or 65535 (0xFFFF) for non-ASCII characters
    int64_t virtual_key_code;       // virtual key code for the character
    int64_t modifier_keys_flags;    // the sum of modifier key flags: Shift 17 bit, Ctrl 18 bit, Opt 19 bit, Cmd 20 bit
};
typedef struct symbolic_hot_keys symbolic_hot_keys_t;

// simple mapping of modifier flags
enum {
    kMFShift    = kCGEventFlagMaskShift,
    kMFControl  = kCGEventFlagMaskControl,
    kMFOption   = kCGEventFlagMaskAlternate,
    kMFCommand  = kCGEventFlagMaskCommand,
};
于 2016-09-05T17:05:49.383 回答
1

我不认为这是可能的。

链接也讨论了使用 CopySymbolicHotKeys。但是,该函数会列出键盘快捷键的系统偏好设置中未列出的键盘快捷键。如果有办法区分实际保留的密钥和标准密钥,那将是理想的。

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

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

这是为禁用系统快捷键首选项中的已知键而发布的代码:

#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
于 2009-05-18T19:46:23.173 回答
0

我不知道如何以编程方式执行此操作,但如果可以选择硬编码,您将在此处找到 MacOSX 快捷方式列表:http: //support.apple.com/kb/HT1343。我会使用正则表达式来吸出组合键,然后以编程方式转换为键符/键码。该页面似乎由 Apple 针对每个 OSX 版本进行更新,因此您应该能够轻松地在每次 OSX 更新时重复该过程。

于 2009-05-18T13:21:26.807 回答