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 ); }
Keep it simple!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战