ホットキーをシステムへ登録するクラスの実装に入る。
ヘッダはこんな感じ。
HotkeyRegister.h
@class Hotkey;
@interface HotkeyRegister : NSObject {
NSMutableSet* _hotkey_set;
}
@property (retain) NSMutableSet* hotkey_set;
+ (HotkeyRegister*)sharedRegister;
- (void)unregistAll;
- (BOOL)registHotkey:(Hotkey*)hotkey;
- (BOOL)unregistHotkey:(Hotkey*)hotkey;
@end
NSMutableSet の _hotkey_set に Hotkeyのインスタンスを追加して管理する。ここで - [Hotkey isEqual:] が生きてくる(今回は keycodeと modifier両方で同値性をチェックしている)。
またインスタンスは1つあれば十分なので、Singletonパターンを使い、インスタンスは sharedRegister で取得させる。
次に実装。
ホットキー登録部分は以前紹介したように Carbon APIを使う。
Cocoaの日々 - ホットキー (2008/04)
こんな感じ。
HotkeyRegister.m
#define SC_HOTKEY_SIGNATURE 'schk'
OSStatus hotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData);
static HotkeyRegister* _hotkey_register = nil;
static UInt32 _hotkey_id = 0;
@implementation HotkeyRegister
@synthesize hotkey_set = _hotkey_set;
- (void)unregistAll
{
for (Hotkey* hotkey in _hotkey_set) {
[self unregistHotkey:hotkey];
}
[_hotkey_set release];
NSLog(@"finished");
}
+ (HotkeyRegister*)sharedRegister
{
if (!_hotkey_register) {
_hotkey_register = [[HotkeyRegister alloc] init];
_hotkey_register.hotkey_set = [[NSMutableSet alloc] init];
EventTypeSpec eventTypeSpecList[] ={
{ kEventClassKeyboard, kEventHotKeyPressed }
};
InstallApplicationEventHandler(
&hotKeyHandler, GetEventTypeCount(eventTypeSpecList),
eventTypeSpecList, self, NULL);
}
return _hotkey_register;
}
// Hot key handler
OSStatus hotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData)
{
EventHotKeyID hotKeyID;
GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL,
sizeof(hotKeyID), NULL, &hotKeyID);
if (hotKeyID.signature == SC_HOTKEY_SIGNATURE) {
for (Hotkey* hotkey in _hotkey_register.hotkey_set) {
if (hotKeyID.id == hotkey.keyid) {
[hotkey.target performSelector:hotkey.action withObject:hotkey];
}
}
}
return noErr;
}
- (BOOL)unregistHotkey:(Hotkey*)hotkey
{
OSStatus status = UnregisterEventHotKey(hotkey.ref);
if (status != noErr) {
NSLog(@"UnregisterEventHotKey() was failed : %d", status);
return NO;
}
NSLog(@"unregistHotkey: %@", hotkey);
return YES;
}
- (BOOL)registHotkey:(Hotkey*)hotkey
{
// replace or overwrite ??
if ([_hotkey_set containsObject:hotkey]) {
// same hotkey exists, then replace it
if (![self unregistHotkey:hotkey]) {
// error
return NO;
}
}
EventHotKeyID hotKeyID;
hotKeyID.id = _hotkey_id++;
hotKeyID.signature = SC_HOTKEY_SIGNATURE;
OSStatus status;
EventHotKeyRef hotkeyRef;
status = RegisterEventHotKey(hotkey.code, hotkey.modifier, hotKeyID,
GetApplicationEventTarget(), 0, &hotkeyRef);
hotkey.ref = hotkeyRef;
hotkey.keyid = hotKeyID.id;
if (status != noErr) {
NSLog(@"RegsiterEventHotKey() was failed : %d", status);
return NO;
}
[_hotkey_set addObject:hotkey];
NSLog(@"registHotkey: %@", [hotkey dump]);
NSLog(@"%@", _hotkey_set);
return YES;
}
@end
ホットキー毎にとっておく必要のある情報(idやEventHotKeyRef)は、あらかじめ用意しておいた Hotkeyのプロパティへ保存しておく。id は登録毎に新規に発番するようにしている。
登録後、システムからのコールバックを受けて hotKeyHandler( ) が呼び出される。この処理で _hotkey_set の中に登録されている Hotkey 情報を調べ、id が一致するものがあれば、Hotkey.target へ Hotkey.action のメッセージを投げる( - [NSObject performSelector:withObject: ] を使う)。
その他、後始末用の unregistAll などを用意しておく。
- - - -
ここまで作ったクラスの動作確認を行うため
次回は一度サンプルアプリに組み込んで動作させてみる。