MacOSX

MacOSXでUSBデバイスからの入力を取得する

More than 1 year has passed since last update.

USBデバイスと直接やり取りするには、IOKitを利用します。今回はマウスからのデータを取得してみます。

おもむろにIOHIDManagerを作成します。

LowLevelMouse.mm
#import <IOKit/hid/IOHIDManager.h>
void main() {
    IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
}

次に、取得するデバイスの条件を指定します。
デバイスがどのようなプロパティを持っているかは、$ ioregなどを利用して調べます。
今回はデバイスの種類(マウス)と、ベンダーID、プロダクトIDを指定してみました。

LowLevelMouse.mm
    NSDictionary* dict = @{
                           @kIOHIDDeviceUsagePageKey: @(kHIDPage_GenericDesktop),
                            @kIOHIDDeviceUsageKey: @(kHIDUsage_GD_Mouse),
                            @kIOHIDVendorIDKey: @(7119),
                            @kIOHIDProductIDKey: @(7),
                            };
    IOHIDManagerSetDeviceMatching(hidManager, (CFDictionaryRef)dict);

IOHIDManagerOpen(2)で、デバイスを開きます。このとき、第二引数でこのデバイスをシステムから奪うかどうか指定できます。
デバイスを開いたら、入力に対するコールバック関数を登録します。

LowLevelMouse.mm
    IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    IOReturn rv = IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeSeizeDevice);
    if (rv != kIOReturnSuccess) {
        NSLog(@"Cannot open HIDManager");
    } else {
        IOHIDManagerRegisterInputValueCallback(hidManager, &Handle_IOHIDInputValueCallback, NULL);
    }

コールバックの中身はこんな感じです。

LowLevelMouse.mm
void Handle_IOHIDInputValueCallback(void *context, IOReturn result, void *sender, IOHIDValueRef valueRef) {
    if (result == kIOReturnSuccess) {
        IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
        uint32_t usage = IOHIDElementGetUsage(elementRef);

        switch (usage) {
            case kHIDUsage_GD_X:
                printf("x: %f\n", IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical));
                break;
            case kHIDUsage_GD_Y:
                printf("y: %f\n", IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical));
                break;
            case kHIDUsage_GD_Wheel:
                printf("wheel: %f", IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical));
                break;
            default:
                printf("usage:%u", usage);
                break;
        }
    }
}

まずusageがどんな値を取るか調べます。
一般的なデバイスについては、http://www.usb.org/developers/hidpage#HID_Usage に一覧があります。
今回調べたマウスは、x、y、wheelの3つの値から構成されていました。

値の種類が分かったら、IOHIDValueRefから生のバイト列を取得できます。が、通常はIOHIDValueGetScaledValue(2)を使います。この関数は、バイト列を扱いやすいdoubleに変換してくれます。

LowLevelMouse.mm
    CFRelease(hidManager);

終わったら、HIDManagerを解放します。

参考資料