在“服务”菜单中设置“自定义键等效”

时间:2013-09-13 00:31:02

标签: objective-c macos cocoa

OmniFocus有一个Cocoa服务,允许您根据所选项目创建任务。

它具有允许您设置触发服务的键盘快捷键的首选项。这不仅仅是一个全球热门,它是一个真正的服务,显示在菜单中。

您可以使用键盘快捷键来实现任何组合,包括与⌥和^的组合。此功能未记录 - docs似乎表示KeyEquivalents必须是⌘+[⇧]+someKey

一旦设定,我会发现三件事:

  1. OmniFocus Info.plist文件未包含列出的KeyEquivalent。这并不奇怪,因为该文件是只读的。
  2. pbs -dump_pboard实用程序列出了服务的NSKeyEquivalent = {};
  3. 使用NSDebugServices列出了这个有趣的行,但没有显示大多数调试会话(显然,对于键盘快捷键⌃⌥⌘M):OmniFocus: Send to Inbox (com.omnigroup.OmniFocus) has a custom key equivalent: <NSKeyboardShortcut: 0x7fb18a0d18f0 (⌃⌥⌘M)>.
  4. 所以我的问题是双重的,我怀疑它们是相关的:

    1. 如何动态更改服务的KeyEquivalent?
    2. 如何将KeyEquivalent设置为包含^和⌥
    3. 的组合

      谢谢!

1 个答案:

答案 0 :(得分:2)

想出来。这里描述了基本过程:Register NSService with Command Alt NSKeyEquivalent

代码是这样的:

//Bundle identifier from Info.plist
NSString* bundleIdentifier = @"com.whatever.MyApp";
//Services -> Menu -> Menu item title from Info.plist
NSString* appServiceName = @"Launch My Service";
//Services -> Instance method name from Info.plist
NSString* methodNameForService = @"myServiceMethod";

//The key equivalent
NSString* keyEquivalent = @"@~r";

CFStringRef serviceStatusName = (CFStringRef)[NSString stringWithFormat:@"%@ - %@ - %@", bundleIdentifier, appServiceName, methodNameForService];
CFStringRef serviceStatusRoot =  CFSTR("NSServicesStatus");
CFPropertyListRef pbsAllServices = (CFPropertyListRef) CFMakeCollectable ( CFPreferencesCopyAppValue(serviceStatusRoot, CFSTR("pbs")) );
// the user did not configure any custom services
BOOL otherServicesDefined = pbsAllServices != NULL;
BOOL ourServiceDefined = NO;
if ( otherServicesDefined ) {
    ourServiceDefined = NULL != CFDictionaryGetValue((CFDictionaryRef)pbsAllServices, serviceStatusName);
}

NSUpdateDynamicServices();
NSMutableDictionary *pbsAllServicesNew = nil;
if (otherServicesDefined) {
    pbsAllServicesNew = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)pbsAllServices];
} else {
   pbsAllServicesNew = [NSMutableDictionary dictionaryWithCapacity:1];
}

NSDictionary *serviceStatus = [NSDictionary dictionaryWithObjectsAndKeys:
                               (id)kCFBooleanTrue, @"enabled_context_menu", 
                               (id)kCFBooleanTrue, @"enabled_services_menu", 
                               keyEquivalent, @"key_equivalent", nil];
[pbsAllServicesNew setObject:serviceStatus forKey:(NSString*)serviceStatusName];
CFPreferencesSetAppValue (
                          serviceStatusRoot,
                          (CFPropertyListRef) pbsAllServicesNew,
                          CFSTR("pbs"));
Boolean result = CFPreferencesAppSynchronize(CFSTR("pbs"));
if (result) {
    NSUpdateDynamicServices();
    NSLog(@"successfully installed our alt-command-r service");
} else {
    NSLog(@"couldn't install our alt-command-r service");
}

如果代码成功,您可以在~/Library/Preferences/pbs.plist

中查看

您应该看到类似的内容:

NSServicesStatus = {
    "com.whatever.MyApp - Launch My Service - myServiceMethod" = {
        enabled_context_menu = :true;
        enabled_services_menu = :true;
        key_equivalent = "@~r";
    };