Как программно получить сочетания клавиш, зарезервированные Mac OS X

StackOverflow https://stackoverflow.com/questions/866056

  •  21-08-2019
  •  | 
  •  

Вопрос

Я работаю над приложением, которое позволяет клиенту настраивать назначение сочетаний клавиш.Я хочу предупредить, если выбрана комбинация клавиш, которая уже используется 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);
Это было полезно?

Решение

Я не думаю, что это возможно.

Этот связь также обсуждается использование 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

Другие советы

Я хотел бы добавить код, который помогает читать/записывать ~/Library/Preferences/com.apple.symbolichotkeys.plist файл способом, представленным Линдси Фергюсон, используя CFPreferencesCopyAppValue() и тогда CFDictionaryGetValueIfPresent() от 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,
};

Я не знаю, как это сделать программно, но если есть возможность жесткого кодирования, вы найдете здесь список ярлыков MacOSX: http://support.apple.com/kb/HT1343 .Я бы использовал регулярное выражение для извлечения комбинаций клавиш, а затем программно конвертировал их в символы клавиш/коды клавиш.Похоже, что страница обновляется Apple для каждого выпуска OSX, поэтому вы сможете легко повторить этот процесс с каждым обновлением OSX.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top