-
-
Save dhleong/6a4834185ab259d2a962 to your computer and use it in GitHub Desktop.
OSX JoyTest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.m | |
// JoyTest | |
// | |
// Created by Daniel Leong on 12/18/14. | |
// Copyright (c) 2014 Daniel Leong. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import <IOKit/hid/IOHIDManager.h> | |
enum | |
{ | |
kJoystickGammaTableSize = 256 | |
}; | |
static void HandleDeviceMatchingCallback(void * inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef); | |
static void HandleInputValueCallback(void * inContext, IOReturn inResult, void* inSender, IOHIDValueRef inIOHIDValueRef); | |
static void HandleDeviceRemovalCallback(void * inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef); | |
static void HandleDevice(IOHIDDeviceRef inIOHIDDeviceRef); | |
static int AxisIndex(uint32_t page, uint32_t usage); | |
int main(int argc, const char * argv[]) { | |
@autoreleasepool { | |
// insert code here... | |
NSLog(@"Hello, World!"); | |
IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); | |
IOHIDManagerSetDeviceMatching(hidManager, NULL); | |
IOHIDManagerRegisterDeviceMatchingCallback(hidManager, HandleDeviceMatchingCallback, NULL); | |
IOHIDManagerRegisterDeviceRemovalCallback(hidManager, HandleDeviceRemovalCallback, NULL); | |
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); | |
IOReturn iores = IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); | |
if (iores != kIOReturnSuccess) { | |
NSLog(@"Cannot open HID manager; joystick support will not function."); | |
} | |
else { | |
NSLog(@"Opened!"); | |
} | |
// CFSetRef set = IOHIDManagerCopyDevices(hidManager); | |
// CFIndex count = CFSetGetCount(set); | |
// const IOHIDDeviceRef results[count]; | |
// | |
// CFSetGetValues(set, (const void **)&results); | |
// for (int i=0; i < count; i++) { | |
//// NSLog(@"%s", results[i]); | |
// CFStringRef ref = IOHIDDeviceGetProperty(results[i], | |
// CFSTR(kIOHIDManufacturerKey)); | |
// NSString *manufacturer = (__bridge NSString *) ref; | |
//// long len = CFStringGetLength(ref); | |
//// char str[len]; | |
//// CFStringGetCString(ref, str, len, ) | |
// | |
// if ([manufacturer containsString:@"ustmaster"]) { | |
// HandleDevice(results[i]); | |
// } | |
// } | |
CFRunLoopRun(); | |
} | |
return 0; | |
} | |
static void HandleDevice(IOHIDDeviceRef device) { | |
NSLog(@"Discovered device!: %@", device); | |
IOOptionBits options = kIOHIDOptionsTypeNone; | |
IOReturn result = IOHIDDeviceOpen(device, options); | |
if (result != kIOReturnSuccess) { | |
NSLog(@"result: %d", result); | |
return; | |
} | |
NSDictionary *dict = [[NSDictionary alloc] init]; | |
IOHIDDeviceRegisterInputValueCallback(device, HandleInputValueCallback, (__bridge void *)(dict)); | |
CFArrayRef elementList = IOHIDDeviceCopyMatchingElements(device, NULL, 0L); | |
if (elementList != NULL) | |
{ | |
CFIndex idx, count = CFArrayGetCount(elementList); | |
for (idx = 0; idx < count; idx++) | |
{ | |
IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elementList, idx); | |
IOHIDElementType elementType = IOHIDElementGetType(element); | |
if (elementType > kIOHIDElementTypeInput_ScanCodes) | |
{ | |
continue; | |
} | |
IOHIDElementCookie elementCookie = IOHIDElementGetCookie(element); | |
uint32_t usagePage = IOHIDElementGetUsagePage(element); | |
uint32_t usage = IOHIDElementGetUsage(element); | |
uint32_t min = (uint32_t)IOHIDElementGetPhysicalMin(element); | |
uint32_t max = (uint32_t)IOHIDElementGetPhysicalMax(element); | |
NSString *name = (__bridge NSString *)IOHIDElementGetProperty(element, CFSTR(kIOHIDElementNameKey)) ?: @"unnamed"; | |
IOHIDValueRef ref; | |
IOHIDDeviceGetValue(device, element, &ref); | |
if (ref) { | |
CFIndex intValue = IOHIDValueGetIntegerValue(ref); | |
if (intValue) { | |
NSLog(@"#%ld, %@ - usage %d:%d, cookie %d, range %d-%d", idx, name, usagePage, usage, (int) elementCookie, min, max); | |
NSLog(@" --> value=%ld", intValue); | |
} | |
} | |
} | |
CFRelease(elementList); | |
} | |
} | |
static void HandleDeviceMatchingCallback(void * inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef device) | |
{ | |
CFStringRef ref = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDManufacturerKey)); | |
NSString *manufacturer = (__bridge NSString *) ref; | |
// long len = CFStringGetLength(ref); | |
// char str[len]; | |
// CFStringGetCString(ref, str, len, ) | |
if ([manufacturer containsString:@"ustmaster"]) { | |
HandleDevice(device); | |
} | |
} | |
static void HandleInputValueCallback(void * inContext, IOReturn inResult, void* inSender, IOHIDValueRef value) | |
{ | |
IOHIDElementRef element = IOHIDValueGetElement(value); | |
IOHIDDeviceRef device = IOHIDElementGetDevice(element); | |
NSString *deviceName = (__bridge NSString *)(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey))); | |
NSString *name = (__bridge NSString *)(IOHIDElementGetName(element)); | |
IOHIDElementCookie cookie = IOHIDElementGetCookie(element); | |
uint32_t usagePage = IOHIDElementGetUsagePage(element); | |
uint32_t usage = IOHIDElementGetUsage(element); | |
int axisIndex = AxisIndex(usagePage, usage); | |
if (axisIndex >= 0) { | |
long intValue = IOHIDValueGetIntegerValue(value); | |
NSLog(@">> (%d) %@.%@%u -> %ld", axisIndex, deviceName, name, cookie, intValue); | |
{ | |
CFIndex intValue = IOHIDValueGetIntegerValue(value); | |
CFIndex min = IOHIDElementGetLogicalMin(element); | |
CFIndex max = IOHIDElementGetLogicalMax(element); | |
float axisValue = (float)(intValue - min) / (float)(max + 1 - min); | |
// Note: this is designed so gammaIndex == intValue if min == 0 and max == kJoystickGammaTableSize - 1 (the common case). | |
unsigned gammaIndex = floor(axisValue * kJoystickGammaTableSize); | |
NSLog(@"value=%f -> %d", axisValue, gammaIndex); | |
// evt.value = gammaTable[gammaIndex]; | |
} | |
// { | |
// CFTypeRef o = IOHIDDeviceGetProperty( | |
// device, CFSTR(kIOHIDDeviceUsagePairsKey)); | |
// printf("\tkIOHIDDeviceUsagePairsKey = %p\n", o); | |
// CFShow(o); | |
// // uint32_t usagePage = (IOHIDDeviceGetProperty(device, CFSTR(kIOHIDDeviceUsagePageKey))); | |
// // if (usagePage == kHIDPage_GenericDesktop) { | |
// // NSLog(@"GEneric desktop!"); | |
// // } else { | |
// // NSLog(@"GEneric desktop? %d", usagePage); | |
// // } | |
// } | |
} | |
} | |
static int AxisIndex(uint32_t page, uint32_t usage) | |
{ | |
/* | |
Map axis-like HID usages to SDL-like axis indices. These are all the | |
commonly used joystick axes according to Microsoft's DirectInput | |
documentation (hey, you've got to get your info somewhere). | |
GD_Slider, GD_Dial, DG_Wheel and Sim_Throttle are actually distinct; | |
unlike the others, they're uncentered. (By implication, | |
IOHIDElementHasPreferredState() should be false.) This should, in | |
particular, be considered when mapping to the throttle: centered axes | |
should provide relative input (for gamepads), while uncentered ones | |
should provide absolute input. Since that festering pool of pus, SDL, | |
can't make this distinction, OOJoystickManager can't either (yet). | |
-- Ahruman 2011-01-04 | |
*/ | |
switch (page) | |
{ | |
case kHIDPage_GenericDesktop: | |
switch (usage) | |
{ | |
case kHIDUsage_GD_X: return 0; | |
case kHIDUsage_GD_Y: return 1; | |
case kHIDUsage_GD_Z: return 2; | |
case kHIDUsage_GD_Rx: return 3; | |
case kHIDUsage_GD_Ry: return 4; | |
case kHIDUsage_GD_Rz: return 5; | |
case kHIDUsage_GD_Slider: return 6; | |
case kHIDUsage_GD_Dial: return 7; | |
case kHIDUsage_GD_Wheel: return 8; | |
} | |
break; | |
case kHIDPage_Simulation: | |
switch (usage) | |
{ | |
case kHIDUsage_Sim_Throttle: | |
return 9; | |
} | |
} | |
// Negative numbers indicate non-axis. | |
return -1; | |
} | |
static void HandleDeviceRemovalCallback(void * inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef) | |
{ | |
NSLog(@"Removed"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment