Пример #1
0
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); i < joysticksCount; ++i)
    {
        IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
        if (deviceLoc == HIDInputManager::getLocationID(d))
        {
            self = d;
            break; // We found it so we stop looping.
        }
    }

    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);

    // Get a list of all elements attached to the device.
    CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self, NULL, kIOHIDOptionsTypeNone);

    if (elements == NULL)
    {
        CFRelease(devices);
        return false;
    }

    // How many elements are there?
    CFIndex elementsCount = CFArrayGetCount(elements);

    if (elementsCount == 0)
    {
        // What is a joystick with no element?
        CFRelease(elements);
        CFRelease(devices);
        return false;
    }

    // Go through all connected elements.
    for (int i = 0; i < elementsCount; ++i)
    {
        IOHIDElementRef element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i);
        switch (IOHIDElementGetType(element))
        {
            case kIOHIDElementTypeInput_Misc:
                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;
                    // kHIDUsage_GD_Vx, kHIDUsage_GD_Vy, kHIDUsage_GD_Vz are ignored.
                }
                break;

            case kIOHIDElementTypeInput_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: // Make compiler happy
                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);

    // Note: Joy::AxisPovX/Y are not supported (yet).
    // Maybe kIOHIDElementTypeInput_Axis is the corresponding type but I can't test.

    // 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. So to prevent
    // leaking we retain objects 'only' now.

    CFRelease(devices);
    CFRelease(elements);

    return true;
}
Пример #2
0
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;
}