IOHIDManager 不触发键盘回调
IOHIDManager not triggering callback for keyboard
因此,我正在尝试使用 CGL 和 IOHIDManager 组合一个简单的全屏 OpenGL 应用程序,以学习较低级别的 API。目前,我正在创建一个 OpenGL 上下文并全屏启动它。我现在正在尝试添加键盘输入,以便我可以退出该应用程序。我发现了许多使用 IOHIDManager 读取密钥的类似示例,但无论我做什么,我的回调都不会触发。
我的回调只是一个打印 "here" 的函数。我不确定哪里出错了——我已经尝试了 CFRunLoopGetCurrent() 和 CFRunLoopMain()。我的 main 只是一个 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 的末尾,我的回调会被调用,但函数永远不会 returns。这应该如何在单线程 CGL 应用程序中工作? IOHIDManager 需要 运行 循环才能运行,这是一个严格的要求吗?
原来我需要用 CreateInputManager
函数创建一个单独的 pthread,指定 IOHIMDanager 是在 CFRunLoopGetCurrent()
上安排回调并在其上启动一个 运行 循环通过调用 CFRunLoopRun()
.
线程
我想知道是否有办法让 IOHIDManager 使用普通的轮询而不是这些回调...
IOKit 和 HID 通过 Mach 消息传递工作,而这又与运行循环机制深度集成,如您所见。如果您确实想要忙轮询,可以使用零超时的 CFRunLoopRunInMode
函数来检查事件。
您可能希望考虑使用 CVDisplayLink 在每个垂直帧刷新时调用您的渲染代码。显示 link 的回调将从运行循环中调用,因此您可以将主线程 运行 留在 CFRunLoopRun() 中。
有关 Apple 建议您在 OpenGL 应用程序中构建事件处理的方式,请参阅 https://developer.apple.com/library/mac/qa/qa1385/_index.html。
因此,我正在尝试使用 CGL 和 IOHIDManager 组合一个简单的全屏 OpenGL 应用程序,以学习较低级别的 API。目前,我正在创建一个 OpenGL 上下文并全屏启动它。我现在正在尝试添加键盘输入,以便我可以退出该应用程序。我发现了许多使用 IOHIDManager 读取密钥的类似示例,但无论我做什么,我的回调都不会触发。
我的回调只是一个打印 "here" 的函数。我不确定哪里出错了——我已经尝试了 CFRunLoopGetCurrent() 和 CFRunLoopMain()。我的 main 只是一个 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 的末尾,我的回调会被调用,但函数永远不会 returns。这应该如何在单线程 CGL 应用程序中工作? IOHIDManager 需要 运行 循环才能运行,这是一个严格的要求吗?
原来我需要用 CreateInputManager
函数创建一个单独的 pthread,指定 IOHIMDanager 是在 CFRunLoopGetCurrent()
上安排回调并在其上启动一个 运行 循环通过调用 CFRunLoopRun()
.
我想知道是否有办法让 IOHIDManager 使用普通的轮询而不是这些回调...
IOKit 和 HID 通过 Mach 消息传递工作,而这又与运行循环机制深度集成,如您所见。如果您确实想要忙轮询,可以使用零超时的 CFRunLoopRunInMode
函数来检查事件。
您可能希望考虑使用 CVDisplayLink 在每个垂直帧刷新时调用您的渲染代码。显示 link 的回调将从运行循环中调用,因此您可以将主线程 运行 留在 CFRunLoopRun() 中。
有关 Apple 建议您在 OpenGL 应用程序中构建事件处理的方式,请参阅 https://developer.apple.com/library/mac/qa/qa1385/_index.html。