IOHIDManager不会触发键盘回调

时间:2016-02-19 03:12:15

标签: macos core-foundation iokit

因此,我尝试使用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要求运行循环才能运行?

2 个答案:

答案 0 :(得分:1)

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

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

请参阅https://developer.apple.com/library/mac/qa/qa1385/_index.html,了解Apple建议您如何在OpenGL应用程序中构建事件处理。

答案 1 :(得分:0)

结果我需要使用CreateInputManager函数创建一个单独的pthread,指定IOHIDManager在CFRunLoopGetCurrent()上安排回调并通过调用{{1}启动该线程上的运行循环}}

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