如何以编程方式获取 Mac OS X 保留的快捷键
-
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
文件以 Lyndsey Ferguson 所代表的方式使用 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 更新中重复该过程。