Mac开发– 全局快捷键: GuoJing's Blog | 用心对待每一行代码

在应用程序开发的时候有很多这样的情况,就是我想在全局使用一个快捷键然后我可以随时调用它。例如Things这个应用,你可以在窗体写自己的一些内容,如下图所示。但是更有意思的是,如果我能在全局去使用就好了,因为我们在大多数的时候,都要跳转到这个程序中,然后在程序中查询,如Things,我必须打开Things,然后添加我的内容,或者减少一个内容,如下图。

如果我能在邮件中,或者浏览器中,忽然发现这是我想看的东西,然后添加到Things中,这样多好,于是Things就出了下面这个功能。

也就是说,我可以不在应用程序窗体上进行应用程序操作。

听起来好像有点复杂,因为在操作系统中,任何程序的xx状态都是单一的,比如你不能一边魔兽一边写程序,你必须要“专注”某个应用程序来使用,比如我想发Twitter,而我又在写代码,我必须切换到Twitter客户端去写东西,而无法在当前“xx”程序的程序中去执行,非要将Twitter客户端xx,然后才能执行。

我最近写了一个Password Saver,专门用于保存非常复杂的密码,当我需要密码的时候,我也希望能够马上查询然后关闭,而不需要“xx”程序来使用,查了一些资料,下面来说说如何创建全局快捷键。

首先,这里我假设的是,你有了UI,有了Controller,一切都就绪了。应用程序会有一个主要的Controller,这里我们就叫MainController吧。我们首先需要添加一个库,以便可以注册我们的全局快捷键,我们在左侧中如下操作,Frameworks->Add->Exiting Frameworks->Carbon.framework,添加Carbon框架。添加之后,我们就有了基础设施。

然后我们需要在MainController中写如下代码。

//重写这个方法,这个方法默认定义的
//当这个controller绑定到view的时候,会自动调用这个方法
-(void)awakeFromNib{
    
//注册事件
    EventHotKeyRef myHotKeyRef;
    EventHotKeyID myHotKeyID;
    EventTypeSpec eventType;
    
    
//注册对应的事件,如键盘按钮
    eventType.eventClass=kEventClassKeyboard;
    eventType.eventKind
=kEventHotKeyPressed;
    
//注册快捷键事件
    InstallApplicationEventHandler(&myHotKeyHandler,1,&eventType,self,NULL);
    myHotKeyID.signature
=mhk1;
    myHotKeyID.id
=1;
    
//注册EventHandler
    RegisterEventHotKey(49, cmdKey+optionKey, myHotKeyID, GetApplicationEventTarget(), 0, &myHotKeyRef);
    NSLog(
@"awake");
}

上面的代码就是实现awakeFromNib方法,当窗体载入的时候(前提是绑定了相应窗体),会自动调用这个方法,调用的时候,我们注册了相应的事件。注意这里的RegisterEventHotKey方法,RegisterEventHotKey方法为注册快捷键的键值的方法,其中最主要的参数为(参数1)初始键,(参数2)附加键,初始键这里为空格(49),后面是command key和option key。

注册之后,我们需要写相应事件。

首先我们将如下代码添加到@implementation之前。

添加之后,我们在该类中实现上面的方法,代码如下。

OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void  *userData){
    NSLog(
@"call hot key %@", userData);
    
//你想做什么事情都可以在这里做
    return noErr;
}

上面的代码都是写在MainController里的,使用上面的代码就定义了全局快捷键。

但是在全局快捷键中,我们如何拿到自己的对象呢,因为这个Carbon方法是一个C方法,是无法使用self对象的,这里我们可以使用userData来得到返回的数据。可以使用MainController *controller = (MainController *)userData;来获得调用的窗体(也可以说是钩子)。

上面的获得窗体的方法,是获得本身发送窗体的对象,如果你理解了之后,或者使用了之后就会发现,就算全局快捷键使用成功,也无法xx相应的功能,这是为什么呢。首先,这个窗体是一个Window,Window是不能被后台xx的,Window只能在前台xx,也就是说你必须使用该应用程序。

在Cocoa中,我们可以使用HUD Window作为后台xx程序的入口,如下图。该类型的窗口可以独立应用程序,屏蔽其他应用程序窗口而存在在前端显示器的窗口。

我们可以创建一个新的xib文件(可以取名叫QuickWindow),并在新的xib文件中删除默认的窗口,然后拖动一个HUD窗口,然后链接。同时,我们还需要为这个窗体写一个Controller。也就是说,基本上一个窗体的view就应该对应一个Controller。

ok之后,我们可以更改一下响应的方法来调用这个窗体,代码如下(注意,这代码还是在MainController中)。

OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void  *userData){
    NSLog(
@"call hot key %@", userData);
    
//打开QuickWindow
    NSWindowController *add_window = [[NSWindowController alloc] initWithWindowNibName:@"QuickWindow"];
    [add_window loadWindow];
    
//打开窗体
    [add_window showWindow:[add_window window]];
    [[add_window window] makeMainWindow];
    
return noErr;
}

上面的代码就是打开窗体的代码,另一个问题就来了。窗体打开之后,该窗体是默认不会被xx和选中的,我们需要在对应的窗体的Controller中用代码设置默认焦点。如下。

-(void)awakeFromNib{
    
//这里的self_panel就是窗体panel
    
//定义变量的原因是通过在IB链接窗体,然后调用改变量就能够使用窗体
    [[self self_panel] makeKeyAndOrderFront:self_panel];
}

在新的窗体中,还需要设置Panel的属性为Non Activating为True才行,当然,记得也要设置一下firstResponer(事件中拖动即可),如下。

1.首先添加Framework。
2.然后定义全局快捷键。
3.其次创建新窗口xib和controller。
4.然后修改快捷键响应方法,打开新窗口。
5.给新窗口设置默认焦点。

:) 8) :evil: :lol: :-| :oops: :wink: :-D :cry: :idea: 8-O :-? :twisted:

郑重声明:资讯 【Mac开发– 全局快捷键: GuoJing's Blog | 用心对待每一行代码】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——