Macos IOHIDManager未触发键盘的回调

Macos IOHIDManager未触发键盘的回调,macos,core-foundation,iokit,Macos,Core Foundation,Iokit,因此,我尝试使用CGL和IOHIDManager组合一个简单的全屏OpenGL应用程序,以便学习较低级别的API。目前,我正在创建一个OpenGL上下文并在全屏上启动它。我正在尝试添加键盘输入,以便退出应用程序。我发现了许多使用IOHIDManager读取键的类似示例,但无论我做什么,我的回调都不会触发 我的回调函数只是一个打印“here”的函数。我不确定哪里出了问题——我已经尝试了CFRunLoopGetCurrent()和CFRunLoopMain()。我的主循环只是一个while循环。有什

因此,我尝试使用CGL和IOHIDManager组合一个简单的全屏OpenGL应用程序,以便学习较低级别的API。目前,我正在创建一个OpenGL上下文并在全屏上启动它。我正在尝试添加键盘输入,以便退出应用程序。我发现了许多使用IOHIDManager读取键的类似示例,但无论我做什么,我的回调都不会触发

我的回调函数只是一个打印“here”的函数。我不确定哪里出了问题——我已经尝试了CFRunLoopGetCurrent()和CFRunLoopMain()。我的主循环只是一个while循环。有什么好处

CFMutableDictionaryRef CreateMatchingDictionary(UInt32 usage_page, UInt32 usage) {        
    CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

    CFNumberRef page_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page);            
    CFDictionarySetValue(dictionary, CFSTR(kIOHIDDeviceUsagePageKey), page_number);
    CFRelease(page_number);

    CFNumberRef usage_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);            
    CFDictionarySetValue(dictionary, CFSTR(kIOHIDDeviceUsageKey), usage_number);
    CFRelease(usage_number);

    return dictionary;
}

void CreateInputManager() {
    IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
    CFMutableDictionaryRef matching_dictionary = CreateMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
    IOHIDManagerSetDeviceMatching(hid_manager, matching_dictionary);
    IOHIDManagerRegisterInputValueCallback(hid_manager, KeyboardCallback, NULL);

    IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
    IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}

void KeyboardCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {                                                                                                       
    puts("CALLBACK!");
}

int main() {
    // Commented out CGL context & fullscreen window creation
    CreateInputManager();
    while(true) {
        ;   
    }   
}
更新


如果我将CFRunLoopRun()放在函数CreateInputManager的末尾,则会调用回调函数,但函数永远不会返回。这在单线程CGL应用程序中应该如何工作?IOHIDManager是否严格要求运行循环才能正常工作?

事实证明,我需要使用
CreateInputManager
函数创建一个单独的pthread,指定IOHIDManager在
CFRunLoopGetCurrent()
上调度回调,并通过调用
CFRunLoopRun()在该线程上启动运行循环


我想知道是否有办法让IOHIDManager使用普通的旧轮询而不是这些回调…

IOKit和HID通过Mach消息传递工作,而Mach消息传递又与runloop机制深入集成,正如您所发现的那样。如果您确实想要忙轮询,可以使用带有零超时的
CFRunLoopRunInMode
函数检查事件

您可能希望考虑使用CVDeStudioLink在每个垂直帧刷新中调用您的渲染代码。显示链接的回调将从runloop调用,因此您可以让主线程在CFRunLoopRun()中运行


请参阅Apple建议您如何在OpenGL应用程序中构造事件处理。

非常好,因此如果我选择通过将HID设置为使用CFRunLoopInMode来进行繁忙轮询,从技术上讲,我的程序中是否没有runloop机制?另外,感谢CVDisplayLink提示,我知道它的iOS版本,但没有OSX版本。嗯,将有一个runloop机制,但您可以选择runloop何时处理事件,一旦它处理完所有挂起的事件,它将从
CFRunLoopInMode
返回并将控制权交还给您的应用程序。实际上,IOHIDQueueCopyNextValueWithTimeout是否允许我在不创建运行循环的情况下在主线程上忙着轮询密钥状态?我不确定如何在内部实现
IOHIDQueueCopyNextValueWithTimeout
/
IOHIDQueueCopyNextValueWithTimeout
,但它可能会很好地工作。