使用 IOHIDManager 获取修饰符键事件 [英] Using IOHIDManager to Get Modifier Key Events

查看:13
本文介绍了使用 IOHIDManager 获取修饰符键事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 IOHIDManager 来获取修饰键事件,因为缺少 Cocoa flagsChanged 事件(很难区分按下/释放、左/右是否都按下等)这是我创建管理器的代码和注册回调.

I'm trying to use IOHIDManager to get modifier key events because Cocoa flagsChanged events are lacking (difficult to differentiate between press/release, left/right if both are down, etc.) Here's the code where I create the manager and register the callback.

IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
        kIOHIDOptionsTypeNone);
if (CFGetTypeID(hidManager) != IOHIDManagerGetTypeID())
    return 1;

CFMutableDictionaryRef capsLock =
    myCreateDeviceMatchingDictionary(0x07, 0x39);
CFMutableDictionaryRef lctrl =
    myCreateDeviceMatchingDictionary(0x07, 0xE0);
CFMutableDictionaryRef lshift =
    myCreateDeviceMatchingDictionary(0x07, 0xE1);
CFMutableDictionaryRef lalt =
    myCreateDeviceMatchingDictionary(0x07, 0xE2);
CFMutableDictionaryRef lsuper =
    myCreateDeviceMatchingDictionary(0x07, 0xE3);
CFMutableDictionaryRef rctrl =
    myCreateDeviceMatchingDictionary(0x07, 0xE4);
CFMutableDictionaryRef rshift =
    myCreateDeviceMatchingDictionary(0x07, 0xE5);
CFMutableDictionaryRef ralt =
    myCreateDeviceMatchingDictionary(0x07, 0xE6);
CFMutableDictionaryRef rsuper =
    myCreateDeviceMatchingDictionary(0x07, 0xE7);

CFMutableDictionaryRef matchesList[] = {
    capsLock,
    lctrl,
    lshift,
    lalt,
    lsuper,
    rctrl,
    rshift,
    ralt,
    rsuper
};
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault,
        (const void **)matchesList, 9, NULL);
IOHIDManagerSetDeviceMatchingMultiple(hidManager, matches);

IOHIDManagerRegisterInputValueCallback(hidManager,
        myHandleModifiersCallback, NULL);

IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode);

IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);

但是,回调永远不会运行.我错过了什么吗?

However, the callback is never being run. Am I missing anything?

我不完全了解 HID 使用页面,所以我不知道是使用带有键盘使用 ID (06) 的通用桌面页面 (0x01) 还是使用带有使用 ID 的键盘/键盘页面 (0x07)对于各个键.也许这与它有关?

I don't fully understand HID usage pages, so I didn't know whether or not to use Generic Desktop Page (0x01) with the keyboard usage ID (06) or the Keyboard/Keypad Page (0x07) with Usage IDs for the individual keys. Maybe that has something to do with it?

推荐答案

我想通了.这样做的方法是使用通用桌面页面 (0x01) 键盘 (06)(和键盘 (07) 以确保完整性)与 IOHIDManagerSetDeviceMatchingMultiple 一起使用,然后输入值回调获取键盘/键盘使用页面 (0x07) 的东西.

I figured it out. The way to do it is to use the Generic Desktop Page (0x01) Keyboard (06) (and Keypad (07) for completeness) for use with IOHIDManagerSetDeviceMatchingMultiple, and then the input value callback gets Keyboard/Keypad Usage Page (0x07) stuff.

例如,要为所有键盘/小键盘设置一个 HIDManager,可以执行以下操作:

For example, to setup a an HIDManager for all keyboards/keypads, one could do something like:

IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
        kIOHIDOptionsTypeNone);

CFMutableDictionaryRef keyboard =
    myCreateDeviceMatchingDictionary(0x01, 6);
CFMutableDictionaryRef keypad =
    myCreateDeviceMatchingDictionary(0x01, 7);

CFMutableDictionaryRef matchesList[] = {
    keyboard,
    keypad,
};
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault,
        (const void **)matchesList, 2, NULL);
IOHIDManagerSetDeviceMatchingMultiple(hidManager, matches);

IOHIDManagerRegisterInputValueCallback(hidManager,
        myHIDKeyboardCallback, NULL);

IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode);

IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);

myCreateDeviceMatchingDictionary 类似于:

Where myCreateDeviceMatchingDictionary is something like:

CFMutableDictionaryRef myCreateDeviceMatchingDictionary(UInt32 usagePage,
        UInt32 usage) {
    CFMutableDictionaryRef ret = CFDictionaryCreateMutable(kCFAllocatorDefault,
            0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
    if (!ret)
        return NULL;

    CFNumberRef pageNumberRef = CFNumberCreate(kCFAllocatorDefault,
            kCFNumberIntType, &usagePage );
    if (!pageNumberRef) {
        CFRelease(ret);
        return NULL;
    }

    CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef);
    CFRelease(pageNumberRef);

    CFNumberRef usageNumberRef = CFNumberCreate(kCFAllocatorDefault,
            kCFNumberIntType, &usage);
    if (!usageNumberRef) {
        CFRelease(ret);
        return NULL;
    }

    CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef);
    CFRelease(usageNumberRef);

    return ret;
}

而 myHIDKeyboardCallback 类似于:

And myHIDKeyboardCallback is something like:

void myHIDKeyboardCallback(void *context, IOReturn result, void *sender,
        IOHIDValueRef value) {
    IOHIDElementRef elem = IOHIDValueGetElement(value);
    if (IOHIDElementGetUsagePage(elem) != 0x07)
        return;
    uint32_t scancode = IOHIDElementGetUsage(elem);
    if (scancode < 4 || scancode > 231)
        return;
    long pressed = IOHIDValueGetIntegerValue(value);
    // ... Do something ...
}

请注意,回调似乎在每次按下或释放时被调用多次,但使用 ID 超出正常范围,这就是if (scancode < 4 || scancode > 231)"的用途.

Note that the callback seems to be called multiple times per press or release but with usage IDs outside the normal range, which is what the "if (scancode < 4 || scancode > 231)" is for.

这篇关于使用 IOHIDManager 获取修饰符键事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆