OSX监听全局键盘按下事件并捕获事件源的硬件接口位置

在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 );
}
原文地址:https://www.cnblogs.com/keitsi/p/7531408.html