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 \n", 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 );
}
相關文章
相關標籤/搜索