// 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
bool JoystickImpl::open(unsigned int index) { m_index = index; m_hat = NULL; Location deviceLoc = m_locationIDs[index]; // The device we need to load // Get all devices CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks(); if (devices == NULL) return false; // Get a usable copy of the joysticks devices. CFIndex joysticksCount = CFSetGetCount(devices); CFTypeRef devicesArray[joysticksCount]; CFSetGetValues(devices, devicesArray); // Get the desired joystick. IOHIDDeviceRef self = 0; for (CFIndex i(0); self == 0 && i < joysticksCount; ++i) { IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i]; if (deviceLoc == HIDInputManager::getLocationID(d)) self = d; } if (self == 0) { CFRelease(devices); return false; } m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey), m_index); m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey), m_index); m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey), m_index); // Get a list of all elements attached to the device. CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self, NULL, kIOHIDOptionsTypeNone); if (elements == NULL) { CFRelease(devices); return false; } // Go through all connected elements. CFIndex elementsCount = CFArrayGetCount(elements); for (int i = 0; i < elementsCount; ++i) { IOHIDElementRef element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i); switch (IOHIDElementGetUsagePage(element)) { case kHIDPage_GenericDesktop: switch (IOHIDElementGetUsage(element)) { case kHIDUsage_GD_X: m_axis[Joystick::X] = element; break; case kHIDUsage_GD_Y: m_axis[Joystick::Y] = element; break; case kHIDUsage_GD_Z: m_axis[Joystick::Z] = element; break; case kHIDUsage_GD_Rx: m_axis[Joystick::U] = element; break; case kHIDUsage_GD_Ry: m_axis[Joystick::V] = element; break; case kHIDUsage_GD_Rz: m_axis[Joystick::R] = element; break; case kHIDUsage_GD_Hatswitch: // From §4.3 MiscellaneousControls of HUT v1.12: // // > Hat Switch: // > A typical example is four switches that are capable of generating // > information about four possible directions in which the knob can be // > tilted. Intermediate positions can also be decoded if the hardware // > allows two switches to be reported simultaneously. // // We assume this model here as well. Hence, with 4 switches and intermediate // positions we have 8 values (0-7) plus the "null" state (8). { CFIndex min = IOHIDElementGetLogicalMin(element); CFIndex max = IOHIDElementGetLogicalMax(element); if (min != 0 || max != 7) { sf::err() << std::hex << "Joystick (vendor/product id: 0x" << m_identification.vendorId << "/0x" << m_identification.productId << std::dec << ") range is an unexpected one: [" << min << ", " << max << "]" << std::endl; } else { m_hat = element; } } break; case kHIDUsage_GD_GamePad: // We assume a game pad is an application collection, meaning it doesn't hold // any values per say. They kind of "emit" the joystick's usages. // See §3.4.3 Usage Types (Collection) of HUT v1.12 if (IOHIDElementGetCollectionType(element) != kIOHIDElementCollectionTypeApplication) { sf::err() << std::hex << "Gamepage (vendor/product id: 0x" << m_identification.vendorId << "/0x" << m_identification.productId << ") is not an CA but a 0x" << IOHIDElementGetCollectionType(element) << std::dec << std::endl; } break; default: #ifdef SFML_DEBUG sf::err() << "Unexpected usage for element of Page Generic Desktop: 0x" << std::hex << IOHIDElementGetUsage(element) << std::dec << std::endl; #endif break; } break; case kHIDPage_Button: if (m_buttons.size() < Joystick::ButtonCount) // If we have free slot... m_buttons.push_back(element); // ...we add this element to the list // Else: too many buttons. We ignore this one. break; default: /* No other page is expected because of the mask applied by the HID manager. */ break; } } // Ensure that the buttons will be indexed in the same order as their // HID Usage (assigned by manufacturer and/or a driver). std::sort(m_buttons.begin(), m_buttons.end(), JoystickButtonSortPredicate); // Retain all these objects for personal use for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it) CFRetain(*it); for (AxisMap::iterator it(m_axis.begin()); it != m_axis.end(); ++it) CFRetain(it->second); if (m_hat != NULL) CFRetain(m_hat); // Note: we didn't retain element in the switch because we might have multiple // Axis X (for example) and we want to keep only the last one. To prevent // leaking we retain objects 'only' now. CFRelease(devices); CFRelease(elements); return true; }