在OSX系统全局监听键盘的按下事件,并可以捕获事件源的硬件的接口位置,用于区分是哪个键盘产生的事件。下面的代码只是以键盘为例子,其实是可以适用于其他输入外设的。如有需要可搜索相关外设的匹配字典的创建代码。
设备匹配字典
CFMutableDictionaryRef myCreateDeviceMatchingDictionary(UInt32 usagePage, UInt32 usage ) { CFMutableDictionaryRef dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0 , & kCFTypeDictionaryKeyCallBacks , & kCFTypeDictionaryValueCallBacks ); if ( ! dict ) return NULL; CFNumberRef pageNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, & usagePage ); if ( ! pageNumberRef ) { CFRelease( dict ); return NULL; } CFDictionarySetValue( dict, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef ); CFRelease( pageNumberRef ); CFNumberRef usageNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, & usage ); if ( ! usageNumberRef ) { CFRelease( dict ); return NULL; } CFDictionarySetValue( dict, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef ); CFRelease( usageNumberRef ); return dict; }
事件的回调函数
void myHIDKeyboardCallback(void* context, IOReturn result, void* sender, IOHIDValueRef value ) { //get device product id and vendor id IOHIDDeviceRef device = sender; // int32_t pid = 1; // CFNumberGetValue(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)), kCFNumberSInt32Type, &pid); // int32_t vendorID = 0; // CFNumberGetValue(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)), kCFNumberSInt32Type, &vendorID); // NSLog(@"vendor:%d product:%d", vendorID, pid); IOHIDElementRef elem = IOHIDValueGetElement( value ); // if (IOHIDElementGetUsagePage(elem) != 0x07) // return; uint32_t scancode = IOHIDElementGetUsage( elem ); if (scancode < 3 || scancode > 231) return; int32_t locationID = 0; CFNumberGetValue(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey)), kCFNumberSInt32Type, &locationID); NSLog(@"location:%d", locationID); long pressed = IOHIDValueGetIntegerValue( value ); uint64_t timestamp = IOHIDValueGetTimeStamp(value); printf( "scancode: %3d, %s timestamp:%llu ", scancode, pressed?"keydown":"keyup ", timestamp); //send the keyboard event NSDictionary* userInfo = [[NSDictionary alloc]initWithObjectsAndKeys: [NSNumber numberWithInt:scancode], NOTIFICATION_KEY_ScanCode, [NSNumber numberWithInt:locationID], NOTIFICATION_KEY_Location, [NSNumber numberWithLong:pressed], NOTIFICATION_KEY_IsKeyDown, [NSNumber numberWithLong:timestamp], NOTIFICATION_KEY_Timestamp, nil]; NSNotification* notification = [NSNotification notificationWithName:NOTIFICATION_KeyBoardEvent object:nil userInfo:userInfo]; [[NSNotificationCenter defaultCenter] postNotification:notification]; UsbSignalController* controller = (__bridge UsbSignalController*)context; [controller onKeyEvent:scancode Location:locationID IsDown:pressed Timestamp:timestamp]; }
注册键盘钩子
-(void)registerKeyboardHook { IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone ); CFMutableDictionaryRef keyboard = myCreateDeviceMatchingDictionary( 0x01, 6 ); CFArrayRef matches; { //CFMutableDictionaryRef keypad = myCreateDeviceMatchingDictionary( 0x01, 7 ); CFMutableDictionaryRef matchesList[] = { keyboard/*, keypad*/ }; matches = CFArrayCreate( kCFAllocatorDefault, (const void **)matchesList, 1/*2*/, NULL ); } IOHIDManagerSetDeviceMatchingMultiple(hidManager, matches ); CFRelease(matches); CFRelease(keyboard ); IOHIDManagerRegisterInputValueCallback(hidManager, myHIDKeyboardCallback, (__bridge void*)self); IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode ); IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone ); }