22

支援技術の目的でOSXキーボードフックを作成しようとしています(つまり、キーロガーではなく、心配しないでください)。

ユーザーがキーを押したときに、実際のキーが押されるのを防ぎ、代わりに偽のキーを押す(自分で選択した文字)を送信したいと思います。

私は次のコードを持っています:

- (void) hookTheKeyboard {
    CGEventMask keyboardMask = CGEventMaskBit(kCGEventKeyDown);
    id eventHandler = [NSEvent addGlobalMonitorForEventsMatchingMask:keyboardMask handler:^(NSEvent *keyboardEvent) {
        NSLog(@"keyDown: %c", [[keyboardEvent characters] characterAtIndex:0]);
        //Want to: Stop the keyboard input
        //Want to: Send another key input instead
    }];
}

これらの目標のいずれかを達成するための助けはありますか?基本的に、NSEvent「keyboardEvent」を変更して別の文字を送信します。ありがとう。

4

3 に答える 3

54

NSEventAPIを使用してこれを行うことはできませんが、を使用してこれを行うことができCGEventTapます。アクティブなイベントタップを作成し、を受信して​​それを変更できる(必要な場合)コールバックを登録し、それを返して実際のイベントストリームを変更できます。CGEventRef


編集

これは、実行中にすべての「b」キーストロークを「v」に置き換える単純なプログラムです。

#import <Cocoa/Cocoa.h>

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
  //0x0b is the virtual keycode for "b"
  //0x09 is the virtual keycode for "v"
  if (CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == 0x0B) {
    CGEventSetIntegerValueField(event, kCGKeyboardEventKeycode, 0x09);
  }

  return event;
}

int main(int argc, char *argv[]) {
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  CFRunLoopSourceRef runLoopSource;

  CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, myCGEventCallback, NULL);

  if (!eventTap) {
    NSLog(@"Couldn't create event tap!");
    exit(1);
  }

  runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

  CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

  CGEventTapEnable(eventTap, true);

  CFRunLoopRun();

  CFRelease(eventTap);
  CFRelease(runLoopSource);
  [pool release];

  exit(0);
}

(おもしろい話:この投稿を編集している間、「すべての「b」キーストロークを置き換える」と書き続けましたが、「すべての「v」キーストロークを置き換える」と表示され続けました。混乱しました。それから、それを思い出しました。私はまだアプリを停止していませんでした。)

于 2011-04-26T04:21:32.527 に答える
5

私はこの答えに出くわしました。同じことをする必要がありましたが、グローバルではなく、自分のアプリケーション内のイベントに対してのみです。このはるかに単純な問題には、はるかに単純な解決策があります。これは、他の人に役立つ場合に備えて、ここで注意します。

  • sendEvent:のオーバーライドを作成することにより、ウィンドウでイベントをインターセプトしました。次に、キーイベント(KeyUpまたはKeyDown)を確認し、前のイベントのほぼすべてのデータを使用して新しいイベントを作成し、代わりにこのイベントでNSWindowスーパークラスを呼び出します。

これは私にとっては完璧に機能しているようで、keyCodeの部分を変更する必要もありませんでしたが、おそらくこれが問題になる可能性があります...

Swiftの例:

class KeyInterceptorWindow : NSWindow {

    override func sendEvent(theEvent: NSEvent) {

        if theEvent.type == .KeyDown || theEvent.type == .KeyUp {
            println(theEvent.description)
            let newEvent = NSEvent.keyEventWithType(theEvent.type, 
                location: theEvent.locationInWindow, 
                modifierFlags: theEvent.modifierFlags, 
                timestamp: theEvent.timestamp, 
                windowNumber: theEvent.windowNumber, 
                context: theEvent.context, 
                characters: "H", 
                charactersIgnoringModifiers: theEvent.charactersIgnoringModifiers!, 
                isARepeat: theEvent.ARepeat, 
                keyCode: theEvent.keyCode)
            super.sendEvent(newEvent!)
        } else {
            super.sendEvent(theEvent)
        }

    }

}
于 2015-04-28T12:47:46.597 に答える
2

james_alvarezの答えのSwift4+バージョン:

class KeyInterceptorWindow: NSWindow {
    override func sendEvent(_ event: NSEvent) {
        if [.keyDown, .keyUp].contains(event.type) {
            let newEvent = NSEvent.keyEvent(with: event.type,
                                            location: event.locationInWindow,
                                            modifierFlags: event.modifierFlags,
                                            timestamp: event.timestamp,
                                            windowNumber: event.windowNumber,
                                            context: nil,
                                            characters: "H",
                                            charactersIgnoringModifiers: event.charactersIgnoringModifiers ?? "",
                                            isARepeat: event.isARepeat,
                                            keyCode: event.keyCode)

            if let newEvent = newEvent {
                super.sendEvent(newEvent)
            }
        } else {
            super.sendEvent(event)
        }
    }
}
于 2019-04-04T18:45:59.683 に答える