MacでHID準拠USBゲームコントローラの値を取得したい
2017-01-01 15:57 - 2 min readコントローラがどんな種類の入力をもっているかスキャンできるコードを紹介します。
このプログラムの管理下にあるときは任意のタイミングで入力の状態がどうなっているかもチェックできます。
startメソッド
の無限ループはチェックのためにその場におきました。よきに取り除いてください。
Criteriaには検出したいデバイスの条件を設定して下さい。
// HIDDeviceManager
#import <Foundation/Foundation.h>
#import <IOKit/hid/IOHIDLib.h>
#import "HIDDeviceManager.h"
static const int numOfDetection = 2;
static const NSDictionary* criteria = @{@kIOHIDDeviceUsagePageKey: @(kHIDPage_GenericDesktop),
@kIOHIDDeviceUsageKey: @(kHIDUsage_GD_Joystick)};
static void CFSetApplier(const void *value,void *context)
{
CFArrayAppendValue((CFMutableArrayRef)context,value);
}
@interface HIDDeviceManager (){}
@property(nonatomic) IOHIDManagerRef manager;
@property(nonatomic) IOHIDDeviceRef* devices;
@property(nonatomic) int deviceNum;
@end
@implementation HIDDeviceManager
- (void) start {
self.manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
IOHIDManagerSetDeviceMatching(self.manager, (__bridge CFDictionaryRef)criteria);
IOHIDManagerOpen(self.manager, kIOHIDOptionsTypeNone);
CFSetRef copyOfDevices = IOHIDManagerCopyDevices(self.manager);
CFMutableArrayRef hidDevices = CFArrayCreateMutable(kCFAllocatorDefault, 0 ,&kCFTypeArrayCallBacks);
CFSetApplyFunction(copyOfDevices, CFSetApplier, (void*)hidDevices);
CFRelease(copyOfDevices);
IOHIDDeviceRef shoudlManage[numOfDetection];
int deviceCount = (int)CFArrayGetCount(hidDevices);
for (int i=0; i<deviceCount && i < numOfDetection; i++) {
IOHIDDeviceRef hidDevice = (IOHIDDeviceRef)CFArrayGetValueAtIndex(hidDevices, i);
if (hidDevice == NULL) {
continue;
}
shoudlManage[self.deviceNum++] = hidDevice;
}
self.devices = shoudlManage;
CFRelease(hidDevices);
while(1) {
time_t t0;
t0=time(NULL);
while(t0==time(NULL))
{
}
for (int i=0; i<self.deviceNum; i++) {
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self.devices[i], NULL, 0);
int elementCount = (int)CFArrayGetCount(elements);
for (int j=0; j<elementCount; j++) {
IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, j);
IOHIDElementType elementType = IOHIDElementGetType(element);
unsigned int usage = IOHIDElementGetUsage(element);
unsigned int usagePage = IOHIDElementGetUsagePage(element);
printf("element %d: type: %d usage: %d value: ", j, elementType, usagePage);
switch(elementType) {
case kIOHIDElementTypeInput_ScanCodes:
case kIOHIDElementTypeInput_Misc:
case kIOHIDElementTypeInput_Button:
case kIOHIDElementTypeInput_Axis:
{
IOHIDValueRef valueRef;
IOHIDDeviceGetValue(self.devices[i], element, &valueRef);
int value = (int)IOHIDValueGetIntegerValue(valueRef);
printf("%d", value);
}
default: {
printf("\n");
break;
}
}
}
CFRelease(elements);
}
}
}
@end
今回はObjective-Cのコードを紹介しますが,Swift3上のコードでも実現できます。やることは各型のRefという接尾辞やCFReleaseを取り除いたり,引数のコールバックをクロージャあるいは関数のUnsafePointerで渡すといった変更を加えていけばObjective-Cレスでスッキリします。別の実装ではSwiftを使っていますが,今回はUnsafePointer
それにしてもI/OKit面倒臭いですね。
値が変更されたタイミングにその値をコールバックで受け取って処理したいならもっとスッキリとした実装があります。 Mac OS Xで動作するドライバの開発