Could you add to the switch something like this:
switch (IOHIDElementGetType(element)) {
case kIOHIDElementTypeInput_Axis:
sf::err() << "Found something interesting: 0x" << std::hex << IOHIDElementGetUsage(element) << std::dec << std::endl;
break;
You'll need to include <ios> too.
Then, compile SFML, install it and for each joystick you have, plug it in (only one at a time) and run one of your program. Maybe there are some axis reported in this category...
Appendix A is a list of examples, giving a wide idea of the structure of such device, so why not.
I've managed to dig a bit into it. Could you try this code (replace the corresponding function) and post the outputs. Try running your SFML application several time with a different position for the missing axis to get a good idea of the possible recorded values.
bool JoystickImpl::open(unsigned int index)
{
m_index = index;
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)
{
// This shouldn't happen!
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);
sf::err()
<< "Name: " << m_identification.name.toAnsiString()
<< ", Vendor ID: 0x" << std::hex << m_identification.vendorId
<< ", Product ID: 0x" << m_identification.productId
<< std::dec << std::endl;
// 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: {
sf::err() << "hat?" << std::endl;
sf::err()
<< std::boolalpha
<< "Null State? " << (bool)IOHIDElementHasNullState(element) << "\n"
<< "Preferred State? " << (bool)IOHIDElementHasPreferredState(element) << "\n"
<< "Is Linear? " << !(bool)IOHIDElementIsNonLinear(element) << "\n"
<< "Is Wrapping? " << (bool)IOHIDElementIsWrapping(element) << "\n"
<< "Is Relative? " << (bool)IOHIDElementIsRelative(element) << "\n"
<< "Is Array? " << (bool)IOHIDElementIsArray(element) << "\n"
<< "Is Virtual? " << (bool)IOHIDElementIsVirtual(element) << "\n"
<< "Collection Type: " << IOHIDElementGetCollectionType(element) << " (based on IOHIDElementCollectionType)\n"
<< "Logical Range: [" << IOHIDElementGetLogicalMin(element) << ", " << IOHIDElementGetLogicalMax(element) << "]\n"
<< "Physical Range: [" << IOHIDElementGetPhysicalMin(element) << ", " << IOHIDElementGetPhysicalMax(element) << "]\n";
IOHIDValueRef value = 0;
IOHIDDeviceGetValue(IOHIDElementGetDevice(element), element, &value);
if (value) {
double x = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
CFIndex y = IOHIDValueGetIntegerValue(value);
sf::err() << "Value: " << x << "/" << x << std::endl;
sf::err() << "Raw value: size -> " << IOHIDValueGetLength(value) << " data -> " << (int)*(IOHIDValueGetBytePtr(value)) << std::endl;
} else {
sf::err() << "No Value." << std::endl;
}
break;
}
default:
sf::err() << "Unexpected usage for element of Page Generic Desktop: 0x" << std::hex << IOHIDElementGetUsage(element) << std::dec << std::endl;
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);
// 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;
}