2011-04-26 39 views
19

我想创建一个OS X的键盘钩为辅助技术的目的(即不要担心,不是一个键盘记录)。修改NSEvent发送一个不同的密钥比被按下

当用户按下一个键,我想防止真正的按键和发送假的按键(我选择的角色)来代替。

我有以下代码:

- (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”来发送不同的字符。谢谢。

回答

39

你不能用NSEvent API来做到这一点,但你可以用可以CGEventTap做到这一点。您可以创建一个活动事件点击并注册a callback,该点接收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'keystroke”,但它一直以“替换每个'v'keystroke”的形式出现。我很困惑,然后我记得我还没有停止过应用程序)

+0

相当新的Objective-C ...帮助一些示例代码?这与我以上的所有相似吗? – cksubs 2011-04-26 05:02:41

+4

如果有帮助:CGEvent apis都是C.不需要objc。 – justin 2011-04-26 05:23:51

+1

@cksubs编辑答案。 – 2011-04-26 05:50:11

3

我发生在这个答案,需要做同样的事情,但只适用于我自己的应用程序不是全球范围内的事件。还有一个更简单的解决方案,这个更简单问题,我在这里指出柜面这对谁都有用:

  • 我拦截事件窗口,通过创建的SendEvent的覆盖:.然后检查关键事件(KeyUp或KeyDown),然后使用几乎所有来自前置事件的数据创建新事件,然后使用此事件调用NSWindow超类。

这似乎完美地工作对我来说,我没有,甚至修改键代码的一部分 - 但也许这可能是一个问题......在斯威夫特

例子:

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) 
    } 
} 

}