static CFIndex find_top_level(IOHIDDeviceRef tIOHIDDeviceRef, CFArrayRef topLevels) { CFArrayRef gElementCFArrayRef; CFIndex numTops = 0; if (!tIOHIDDeviceRef) return 0; gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0); if (gElementCFArrayRef) { CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); for (idx=0; idx<cnt; idx++) { IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gElementCFArrayRef, idx); int eleType = IOHIDElementGetType(tIOHIDElementRef); /* Check for top-level gaming device collections */ if (eleType == kIOHIDElementTypeCollection && IOHIDElementGetParent(tIOHIDElementRef) == 0) { int tUsagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); int tUsage = IOHIDElementGetUsage(tIOHIDElementRef); if (tUsagePage == kHIDPage_GenericDesktop && (tUsage == kHIDUsage_GD_Joystick || tUsage == kHIDUsage_GD_GamePad)) { CFArrayAppendValue((CFMutableArrayRef)topLevels, tIOHIDElementRef); numTops++; } } } } return numTops; }
/************************************************************************** * find_top_level */ static CFIndex find_top_level(IOHIDDeviceRef hid_device, CFMutableArrayRef main_elements) { CFArrayRef elements; CFIndex total = 0; TRACE("hid_device %s\n", debugstr_device(hid_device)); if (!hid_device) return 0; elements = IOHIDDeviceCopyMatchingElements(hid_device, NULL, 0); if (elements) { CFIndex i, count = CFArrayGetCount(elements); for (i = 0; i < count; i++) { IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); int type = IOHIDElementGetType(element); TRACE("element %s\n", debugstr_element(element)); /* Check for top-level gaming device collections */ if (type == kIOHIDElementTypeCollection && IOHIDElementGetParent(element) == 0) { int usage_page = IOHIDElementGetUsagePage(element); int usage = IOHIDElementGetUsage(element); if (usage_page == kHIDPage_GenericDesktop && (usage == kHIDUsage_GD_Joystick || usage == kHIDUsage_GD_GamePad)) { CFArrayAppendValue(main_elements, element); total++; } } } CFRelease(elements); } TRACE("-> total %d\n", (int)total); return total; }
// utility routine to dump element info void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef) { if (inIOHIDElementRef) { printf(" Element: %p = { ", inIOHIDElementRef); #if false IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice(inIOHIDElementRef); printf("Device: %p, ", tIOHIDDeviceRef); #endif // if 0 IOHIDElementRef parentIOHIDElementRef = IOHIDElementGetParent(inIOHIDElementRef); printf("parent: %p, ", parentIOHIDElementRef); #if false CFArrayRef childrenCFArrayRef = IOHIDElementGetChildren(inIOHIDElementRef); printf("children: %p: { ", childrenCFArrayRef); fflush(stdout); CFShow(childrenCFArrayRef); fflush(stdout); printf(" }, "); #endif // if 0 IOHIDElementCookie tIOHIDElementCookie = IOHIDElementGetCookie(inIOHIDElementRef); printf("cookie: 0x%08lX, ", (long unsigned int) tIOHIDElementCookie); IOHIDElementType tIOHIDElementType = IOHIDElementGetType(inIOHIDElementRef); switch (tIOHIDElementType) { case kIOHIDElementTypeInput_Misc: { printf("type: Misc, "); break; } case kIOHIDElementTypeInput_Button: { printf("type: Button, "); break; } case kIOHIDElementTypeInput_Axis: { printf("type: Axis, "); break; } case kIOHIDElementTypeInput_ScanCodes: { printf("type: ScanCodes, "); break; } case kIOHIDElementTypeOutput: { printf("type: Output, "); break; } case kIOHIDElementTypeFeature: { printf("type: Feature, "); break; } case kIOHIDElementTypeCollection: { IOHIDElementCollectionType tIOHIDElementCollectionType = IOHIDElementGetCollectionType(inIOHIDElementRef); switch (tIOHIDElementCollectionType) { case kIOHIDElementCollectionTypePhysical: { printf("type: Physical Collection, "); break; } case kIOHIDElementCollectionTypeApplication: { printf("type: Application Collection, "); break; } case kIOHIDElementCollectionTypeLogical: { printf("type: Logical Collection, "); break; } case kIOHIDElementCollectionTypeReport: { printf("type: Report Collection, "); break; } case kIOHIDElementCollectionTypeNamedArray: { printf("type: Named Array Collection, "); break; } case kIOHIDElementCollectionTypeUsageSwitch: { printf("type: Usage Switch Collection, "); break; } case kIOHIDElementCollectionTypeUsageModifier: { printf("type: Usage Modifier Collection, "); break; } default: { printf("type: %p Collection, ", (void *) tIOHIDElementCollectionType); break; } } // switch break; } default: { printf("type: %p, ", (void *) tIOHIDElementType); break; } } /* switch */ uint32_t usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); uint32_t usage = IOHIDElementGetUsage(inIOHIDElementRef); printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage); CFStringRef tCFStringRef = HIDCopyUsageName(usagePage, usage); if (tCFStringRef) { char usageString[256] = ""; (void) CFStringGetCString(tCFStringRef, usageString, sizeof(usageString), kCFStringEncodingUTF8); printf("\"%s\", ", usageString); CFRelease(tCFStringRef); } CFStringRef nameCFStringRef = IOHIDElementGetName(inIOHIDElementRef); char buffer[256]; if ( nameCFStringRef && CFStringGetCString(nameCFStringRef, buffer, sizeof(buffer), kCFStringEncodingUTF8) ) { printf("name: %s, ", buffer); } uint32_t reportID = IOHIDElementGetReportID(inIOHIDElementRef); uint32_t reportSize = IOHIDElementGetReportSize(inIOHIDElementRef); uint32_t reportCount = IOHIDElementGetReportCount(inIOHIDElementRef); printf("report: { ID: %lu, Size: %lu, Count: %lu }, ", (long unsigned int) reportID, (long unsigned int) reportSize, (long unsigned int) reportCount); uint32_t unit = IOHIDElementGetUnit(inIOHIDElementRef); uint32_t unitExp = IOHIDElementGetUnitExponent(inIOHIDElementRef); if (unit || unitExp) { printf("unit: %lu * 10^%lu, ", (long unsigned int) unit, (long unsigned int) unitExp); } CFIndex logicalMin = IOHIDElementGetLogicalMin(inIOHIDElementRef); CFIndex logicalMax = IOHIDElementGetLogicalMax(inIOHIDElementRef); if (logicalMin != logicalMax) { printf("logical: {min: %ld, max: %ld}, ", logicalMin, logicalMax); } CFIndex physicalMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef); CFIndex physicalMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef); if (physicalMin != physicalMax) { printf("physical: {min: %ld, max: %ld}, ", physicalMin, physicalMax); } Boolean isVirtual = IOHIDElementIsVirtual(inIOHIDElementRef); if (isVirtual) { printf("isVirtual, "); } Boolean isRelative = IOHIDElementIsRelative(inIOHIDElementRef); if (isRelative) { printf("isRelative, "); } Boolean isWrapping = IOHIDElementIsWrapping(inIOHIDElementRef); if (isWrapping) { printf("isWrapping, "); } Boolean isArray = IOHIDElementIsArray(inIOHIDElementRef); if (isArray) { printf("isArray, "); } Boolean isNonLinear = IOHIDElementIsNonLinear(inIOHIDElementRef); if (isNonLinear) { printf("isNonLinear, "); } Boolean hasPreferredState = IOHIDElementHasPreferredState(inIOHIDElementRef); if (hasPreferredState) { printf("hasPreferredState, "); } Boolean hasNullState = IOHIDElementHasNullState(inIOHIDElementRef); if (hasNullState) { printf("hasNullState, "); } printf(" }\n"); } } // HIDDumpElementInfo