【问题标题】:How do I programmatically get the shortcut keys reserved by Mac OS X如何以编程方式获取 Mac OS X 保留的快捷键
【发布时间】:2010-10-26 08:21:33
【问题描述】:

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

【问题讨论】:

    标签: macos macos-carbon


    【解决方案1】:

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

    【讨论】:

    • 不,硬编码不是一个选项,因为用户可以更改系统偏好设置中的值,然后硬编码值无效。
    • 我在想,但是如果用户自己更改了系统偏好,那么他们可能会意识到他们正在破坏它。我认为,在几乎所有情况下,覆盖他们的系统偏好实际上是他们想要的目标(在新环境下重用偏好的快捷方式)。我仍然接受这不是理想的答案。
    【解决方案2】:

    我认为这是不可能的。

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

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

    我还发现了一个 link 描述修饰键值是什么。

    这是在系统快捷键首选项中禁用已知键的代码:

    #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
    

    【讨论】:

    • 澄清一下:CopySymbolicHotKeys() 是否返回默认热键,而不是实际设置?
    【解决方案3】:

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

    /**
     * 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,
    };
    

    【讨论】:

      猜你喜欢
      • 2011-05-23
      • 1970-01-01
      • 2012-02-28
      • 2014-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-18
      相关资源
      最近更新 更多