Geometry 関数
NSBundle
NSDictionary
NSFileManager
NSMutableAttributedString
NSNumber
NSScanner
NSString
NSTimer
Graphic 関数
NSApplication
NSBezierPath
NSCell
NSColor
NSCursor
NSCustomImageRep
NSDocument
NSDocumentController
NSDragging
NSEvent
NSFontManager
NSGraphicsContext
NSImage
NSMenu
NSOutlineView
NSPanel
NSPopUpButton
NSResponder
NSScrollView
NSString 追加
NSTableColumn
NSTableView
NSTextStorage
NSTextView
NSToolbar
NSView
NSWindow
NSWorkspace
その他
.nib ウィンドウ
Views パレット
クラス
インスタンス変数
メソッド
CFXML
Carbon Event
-ホットキーを登録する
Carbon Graphics
Cocoa で日本語
メソッド
その他

- With Carbon-
Carbon Event

With Carbon - Carbon Event
ホットキーを登録する
Keywords: RegisterEventHotKey(), UnregisterEventHotKey()

Carbon Event を使えば、ホットキーを登録できるぜ。ホットキーとは、自分のアプリケーションが前面に出ていなくても、受け取れるキーイベント。これを使えば、どこからでもショートカットキーでアプリケーションを呼び出せる。(この記事は、いいむらさんのホットキーに反応するを参考にさせてもらいました。)

ホットキーの登録、削除には、RegisterEventHotKey()UnregisterEventHotKey() を使う。

HIToolbox/CarbonEvents.h
extern OSStatus 
RegisterEventHotKey(
  UInt32            inHotKeyCode,
  UInt32            inHotKeyModifiers,
  EventHotKeyID     inHotKeyID,
  EventTargetRef    inTarget,
  OptionBits        inOptions,
  EventHotKeyRef *  outRef)
AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;

extern OSStatus 
UnregisterEventHotKey(EventHotKeyRef inHotKey)
AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;

RegisterEventHotKey() では、ホットキーの virtual key code、修飾用のキー(Shift とか Command とか)を登録する。EventHotKeyID は、ホットキーごとにユニークな値を設定するようにするんだ。登録に成功すると EventHotKeyRef が返ってくるので、これは保持しておこう。UnregisterEventHotKey() は、その EventHotKeyRef とともに呼び出すんだ。

これで登録はできるけど、どうやって呼び出されるんだ?Carbon では InstallApplicationEventHandler() を使ったりするんだが、ここは Cocoa らしくいこう。NSApplication の sendEvent: メソッドの中で捕まえることができる。このメソッドには NSEvent が渡されてくるんだけど、その subtypekEventHotKeyPressedSubtype だったら、ホットキーイベントだ。この記事は、Doing Carbon things in Cocoa を参考にしました。)

HotKeyApplication.m (sample)
// Undocumented event subtype
enum {
    kEventHotKeyPressedSubtype = 6, 
    kEventHotKeyReleasedSubtype = 9, 
};

- (void)sendEvent:(NSEvent*)event
{
    // For hot key event
    if ([event type] == NSSystemDefined && 
        [event subtype] == kEventHotKeyPressedSubtype)
    {
        // Hot key is pressed!

これで、ホットキーを登録するのに必要な情報は全部そろった。では、サンプル。

NSApplication のサブクラス、HotKeyApplication を作ってみた。こいつが、ホットキーを登録するためのメソッドを提供する。まず登録用のメソッドは、registerHotKeyCode:withModifier:target:selector:

HotKeyApplication.h (sample)
- (void*)registerHotKeyCode:(unsigned int)keyCode 
        withModifier:(unsigned int)keyModifier 
        target:(id)object 
        selector:(SEL)selector;

このメソッドの仕様は、まず keyCode は virtual key code を指定する。keyModifier は、修飾用のキー。NSShiftMaskNSControlKeyMaskNSCommandKeyMaskNSAlternateKeyMask の OR を指定してやる。objectselector は、ホットキーが押されたときに呼ばれるメソッドだ。登録が成功したら、EventHotKeyRef を返す。

続いて、削除するためのメソッド unregisterHotKey:

HotKeyApplication.h (sample)
- (void)unregisterHotKey:(void*)hotKeyRef;

つくるときに得られた EventHotKeyRef を渡してやる。これで削除しよう。

という感じの仕様で実装する。そうすると、ソースコードはざっとこんな感じに。

HotKeyApplication.h (sample)
- (void*)registerHotKeyCode:(unsigned int)keyCode 
        withModifier:(unsigned int)keyModifier 
        target:(id)object 
        selector:(SEL)selector
{
    static UInt32	_id = 0;
    
    OSStatus		status;
    UInt32			modifier;
    EventHotKeyID	keyId;
    EventHotKeyRef	hotKeyRef;
    int				buf[2];
    
    // Make key modifier
    modifier = 0;
    if (keyModifier & NSShiftKeyMask) { modifier |= shiftKey; }
    if (keyModifier & NSControlKeyMask) { modifier |= controlKey; }
    if (keyModifier & NSCommandKeyMask) { modifier |= cmdKey; }
    if (keyModifier & NSAlternateKeyMask) { modifier |= optionKey; }
    
    // Make hot key ID
    keyId.signature = 'HtKe';
    keyId.id = _id++;
    
    // Register hot key
    status = RegisterEventHotKey(
                    keyCode, 
                    modifier, 
                    keyId, 
                    GetApplicationEventTarget(), 
                    0, 
                    &hotKeyRef);
    if (status != noErr) {
        return NULL;
    }
    
    // Set hot key reference into dictionary
    buf[0] = (int)object;
    buf[1] = (int)selector;
    [_targetDict setObject:[NSData dataWithBytes:buf length:sizeof(buf)] 
                    forKey:[NSNumber numberWithInt:(int)hotKeyRef]];
    
    return (void*)hotKeyRef;
}

- (void)unregisterHotKey:(void*)hotKeyRef
{
    OSStatus	status;
    
    // Unregister hot key
    status = UnregisterEventHotKey(hotKeyRef);
    
    // Remove hot key reference from dictionary
    [_targetDict removeObjectForKey:
        [NSNumber numberWithInt:(int)hotKeyRef]];
}

登録するときは、まず修飾キーのコードを変換する。続いて、ユニークな値になるように EventHotKeyID を作ってやる。signature としては、適当な値を使ってみた。RegisterEventHotKey() の呼び出しが成功すれば、EventHotKeyRef が得られるはず。これをキーにして、ターゲットの objectselector を保持しておこう。削除側のメソッドは簡単だね。

ホットキーが押されたときに呼び出される、sendEvent: の実装はこんな感じだ。

HotKeyApplication.h (sample)
- (void)sendEvent:(NSEvent*)event
{
    // For hot key event
    if ([event type] == NSSystemDefined && 
        [event subtype] == kEventHotKeyPressedSubtype)
    {
        EventHotKeyRef	hotKeyRef;
        NSData*			data;
        
        // Get hot key refrence
        hotKeyRef = (EventHotKeyRef)[event data1];
        
        // Get object and selector
        data = (NSData*)[_targetDict objectForKey:
                [NSNumber numberWithInt:(int)hotKeyRef]];
        if (data) {
            int	buf[2];
            id	object;
            SEL	selector;
            
            [data getBytes:buf length:sizeof(buf)];
            object = (id)buf[0];
            selector = (SEL)buf[1];
            if (object && selector) {
                [object performSelector:selector];
            }
        }
    }
    
    [super sendEvent:event];
}

まず typesubtype を呼んでイベントをチェックする。ホットキーのイベントだったら、data1 を呼んでやる。これを呼ぶと、EventHotKeyRef を得ることができるんだ。それをキーにして、object と selector を取り出して、performSelector: してやればできあがりだ。

サンプルアプリケーションの実行画面は、下のような感じ。Key テキストフィールドに、'0' から '9' か、'A' から 'Z' の一字を入れて、Register ボタンを押せば、ホットキーが登録されるよ。アプリケーションをバックグラウンドに持っていたりして、実験してみてくれ。

(あまつぶ)

(Unsanity.org)

■関連リンク:
ホットキーに反応する(あまつぶ)
Doing Carbon things in Cocoa (Unsanity.org)

■サンプルダウンロード:
HotKey.tar.gz



[Home] [Download] [Archives] [BBS] [Cocoa Programming Tips 1001] [Core Foundation の秘密] [Safari Developer Center] [はじめてのブラウザのつくり方] [Sketch BP] [スクリーンセイバーを作ろう] [Objective-C 最適化] [Authorization API 完全理解] [Mac OS X Programming Books Review] [オブジェクト指向の言語比較論] [panther-dev]

mailto: mkino@xd5.so-net.ne.jp