63

アプリケーションがフォーカスされていない場合でも、キーストロークを転送する必要がある Mac OS X 用のタイピング チューター アプリケーションに取り組んでいます。

おそらくNSDistributedNotificationCenterを介して、システムにキーストロークをアプリに転送させる方法はありますか? 私はばかげて自分自身をグーグルで検索しましたが、答えを見つけることができませんでした...

編集: 以下のサンプル コード

正しい方向に向けてくれた@NSGodに感謝します-メソッドを使用してグローバルイベントモニターaddGlobalMonitorForEventsMatchingMask:handler:を追加することになりました。これは美しく機能します。完全を期すために、私の実装は次のようになります。

// register for keys throughout the device...
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                       handler:^(NSEvent *event){

    NSString *chars = [[event characters] lowercaseString];
    unichar character = [chars characterAtIndex:0];

    NSLog(@"keydown globally! Which key? This key: %c", character);

}];

私にとって、トリッキーな部分はブロックを使用していたので、誰かに役立つ場合に備えて少し説明します。

上記のコードで注意すべき点は、NSEvent に対する1 つのメソッド呼び出しであるということです。ブロックは引数として関数に直接渡さます。インライン デリゲート メソッドのようなものと考えることができます。これが私にとって沈み込むのに時間がかかったという理由だけで、私はそれをここで段階的に処理するつもりです:

[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask

この最初のビットは問題ありません。NSEvent でクラス メソッドを呼び出し、監視するイベント (この場合は NSKeyDownMask) を伝えます。サポートされているイベント タイプのマスクのリストは、こちらにあります。

ここで、ブロックを必要とするハンドラーという難しい部分に取り掛かります。

handler:^(NSEvent *event){

これを正しく行うにはいくつかのコンパイル エラーが発生しましたが、(Apple に感謝します) 非常に建設的なエラー メッセージでした。まず気になるのはカラット^。これは、ブロックの開始を示します。その後、括弧内に、

NSEvent *event

イベントをキャプチャするためにブロック内で使用する変数を宣言します。あなたはそれを呼び出すことができます

NSEvent *someCustomNameForAnEvent

ブロック内でその名前を使用するだけです。あとは、これで終わりです。中括弧と括弧を閉じて、メソッド呼び出しを終了してください。

}];

そして、あなたは完了です!これは本当に「ワンライナー」のようなものです。アプリ内のどこでこの呼び出しを実行しても問題ありません。AppDelegate の applicationDidFinishLaunching メソッドで実行します。次に、ブロック内で、アプリ内から他のメソッドを呼び出すことができます。

4

4 に答える 4

26

OS X 10.6+の最小要件に問題がなく、イベントのストリームへの「読み取り専用」アクセスで十分な場合は、Cocoa: Cocoaイベント処理ガイド:イベントの監視にグローバルイベントモニターをインストールできます。

OS X 10.5以前をサポートする必要があり、読み取り専用アクセスで問題がなく、Carbon Event Managerを使用してもかまわない場合は、基本的にを使用してCarbonと同等の機能を実行できます GetEventMonitorTarget()。(ただし、その方法に関する(公式の)ドキュメントを見つけるのは難しいでしょう)。そのAPIはOSX10.3で最初に利用可能になったと思います。

イベントストリームへの読み取り/書き込みアクセスが必要な場合は、ApplicationServices> CoreGraphics:CGEventTapCreate()およびその仲間の一部である少し低レベルのAPIを確認する必要があります。これは10.4で最初に利用可能になりました。

3つの方法すべてで、ユーザーが[システム環境設定]> [ユニバーサルアクセス]環境設定ペインで[支援デバイスへのアクセスを有効にする]を有効にする必要があることに注意してください(少なくとも主要なイベントの場合)。

于 2011-01-21T00:29:43.570 に答える
15

私のケースで機能したコードを投稿しています。

アプリの起動後にグローバル イベント ハンドラーを追加しています。私のショートカットは ctrl+alt+cmd+T でアプリを開きます。

- (void) applicationWillFinishLaunching:(NSNotification *)aNotification
{
    // Register global key handler, passing a block as a callback function
    [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                           handler:^(NSEvent *event){

        // Activate app when pressing cmd+ctrl+alt+T
        if([event modifierFlags] == 1835305 && [[event charactersIgnoringModifiers] compare:@"t"] == 0) {

              [NSApp activateIgnoringOtherApps:YES];
        }
    }];

}
于 2012-06-03T20:01:39.683 に答える
4

NSGodがすでに指摘しているように、CoreGraphicsを使用することもできます。

クラス内(例:-init):

CFRunLoopRef runloop = (CFRunLoopRef)CFRunLoopGetCurrent();

CGEventMask interestedEvents = NSKeyDown;
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 
                                        0, interestedEvents, myCGEventCallback, self);
// by passing self as last argument, you can later send events to this class instance

CFRunLoopSourceRef source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, 
                                                           eventTap, 0);
CFRunLoopAddSource((CFRunLoopRef)runloop, source, kCFRunLoopCommonModes);
CFRunLoopRun();

クラスの外ですが、同じ.mファイルにあります。

CGEventRef myCGEventCallback(CGEventTapProxy proxy, 
                             CGEventType type, 
                             CGEventRef event, 
                             void *refcon)
{

    if(type == NX_KEYDOWN)
    {
       // we convert our event into plain unicode
       UniChar myUnichar[2];
       UniCharCount actualLength;
       UniCharCount outputLength = 1;
       CGEventKeyboardGetUnicodeString(event, outputLength, &actualLength, myUnichar);

       // do something with the key

       NSLog(@"Character: %c", *myUnichar);
       NSLog(@"Int Value: %i", *myUnichar);

       // you can now also call your class instance with refcon
       [(id)refcon sendUniChar:*myUnichar];
   }

   // send event to next application
   return event;
}
于 2013-02-20T16:33:28.783 に答える
4

これで私が見つけた問題は、別のアプリによってグローバルに登録されたキーは咳をしないということです...または少なくとも私の場合、おそらく私は何か間違ったことをしています.

たとえば、「Command-Shift-3」のように、プログラムがすべてのキーを表示する必要がある場合、それを表示するために通過することはわかりません... OSによって占有されるためです。

それとも誰かがそれを理解しましたか?ぜひ知りたい...

于 2011-02-17T19:50:57.703 に答える