Exemple #1
0
bool HIDGamepad::maybeAddButton(IOHIDElementRef element)
{
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    if (usagePage != kHIDPage_Button && usagePage != kHIDPage_GenericDesktop)
        return false;

    uint32_t usage = IOHIDElementGetUsage(element);

    if (usagePage == kHIDPage_GenericDesktop) {
        if (usage < kHIDUsage_GD_DPadUp || usage > kHIDUsage_GD_DPadLeft)
            return false;
        usage = std::numeric_limits<uint32_t>::max();
    } else if (!usage)
        return false;

    CFIndex min = IOHIDElementGetLogicalMin(element);
    CFIndex max = IOHIDElementGetLogicalMax(element);

    m_buttons.append(makeUniqueRef<HIDGamepadButton>(usage, min, max, element));

    IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
    m_elementMap.set(cookie, &m_buttons.last().get());

    return true;
}
    void analog_event(IOReturn result, IOHIDElementRef element, IOHIDValueRef value) {
        int int_value = IOHIDValueGetIntegerValue(value);
        uint16_t usage = IOHIDElementGetUsage(element);
        switch (usage) {
          case kHIDUsage_GD_X:
          case kHIDUsage_GD_Y:
          case kHIDUsage_GD_Rx:
          case kHIDUsage_GD_Ry:
            {
                int min = IOHIDElementGetLogicalMin(element);
                int max = IOHIDElementGetLogicalMax(element);
                double double_value = int_value;
                if (int_value < 0) {
                    double_value = -(double_value / min);
                } else {
                    double_value = (double_value / max);
                }

                usage -= kHIDUsage_GD_X;
                gamepad[usage] = double_value;
                static const int x_component[] = {0, 0, -1, 3, 3, -1};
                double x = gamepad[x_component[usage]];
                double y = gamepad[x_component[usage] + 1];
                enqueue(new GamepadStickEvent(
                            now_usecs(), kHIDUsage_GD_X + x_component[usage], x, y));
            }
            break;
          case kHIDUsage_GD_Z:
          case kHIDUsage_GD_Rz:
            button_event(result, element, value);
            break;
        }
    }
Exemple #3
0
// *************************************************************************
//
// IOHIDElement_SetupCalibration(inIOHIDElementRef)
//
// Purpose:	set default values for the element calibration parameters
//
// Inputs:  inIOHIDElementRef	- the IOHIDElementRef for this element
//
// Returns:	nothing
//
void IOHIDElement_SetupCalibration(IOHIDElementRef inIOHIDElementRef) {
	// these are the min/max values returned by IOHIDValueGetScaledValue(v, kIOHIDValueScaleTypeCalibrated);
	IOHIDElement_SetCalibrationMin(inIOHIDElementRef, IOHIDElementGetLogicalMin(inIOHIDElementRef));
	IOHIDElement_SetCalibrationMax(inIOHIDElementRef, IOHIDElementGetLogicalMax(inIOHIDElementRef));
    
	CFIndex phyMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef);
	CFIndex phyMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef);
	CFIndex phyRange = phyMax - phyMin;
    // calculate the middle physical value we would expect from this element
	double phyMid = (phyMin + phyMax) / 2.f;
    
	// this is the granularity of the values returned by IOHIDValueGetScaledValue(v, kIOHIDValueScaleTypeCalibrated);
	// for example if set to 0.1 the values returned will be multiples of 0.1 (0.1, 0.2, 0.3, etc.)
	IOHIDElement_SetCalibrationGranularity(inIOHIDElementRef, 0.);
    
	Boolean isRelative = IOHIDElementIsRelative(inIOHIDElementRef);
	Boolean hasPreferredState = IOHIDElementHasPreferredState(inIOHIDElementRef);
	// define the dead zone (like in the middle of joystick axis)
	if (!isRelative && hasPreferredState && (phyRange > 3)) {
		IOHIDElement_SetCalibrationDeadZoneMin(inIOHIDElementRef, phyMid - 1.0);
		IOHIDElement_SetCalibrationDeadZoneMax(inIOHIDElementRef, phyMid + 1.0);
	} else {
		IOHIDElement_SetCalibrationDeadZoneMin(inIOHIDElementRef, 0.);
		IOHIDElement_SetCalibrationDeadZoneMax(inIOHIDElementRef, 0.);
	}
    
	// get the current value of this element
	double phyValue = IOHIDElement_GetValue(inIOHIDElementRef, kIOHIDValueScaleTypePhysical);
    
#if true
	// use that that value to determine the min/max saturation values used for calibration
	IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, phyValue);
	IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, phyValue);
#else // if 1
#if true
	// this value determines the min/max values that have been recieved from the device element
	IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, (phyMin + phyMid) / 2.f);
	IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, (phyMid + phyMax) / 2.f);
#else // if 1
    // use it as our min/max saturation
    // this value determines the min/max values that have been recieved from the device element
	IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, phyMid);
	IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, phyMid);
#endif // if 1
    // and the current value to adjust the current saturation values if it's outside their range
	if (phyValue < IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef)) {
		IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, phyValue);
	}
	if (phyValue > IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef)) {
		IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, phyValue);
	}
    
#endif // if 1
}   // IOHIDElement_SetupCalibration
float GamepadManager::mapAnalogAxis(IOHIDValueRef value, IOHIDElementRef element)
{
    
    CFIndex val = IOHIDValueGetIntegerValue(value);
    CFIndex min = IOHIDElementGetLogicalMin(element);
    CFIndex max = IOHIDElementGetLogicalMax(element);
    
    float v = (float) (val - min) / (float) (max - min);
    v = v * 2.0f - 1.0f;
    
    // Dead zone.
    if (v < 0.1f && v > -0.1f)
    {
        v = 0.0f;
    }
    
    return v;
}
Exemple #5
0
//*************************************************************************
//
// IOHIDElement_SetupCalibration( inElementRef )
//
// Purpose:	set default values for the element calibration parameters
//
// Inputs:  inElementRef	- the IOHIDElementRef for this element
//
// Returns:	nothing
//
void IOHIDElement_SetupCalibration( IOHIDElementRef inIOHIDElementRef )
{
	// these are the min/max values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated );
	IOHIDElement_SetCalibrationMin( inIOHIDElementRef, IOHIDElementGetLogicalMin( inIOHIDElementRef ) );
	IOHIDElement_SetCalibrationMax( inIOHIDElementRef, IOHIDElementGetLogicalMax( inIOHIDElementRef ) );

	// this is the granularity of the values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated );
	// for example if set to 0.1 the values returned will be multiples of 0.1 ( 0.1, 0.2, 0.3, etc. )
	IOHIDElement_SetCalibrationGranularity( inIOHIDElementRef, 0. );
	
	// these define the dead zone (like in the middel of joystick axis)
	IOHIDElement_SetCalibrationDeadZoneMin( inIOHIDElementRef, 0 );
	IOHIDElement_SetCalibrationDeadZoneMax( inIOHIDElementRef, 0 );
#if 1
	// get the current value of this element
	double value = IOHIDElement_GetValue( inIOHIDElementRef, kIOHIDValueScaleTypePhysical );
	// use it as our min/mas saturation
	IOHIDElement_SetCalibrationSaturationMin( inIOHIDElementRef, value );
	IOHIDElement_SetCalibrationSaturationMax( inIOHIDElementRef, value );
#else
	// calculate the middle physical value we would expect from this element
	CFIndex valueMin = IOHIDElementGetPhysicalMin( inIOHIDElementRef );
	CFIndex valueMax = IOHIDElementGetPhysicalMax( inIOHIDElementRef );
	CFIndex valueMid = ( valueMin + valueMax ) / 2;
	
	// use it as our min/mas saturation
	// this value determines the min/max values that have been recieved from the device element
	IOHIDElement_SetCalibrationSaturationMin( inIOHIDElementRef, valueMid );
	IOHIDElement_SetCalibrationSaturationMax( inIOHIDElementRef, valueMid );
	
	// get the current value of this element
	double value = IOHIDElement_GetValue( inIOHIDElementRef, kIOHIDValueScaleTypePhysical );
	
	// and use it to adjust the current saturation values if it's outside their range
	if ( value < IOHIDElement_GetCalibrationSaturationMin( inIOHIDElementRef ) ) {
		IOHIDElement_SetCalibrationSaturationMin( inIOHIDElementRef, value );
	}
	
	if ( value > IOHIDElement_GetCalibrationSaturationMax( inIOHIDElementRef ) ) {
		IOHIDElement_SetCalibrationSaturationMax( inIOHIDElementRef, value );
	}
#endif
}	// IOHIDElement_SetupCalibration
Exemple #6
0
bool HIDGamepad::maybeAddDPad(IOHIDElementRef element)
{
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    if (usagePage != kHIDPage_GenericDesktop)
        return false;

    uint32_t usage = IOHIDElementGetUsage(element);
    if (!usage || usage != kHIDUsage_GD_Hatswitch)
        return false;

    CFIndex min = IOHIDElementGetLogicalMin(element);
    CFIndex max = IOHIDElementGetLogicalMax(element);

    m_dPads.append(makeUniqueRef<HIDGamepadDPad>(min, max, element));

    IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
    m_elementMap.set(cookie, &m_dPads.last().get());

    return true;
}
Exemple #7
0
bool HIDGamepad::maybeAddButton(IOHIDElementRef element)
{
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    if (usagePage != kHIDPage_Button)
        return false;

    uint32_t usage = IOHIDElementGetUsage(element);
    if (!usage)
        return false;

    CFIndex min = IOHIDElementGetLogicalMin(element);
    CFIndex max = IOHIDElementGetLogicalMax(element);

    m_buttons.append(std::make_unique<HIDGamepadButton>(usage, min, max, element));

    IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
    m_elementMap.set(cookie, m_buttons.last().get());

    return true;
}
Exemple #8
0
static void get_osx_device_elements_props(JoystickImpl *device)
{
    CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;

    if (gElementCFArrayRef)
    {
        CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );

        for ( idx = 0; idx < cnt; idx++ )
        {
            IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );

            device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
            device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
            device->generic.props[idx].lMin =  0;
            device->generic.props[idx].lMax =  0xffff;
            device->generic.props[idx].lDeadZone = 0;
            device->generic.props[idx].lSaturation = 0;
        }
    }
}
Exemple #9
0
/* See if we care about this HID element, and if so, note it in our recDevice. */
static void
AddHIDElement(const void *value, void *parameter)
{
    recDevice *pDevice = (recDevice *) parameter;
    IOHIDElementRef refElement = (IOHIDElementRef) value;
    const CFTypeID elementTypeID = refElement ? CFGetTypeID(refElement) : 0;

    if (refElement && (elementTypeID == IOHIDElementGetTypeID())) {
        const IOHIDElementCookie cookie = IOHIDElementGetCookie(refElement);
        const uint32_t usagePage = IOHIDElementGetUsagePage(refElement);
        const uint32_t usage = IOHIDElementGetUsage(refElement);
        recElement *element = NULL;
        recElement **headElement = NULL;

        /* look at types of interest */
        switch (IOHIDElementGetType(refElement)) {
            case kIOHIDElementTypeInput_Misc:
            case kIOHIDElementTypeInput_Button:
            case kIOHIDElementTypeInput_Axis: {
                switch (usagePage) {    /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */
                    case kHIDPage_GenericDesktop:
                        switch (usage) {
                            case kHIDUsage_GD_X:
                            case kHIDUsage_GD_Y:
                            case kHIDUsage_GD_Z:
                            case kHIDUsage_GD_Rx:
                            case kHIDUsage_GD_Ry:
                            case kHIDUsage_GD_Rz:
                            case kHIDUsage_GD_Slider:
                            case kHIDUsage_GD_Dial:
                            case kHIDUsage_GD_Wheel:
                                if (!ElementAlreadyAdded(cookie, pDevice->firstAxis)) {
                                    element = (recElement *) SDL_calloc(1, sizeof (recElement));
                                    if (element) {
                                        pDevice->axes++;
                                        headElement = &(pDevice->firstAxis);
                                    }
                                }
                                break;

                            case kHIDUsage_GD_Hatswitch:
                                if (!ElementAlreadyAdded(cookie, pDevice->firstHat)) {
                                    element = (recElement *) SDL_calloc(1, sizeof (recElement));
                                    if (element) {
                                        pDevice->hats++;
                                        headElement = &(pDevice->firstHat);
                                    }
                                }
                                break;
                        }
                        break;

                    case kHIDPage_Simulation:
                        switch (usage) {
                            case kHIDUsage_Sim_Rudder:
                            case kHIDUsage_Sim_Throttle:
                                if (!ElementAlreadyAdded(cookie, pDevice->firstAxis)) {
                                    element = (recElement *) SDL_calloc(1, sizeof (recElement));
                                    if (element) {
                                        pDevice->axes++;
                                        headElement = &(pDevice->firstAxis);
                                    }
                                }
                                break;

                            default:
                                break;
                        }
                        break;

                    case kHIDPage_Button:
                        if (!ElementAlreadyAdded(cookie, pDevice->firstButton)) {
                            element = (recElement *) SDL_calloc(1, sizeof (recElement));
                            if (element) {
                                pDevice->buttons++;
                                headElement = &(pDevice->firstButton);
                            }
                        }
                        break;

                    default:
                        break;
                }
            }
            break;

            case kIOHIDElementTypeCollection: {
                CFArrayRef array = IOHIDElementGetChildren(refElement);
                if (array) {
                    AddHIDElements(array, pDevice);
                }
            }
            break;

            default:
                break;
        }

        if (element && headElement) {       /* add to list */
            recElement *elementPrevious = NULL;
            recElement *elementCurrent = *headElement;
            while (elementCurrent && usage >= elementCurrent->usage) {
                elementPrevious = elementCurrent;
                elementCurrent = elementCurrent->pNext;
            }
            if (elementPrevious) {
                elementPrevious->pNext = element;
            } else {
                *headElement = element;
            }

            element->elementRef = refElement;
            element->usagePage = usagePage;
            element->usage = usage;
            element->pNext = elementCurrent;

            element->minReport = element->min = (SInt32) IOHIDElementGetLogicalMin(refElement);
            element->maxReport = element->max = (SInt32) IOHIDElementGetLogicalMax(refElement);
            element->cookie = IOHIDElementGetCookie(refElement);

            pDevice->elements++;
        }
    }
}
/**************************************************************************
 *                              collect_joystick_elements
 */
static void collect_joystick_elements(joystick_t* joystick, IOHIDElementRef collection)
{
    CFIndex    i, count;
    CFArrayRef children = IOHIDElementGetChildren(collection);

    TRACE("collection %s\n", debugstr_element(collection));

    count = CFArrayGetCount(children);
    for (i = 0; i < count; i++)
    {
        IOHIDElementRef child;
        int type;

        child = (IOHIDElementRef)CFArrayGetValueAtIndex(children, i);
        TRACE("child %s\n", debugstr_element(child));
        type = IOHIDElementGetType(child);
        switch (type)
        {
            case kIOHIDElementTypeCollection:
                collect_joystick_elements(joystick, child);
                break;
            case kIOHIDElementTypeInput_Button:
            {
                int usage_page = IOHIDElementGetUsagePage(child);

                TRACE("kIOHIDElementTypeInput_Button usage_page %d\n", usage_page);

                /* avoid strange elements found on the 360 controller */
                if (usage_page == kHIDPage_Button)
                    CFArrayAppendValue(joystick->buttons, child);
                break;
            }
            case kIOHIDElementTypeInput_Axis:
            {
                TRACE("kIOHIDElementTypeInput_Axis; ignoring\n");
                break;
            }
            case kIOHIDElementTypeInput_Misc:
            {
                uint32_t usage = IOHIDElementGetUsage( child );
                switch(usage)
                {
                    case kHIDUsage_GD_Hatswitch:
                    {
                        TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Hatswitch\n");
                        if (joystick->hatswitch)
                            TRACE("    ignoring additional hatswitch\n");
                        else
                            joystick->hatswitch = (IOHIDElementRef)CFRetain(child);
                        break;
                    }
                    case kHIDUsage_GD_X:
                    case kHIDUsage_GD_Y:
                    case kHIDUsage_GD_Z:
                    case kHIDUsage_GD_Rx:
                    case kHIDUsage_GD_Ry:
                    case kHIDUsage_GD_Rz:
                    {
                        int axis = axis_for_usage(usage);
                        TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_<axis> (%d) axis %d\n", usage, axis);
                        if (axis < 0 || joystick->axes[axis].element)
                            TRACE("    ignoring\n");
                        else
                        {
                            joystick->axes[axis].element = (IOHIDElementRef)CFRetain(child);
                            joystick->axes[axis].min_value = IOHIDElementGetLogicalMin(child);
                            joystick->axes[axis].max_value = IOHIDElementGetLogicalMax(child);
                        }
                        break;
                    }
                    case kHIDUsage_GD_Slider:
                        TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Slider; ignoring\n");
                        break;
                    default:
                        FIXME("kIOHIDElementTypeInput_Misc / Unhandled usage %d\n", usage);
                        break;
                }
                break;
            }
            default:
                FIXME("Unhandled type %i\n",type);
                break;
        }
    }
}
Exemple #11
0
bool Joystick::init()
{
  SYNC;
  if(!p->hidManager)
  {
    VERIFY(p->hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone));
    IOHIDManagerSetDeviceMatching((IOHIDManagerRef) p->hidManager, 0);
    IOHIDManagerOpen((IOHIDManagerRef) p->hidManager, kIOHIDOptionsTypeNone);
    p->nextDevice = 0;
  }

  CFSetRef copyOfDevices = IOHIDManagerCopyDevices((IOHIDManagerRef) p->hidManager);
  CFMutableArrayRef devArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
  CFSetApplyFunction(copyOfDevices, Joystick::Private::copyCallBack, (void*) devArray);
  CFRelease(copyOfDevices);

  while(!p->deviceId && p->nextDevice < (unsigned) CFArrayGetCount(devArray))
  {
    p->deviceId = CFArrayGetValueAtIndex(devArray, p->nextDevice++);
    if(p->deviceId)
    {
      CFArrayRef elemAry = IOHIDDeviceCopyMatchingElements((IOHIDDeviceRef) p->deviceId, 0, 0);
      bool isJoystick = false;
      for(int i = 0; !isJoystick && i < (int) CFArrayGetCount(elemAry); ++i)
      {
        IOHIDElementRef elem = (IOHIDElementRef) CFArrayGetValueAtIndex(elemAry, i);
        isJoystick = IOHIDElementGetUsagePage(elem) == kHIDPage_GenericDesktop &&
                     (IOHIDElementGetUsage(elem) == kHIDUsage_GD_Joystick ||
                      IOHIDElementGetUsage(elem) == kHIDUsage_GD_GamePad);
      }
      if(isJoystick)
      {
        CFRetain((IOHIDDeviceRef) p->deviceId);
        ++(p->usedJoysticks);
        for(int i = 0; i < (int) CFArrayGetCount(elemAry); ++i)
        {
          IOHIDElementRef elem = (IOHIDElementRef) CFArrayGetValueAtIndex(elemAry, i);
          IOHIDElementType elemType = IOHIDElementGetType(elem);

          if(elemType == kIOHIDElementTypeInput_Misc ||
             elemType == kIOHIDElementTypeInput_Button ||
             elemType == kIOHIDElementTypeInput_Axis ||
             elemType == kIOHIDElementTypeInput_ScanCodes)
          {
            if(IOHIDElementGetUsagePage(elem) == kHIDPage_GenericDesktop)
              switch(IOHIDElementGetUsage(elem))
              {
                case kHIDUsage_GD_X:
                case kHIDUsage_GD_Y:
                case kHIDUsage_GD_Z:
                case kHIDUsage_GD_Rx:
                case kHIDUsage_GD_Ry:
                case kHIDUsage_GD_Rz:
                {
                  CFRetain(elem);
                  int axis = IOHIDElementGetUsage(elem) - kHIDUsage_GD_X;
                  p->axisIds[axis] = elem;
                  p->axisMin[axis] = (int) IOHIDElementGetLogicalMin(elem);
                  p->axisMax[axis] = (int) IOHIDElementGetLogicalMax(elem);
                  break;
                }
                case kHIDUsage_GD_Hatswitch:
                  CFRetain(elem);
                  p->hatId = elem;
                  p->axisMin[6] = p->axisMin[7] = -1;
                  p->axisMax[6] = p->axisMax[7] = 1;
                  break;
              }
            else if(IOHIDElementGetUsagePage(elem) == kHIDPage_Button)
            {
              int button = IOHIDElementGetUsage(elem) - 1;
              if(button >= 0 && button < numOfButtons)
              {
                CFRetain(elem);
                p->buttonIds[button] = elem;
              }
            }
          }
        }
      }
      else
        p->deviceId = 0;
      CFRelease(elemAry);
    }
  }

  CFRelease(devArray);

  return p->deviceId != 0;
}
static void onDeviceMatched(void * context, IOReturn result, void * sender, IOHIDDeviceRef device) {
  CFArrayRef elements;
  CFIndex elementIndex;
  IOHIDElementRef element;
  CFStringRef cfProductName;
  struct Gamepad_device * deviceRecord;
  struct Gamepad_devicePrivate * hidDeviceRecord;
  IOHIDElementType type;
  char * description;
  struct Gamepad_queuedEvent queuedEvent;
	
  deviceRecord = malloc(sizeof(struct Gamepad_device));
  deviceRecord->deviceID = nextDeviceID++;
  deviceRecord->vendorID = IOHIDDeviceGetVendorID(device);
  deviceRecord->productID = IOHIDDeviceGetProductID(device);
  deviceRecord->deviceMap = Gamepad_deviceMap(deviceRecord->vendorID, deviceRecord->productID);
  deviceRecord->numAxes = 0;
  deviceRecord->numButtons = 0;
  devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
  devices[numDevices++] = deviceRecord;
	
  hidDeviceRecord = malloc(sizeof(struct Gamepad_devicePrivate));
  hidDeviceRecord->deviceRef = device;
  hidDeviceRecord->axisElements = NULL;
  hidDeviceRecord->buttonElements = NULL;
  deviceRecord->privateData = hidDeviceRecord;
	
  cfProductName = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
  if (cfProductName == NULL || CFGetTypeID(cfProductName) != CFStringGetTypeID()) {
    description = malloc(strlen("[Unknown]" + 1));
    strcpy(description, "[Unknown]");
		
  } else {
    CFIndex length;
		
    CFStringGetBytes(cfProductName, CFRangeMake(0, CFStringGetLength(cfProductName)), kCFStringEncodingUTF8, '?', false, NULL, 100, &length);
    description = malloc(length + 1);
    CFStringGetBytes(cfProductName, CFRangeMake(0, CFStringGetLength(cfProductName)), kCFStringEncodingUTF8, '?', false, (UInt8 *) description, length + 1, NULL);
    description[length] = '\x00';
  }
  deviceRecord->description = description;
	
  elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
  for (elementIndex = 0; elementIndex < CFArrayGetCount(elements); elementIndex++) {
    element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, elementIndex);
    type = IOHIDElementGetType(element);
		
    // All of the axis elements I've ever detected have been kIOHIDElementTypeInput_Misc. kIOHIDElementTypeInput_Axis is only included for good faith...
    if (type == kIOHIDElementTypeInput_Misc ||
        type == kIOHIDElementTypeInput_Axis) {
			
      hidDeviceRecord->axisElements = realloc(hidDeviceRecord->axisElements, sizeof(struct HIDGamepadAxis) * (deviceRecord->numAxes + 1));
      hidDeviceRecord->axisElements[deviceRecord->numAxes].cookie = IOHIDElementGetCookie(element);
      hidDeviceRecord->axisElements[deviceRecord->numAxes].logicalMin = IOHIDElementGetLogicalMin(element);
      hidDeviceRecord->axisElements[deviceRecord->numAxes].logicalMax = IOHIDElementGetLogicalMax(element);
      hidDeviceRecord->axisElements[deviceRecord->numAxes].hasNullState = !!IOHIDElementHasNullState(element);
      hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitch = IOHIDElementGetUsage(element) == kHIDUsage_GD_Hatswitch;
      hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitchSecondAxis = false;
      deviceRecord->numAxes++;
			
      if (hidDeviceRecord->axisElements[deviceRecord->numAxes - 1].isHatSwitch) {
        hidDeviceRecord->axisElements = realloc(hidDeviceRecord->axisElements, sizeof(struct HIDGamepadAxis) * (deviceRecord->numAxes + 1));
        hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitchSecondAxis = true;
        deviceRecord->numAxes++;
      }
			
    } else if (type == kIOHIDElementTypeInput_Button) {
      hidDeviceRecord->buttonElements = realloc(hidDeviceRecord->buttonElements, sizeof(struct HIDGamepadButton) * (deviceRecord->numButtons + 1));
      hidDeviceRecord->buttonElements[deviceRecord->numButtons].cookie = IOHIDElementGetCookie(element);
      deviceRecord->numButtons++;
    }
  }
  CFRelease(elements);
	
  deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
  deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
	
  IOHIDDeviceRegisterInputValueCallback(device, onDeviceValueChanged, deviceRecord);
	
  queuedEvent.deviceID = deviceRecord->deviceID;
  queuedEvent.eventType = GAMEPAD_EVENT_DEVICE_ATTACHED;
  queuedEvent.eventData = deviceRecord;
	
  if (deviceEventCount >= deviceEventQueueSize) {
    deviceEventQueueSize = deviceEventQueueSize == 0 ? 1 : deviceEventQueueSize * 2;
    deviceEventQueue = realloc(deviceEventQueue, sizeof(struct Gamepad_queuedEvent) * deviceEventQueueSize);
  }
  deviceEventQueue[deviceEventCount++] = queuedEvent;
}
Exemple #13
0
void joypad::add_hid_element(IOHIDElementRef p_element) {
	const CFTypeID elementTypeID = p_element ? CFGetTypeID(p_element) : 0;

	if (p_element && (elementTypeID == IOHIDElementGetTypeID())) {
		const IOHIDElementCookie cookie = IOHIDElementGetCookie(p_element);
		const uint32_t usagePage = IOHIDElementGetUsagePage(p_element);
		const uint32_t usage = IOHIDElementGetUsage(p_element);
		Vector<rec_element> *list = NULL;

		switch (IOHIDElementGetType(p_element)) {
			case kIOHIDElementTypeInput_Misc:
			case kIOHIDElementTypeInput_Button:
			case kIOHIDElementTypeInput_Axis: {
				switch (usagePage) {
					case kHIDPage_GenericDesktop:
						switch (usage) {
							case kHIDUsage_GD_X:
							case kHIDUsage_GD_Y:
							case kHIDUsage_GD_Z:
							case kHIDUsage_GD_Rx:
							case kHIDUsage_GD_Ry:
							case kHIDUsage_GD_Rz:
							case kHIDUsage_GD_Slider:
							case kHIDUsage_GD_Dial:
							case kHIDUsage_GD_Wheel:
								if (!has_element(cookie, &axis_elements)) {
									list = &axis_elements;
								}
								break;

							case kHIDUsage_GD_Hatswitch:
								if (!has_element(cookie, &hat_elements)) {
									list = &hat_elements;
								}
								break;
							case kHIDUsage_GD_DPadUp:
							case kHIDUsage_GD_DPadDown:
							case kHIDUsage_GD_DPadRight:
							case kHIDUsage_GD_DPadLeft:
							case kHIDUsage_GD_Start:
							case kHIDUsage_GD_Select:
								if (!has_element(cookie, &button_elements)) {
									list = &button_elements;
								}
								break;
						}
						break;

					case kHIDPage_Simulation:
						switch (usage) {
							case kHIDUsage_Sim_Rudder:
							case kHIDUsage_Sim_Throttle:
								if (!has_element(cookie, &axis_elements)) {
									list = &axis_elements;
								}
								break;

							default:
								break;
						}
						break;

					case kHIDPage_Button:
					case kHIDPage_Consumer:
						if (!has_element(cookie, &button_elements)) {
							list = &button_elements;
						}
						break;

					default:
						break;
				}
			} break;

			case kIOHIDElementTypeCollection: {
				CFArrayRef array = IOHIDElementGetChildren(p_element);
				if (array) {
					add_hid_elements(array);
				}
			} break;

			default:
				break;
		}

		if (list) { /* add to list */
			rec_element element;

			element.ref = p_element;
			element.usage = usage;

			element.min = (SInt32)IOHIDElementGetLogicalMin(p_element);
			element.max = (SInt32)IOHIDElementGetLogicalMax(p_element);
			element.cookie = IOHIDElementGetCookie(p_element);
			list->push_back(element);
			list->sort_custom<rec_element::Comparator>();
		}
	}
}
Exemple #14
0
JoystickState JoystickImpl::update()
{
    static const JoystickState disconnectedState; // return this if joystick was disconnected
    JoystickState       state; // otherwise return that
    state.connected = true;

    // Note: free up is done in close() which is called, if required,
    //       by the joystick manager. So we don't release buttons nor axes here.

    // First, let's determine if the joystick is still connected
    Location selfLoc = m_locationIDs[m_index];

    // Get all devices
    CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks();
    if (devices == NULL)
        return disconnectedState;

    // Get a usable copy of the joysticks devices.
    CFIndex joysticksCount = CFSetGetCount(devices);
    CFTypeRef devicesArray[joysticksCount];
    CFSetGetValues(devices, devicesArray);

    // Search for it
    bool found = false;
    for (CFIndex i(0); i < joysticksCount; ++i)
    {
        IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
        if (selfLoc == HIDInputManager::getLocationID(d))
        {
            found = true;
            break; // Stop looping
        }
    }

    // Release unused stuff
    CFRelease(devices);

    // If not found we consider it disconnected
    if (!found)
        return disconnectedState;

    // Update buttons' state
    unsigned int i = 0;
    for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it, ++i)
    {
        IOHIDValueRef value = 0;
        IOHIDDeviceGetValue(IOHIDElementGetDevice(*it), *it, &value);

        // Check for plug out.
        if (!value)
        {
            // No value? Hum... Seems like the joystick is gone
            return disconnectedState;
        }

        // 1 means pressed, others mean released
        state.buttons[i] = IOHIDValueGetIntegerValue(value) == 1;
    }

    // Update hatswitch's state
    for (ButtonsVector::iterator it(m_hats.begin()); it != m_hats.end(); ++it, ++i)
    {
        IOHIDValueRef value = 0;
        IOHIDDeviceGetValue(IOHIDElementGetDevice(*it), *it, &value);

        // Check for plug out.
        if (!value)
        {
            // No value? Hum... Seems like the joystick is gone
            return disconnectedState;
        }
    
        int hatValue = IOHIDValueGetIntegerValue(value);
        int min = IOHIDElementGetLogicalMin(*it);
        int max = IOHIDElementGetLogicalMax(*it);
        int range = max - min + 1;
        if (range == 4) {
            hatValue *= 2;
        } else if (range != 8) {
            hatValue = -1;
        }
        switch (hatValue) {
            case 0:
                state.axes[Joystick::PovY] = 100;
                break;
            case 1:
                state.axes[Joystick::PovX] = 100;
                state.axes[Joystick::PovY] = 100;
                break;
            case 2:
                state.axes[Joystick::PovX] = 100;
                break;
            case 3:
                state.axes[Joystick::PovX] = 100;
                state.axes[Joystick::PovY] = -100;
                break;
            case 4:
                state.axes[Joystick::PovY] = -100;
                break;
            case 5:
                state.axes[Joystick::PovX] = -100;
                state.axes[Joystick::PovY] = -100;
                break;
            case 6:
                state.axes[Joystick::PovX] = -100;
                break;
            case 7:
                state.axes[Joystick::PovX] = -100;
                state.axes[Joystick::PovY] = 100;
                break;
        }
    }

    // Update axes' state
    for (AxisMap::iterator it = m_axis.begin(); it != m_axis.end(); ++it)
    {
        IOHIDValueRef value = 0;
        IOHIDDeviceGetValue(IOHIDElementGetDevice(it->second), it->second, &value);

        // Check for plug out.
        if (!value)
        {
            // No value? Hum... Seems like the joystick is gone
            return disconnectedState;
        }

        // We want to bind [physicalMin,physicalMax] to [-100=min,100=max].
        //
        // General formula to bind [a,b] to [c,d] with a linear progression:
        //
        // f : [a, b] -> [c, d]
        //        x  |->  (x-a)(d-c)/(b-a)+c
        //
        // This method might not be very accurate (the "0 position" can be
        // slightly shift with some device) but we don't care because most
        // of devices are so sensitive that this is not relevant.
        double  physicalMax   = IOHIDElementGetPhysicalMax(it->second);
        double  physicalMin   = IOHIDElementGetPhysicalMin(it->second);
        double  scaledMin     = -100;
        double  scaledMax     =  100;
        double  physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
        float   scaledValue   = (((physicalValue - physicalMin) * (scaledMax - scaledMin)) / (physicalMax - physicalMin)) + scaledMin;
        state.axes[it->first] = scaledValue;
    }

    return state;
}
unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef		inIOHIDDeviceRef,
                                             IOHIDElementRef *	outIOHIDElementRef,
                                             double				timeout) {
	if (!inIOHIDDeviceRef) {
		return (0);
	}
	if (0 == HIDHaveDeviceList()) {                                             // if we do not have a device list
		return (0);                                                             // return 0
	}

	Boolean found = false;

	// build list of device and elements to save current values
	CFIndex maxElements = HIDCountDeviceElements(inIOHIDDeviceRef,
	                                             kHIDElementTypeInput);
	double *saveValueArray = (double *) calloc(maxElements,
	                                           sizeof(double));                 // 2D array to save values

	// store initial values on first pass / compare to initial value on subsequent passes
	Boolean first = true;

	// get all the elements from this device
	CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef,
	                                                               NULL,
	                                                               kIOHIDOptionsTypeNone);
	// if that worked...
	if (elementCFArrayRef) {
		clock_t start = clock(),
		        end;

		// poll all devices and elements
		while (!found) {
			uint32_t currElementIndex = 0;
			CFIndex idx,
			        cnt = CFArrayGetCount(elementCFArrayRef);
			for (idx = 0; idx < cnt; idx++) {
				*outIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef,
				                                                               idx);
				if (!*outIOHIDElementRef) {
					continue;
				}

				// is this an input element?
				IOHIDElementType type = IOHIDElementGetType(*outIOHIDElementRef);

				switch (type) {
					// these types are inputs
					case kIOHIDElementTypeInput_Misc:
					case kIOHIDElementTypeInput_Button:
					case kIOHIDElementTypeInput_Axis:
					case kIOHIDElementTypeInput_ScanCodes:
					default:
					{
						break;
					}

					case kIOHIDElementTypeOutput:
					case kIOHIDElementTypeFeature:
					case kIOHIDElementTypeCollection:
					{
						*outIOHIDElementRef = NULL;                             // these types are not (Skip them)
						break;
					}
				}                                                               /* switch */
				if (!*outIOHIDElementRef) {
					continue;                                                   // skip this element
				}

				// get this elements current value
				double value = 0;                                               // default value is zero
				IOHIDValueRef tIOHIDValueRef;
				IOReturn ioReturn = IOHIDDeviceGetValue(inIOHIDDeviceRef,
				                                        *outIOHIDElementRef,
				                                        &tIOHIDValueRef);
				if (kIOReturnSuccess == ioReturn) {
					value = IOHIDValueGetScaledValue(tIOHIDValueRef,
					                                 kIOHIDValueScaleTypePhysical);
				}
				if (first) {
					saveValueArray[currElementIndex] = value;
				} else {
					CFIndex min = IOHIDElementGetLogicalMin(*outIOHIDElementRef);
					CFIndex max = IOHIDElementGetLogicalMax(*outIOHIDElementRef);

					double initialValue = saveValueArray[currElementIndex];
					double delta = (double) (max -
					                         min) *
					               kPercentMove *
					               0.01f;
					// is the new value within +/- delta of the initial value?
					if (((initialValue +
					      delta) < value) ||
					    ((initialValue -
					      delta) > value))
					{
						found = 1;                                              // (yes!) mark as found
						break;
					}
				}                                                               // if (first)

				currElementIndex++;                                             // bump element index
			}                                                                   // next idx
			if (first) {
				first = false;                                                  // no longer the first pass
			} else {
				// are we done?
				end = clock();
				double secs = (double) (end -
				                        start) /
				              CLOCKS_PER_SEC;
				if (secs > timeout) {
					break;                                                      // (yes) timeout
				}
			}
		}                                                                       // while (!found)

		CFRelease(elementCFArrayRef);
	}                                                                           // if (elementCFArrayRef)
	if (saveValueArray) {
		free(saveValueArray);
	}
	// return device and element moved
	if (found) {
		return (1);
	} else {
		*outIOHIDElementRef = NULL;

		return (0);
	}
}                                                                               // HIDConfigureSingleDeviceAction
// 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
Exemple #17
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;
}
Exemple #18
0
//int main( int argc, const char * argv[] )
int manipulate_led( int which_led, int led_value )
{
#pragma unused ( argc, argv )
	IOHIDDeviceRef * tIOHIDDeviceRefs = nil;

	// create a IO HID Manager reference
	IOHIDManagerRef tIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone );
	require( tIOHIDManagerRef, Oops );

	// Create a device matching dictionary
	CFDictionaryRef matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( TRUE,
																				  kHIDPage_GenericDesktop,
																				  kHIDUsage_GD_Keyboard );
	require( matchingCFDictRef, Oops );

	// set the HID device matching dictionary
	IOHIDManagerSetDeviceMatching( tIOHIDManagerRef, matchingCFDictRef );

	if ( matchingCFDictRef ) {
		CFRelease( matchingCFDictRef );
	}

	// Now open the IO HID Manager reference
	IOReturn tIOReturn = IOHIDManagerOpen( tIOHIDManagerRef, kIOHIDOptionsTypeNone );
	require_noerr( tIOReturn, Oops );

	// and copy out its devices
	CFSetRef deviceCFSetRef = IOHIDManagerCopyDevices( tIOHIDManagerRef );
	require( deviceCFSetRef, Oops );

	// how many devices in the set?
	CFIndex deviceIndex, deviceCount = CFSetGetCount( deviceCFSetRef );

	// allocate a block of memory to extact the device ref's from the set into
	tIOHIDDeviceRefs = malloc( sizeof( IOHIDDeviceRef ) * deviceCount );
	if (!tIOHIDDeviceRefs) {
		CFRelease(deviceCFSetRef);
		deviceCFSetRef = NULL;
		goto Oops;
	}

	// now extract the device ref's from the set
	CFSetGetValues( deviceCFSetRef, (const void **) tIOHIDDeviceRefs );
	CFRelease(deviceCFSetRef);
	deviceCFSetRef = NULL;

	// before we get into the device loop we'll setup our element matching dictionary
	matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( FALSE, kHIDPage_LEDs, 0 );
	require( matchingCFDictRef, Oops );

	int pass;	// do 256 passes
	//for ( pass = 0; pass < 256; pass++ ) {
		Boolean delayFlag = FALSE;	// if we find an LED element we'll set this to TRUE

		//printf( "pass = %d.\n", pass );
		for ( deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++ ) {

			// if this isn't a keyboard device...
			if ( !IOHIDDeviceConformsTo( tIOHIDDeviceRefs[deviceIndex], kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard ) ) {
				continue;	// ...skip it
			}

			//printf( "	 device = %p.\n", tIOHIDDeviceRefs[deviceIndex] );

			// copy all the elements
			CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRefs[deviceIndex],
																		   matchingCFDictRef,
																		   kIOHIDOptionsTypeNone );
			require( elementCFArrayRef, next_device );

			// for each device on the system these values are divided by the value ranges of all LED elements found
			// for example, if the first four LED element have a range of 0-1 then the four least significant bits of
			// this value will be sent to these first four LED elements, etc.
			int device_value = pass;

			// iterate over all the elements
			CFIndex elementIndex, elementCount = CFArrayGetCount( elementCFArrayRef );
			for ( elementIndex = 0; elementIndex < elementCount; elementIndex++ ) {
				IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, elementIndex );
				require( tIOHIDElementRef, next_element );

				uint32_t usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );

				// if this isn't an LED element...
				if ( kHIDPage_LEDs != usagePage ) {
					continue;	// ...skip it
				}

				uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
				IOHIDElementType tIOHIDElementType = IOHIDElementGetType( tIOHIDElementRef );

				//printf( "		 element = %p (page: %d, usage: %d, type: %d ).\n",
				//	   tIOHIDElementRef, usagePage, usage, tIOHIDElementType );

				// get the logical mix/max for this LED element
				CFIndex minCFIndex = IOHIDElementGetLogicalMin( tIOHIDElementRef );
				CFIndex maxCFIndex = IOHIDElementGetLogicalMax( tIOHIDElementRef );

				// calculate the range
				CFIndex modCFIndex = maxCFIndex - minCFIndex + 1;

				// compute the value for this LED element
				//CFIndex tCFIndex = minCFIndex + ( device_value % modCFIndex );
				CFIndex tCFIndex = led_value;
				device_value /= modCFIndex;

				//printf( "			 value = 0x%08lX.\n", tCFIndex );

				uint64_t timestamp = 0; // create the IO HID Value to be sent to this LED element
				IOHIDValueRef tIOHIDValueRef = IOHIDValueCreateWithIntegerValue( kCFAllocatorDefault, tIOHIDElementRef, timestamp, tCFIndex );
				if ( tIOHIDValueRef ) {
					// now set it on the device
					tIOReturn = IOHIDDeviceSetValue( tIOHIDDeviceRefs[deviceIndex], tIOHIDElementRef, tIOHIDValueRef );
					CFRelease( tIOHIDValueRef );
					require_noerr( tIOReturn, next_element );
					delayFlag = TRUE;	// set this TRUE so we'll delay before changing our LED values again
				}
			next_element:	;
				continue;
			}
			CFRelease( elementCFArrayRef );
		next_device: ;
			continue;
		}

		// if we found an LED we'll delay before continuing
		//if ( delayFlag ) {
		//	usleep( 500000 ); // sleep one half second
		//}

		// if the mouse is down…
		//if (GetCurrentButtonState()) {
		//	break;	// abort pass loop
		//}
	//}						  // next pass

	if ( matchingCFDictRef ) {
		CFRelease( matchingCFDictRef );
	}
Oops:	;
	if ( tIOHIDDeviceRefs ) {
		free(tIOHIDDeviceRefs);
	}

	if ( tIOHIDManagerRef ) {
		CFRelease( tIOHIDManagerRef );
	}
	return 0;
} /* main */
Exemple #19
0
static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
      void* sender, IOHIDValueRef value)
{
   iohidmanager_hid_t *hid                  = (iohidmanager_hid_t*)hid_driver_get_data();
   struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)data;
   IOHIDElementRef element                  = IOHIDValueGetElement(value);
   uint32_t type                            = (uint32_t)IOHIDElementGetType(element);
   uint32_t page                            = (uint32_t)IOHIDElementGetUsagePage(element);
   uint32_t use                             = (uint32_t)IOHIDElementGetUsage(element);
   uint32_t cookie                          = (uint32_t)IOHIDElementGetCookie(element);
   apple_input_rec_t *tmp                   = NULL;

   if (type != kIOHIDElementTypeInput_Misc)
      if (type != kIOHIDElementTypeInput_Button)
         if (type != kIOHIDElementTypeInput_Axis)
            return;

   /* Joystick handler.
    * TODO: Can GamePad work the same? */

   int pushed_button = 0;

   switch (page)
   {
      case kHIDPage_GenericDesktop:
         switch (type)
         {
            case kIOHIDElementTypeInput_Misc:
               switch (use)
               {
                  case kHIDUsage_GD_Hatswitch:
                     {
                        tmp = adapter->hats;

                        while(tmp && tmp->cookie != (IOHIDElementCookie)cookie)
                           tmp = tmp->next;

                        if(tmp->cookie == (IOHIDElementCookie)cookie)
                        {
                           CFIndex range = IOHIDElementGetLogicalMax(element) - IOHIDElementGetLogicalMin(element);
                           CFIndex val   = IOHIDValueGetIntegerValue(value);

                           if(range == 3)
                              val *= 2;

                           switch(val)
                           {
                              case 0:
                                 /* pos = up */
                                 hid->hats[adapter->slot][0] = 0;
                                 hid->hats[adapter->slot][1] = -1;
                                 break;
                              case 1:
                                 /* pos = up+right */
                                 hid->hats[adapter->slot][0] = 1;
                                 hid->hats[adapter->slot][1] = -1;
                                 break;
                              case 2:
                                 /* pos = right */
                                 hid->hats[adapter->slot][0] = 1;
                                 hid->hats[adapter->slot][1] = 0;
                                 break;
                              case 3:
                                 /* pos = down+right */
                                 hid->hats[adapter->slot][0] = 1;
                                 hid->hats[adapter->slot][1] = 1;
                                 break;
                              case 4:
                                 /* pos = down */
                                 hid->hats[adapter->slot][0] = 0;
                                 hid->hats[adapter->slot][1] = 1;
                                 break;
                              case 5:
                                 /* pos = down+left */
                                 hid->hats[adapter->slot][0] = -1;
                                 hid->hats[adapter->slot][1] = 1;
                                 break;
                              case 6:
                                 /* pos = left */
                                 hid->hats[adapter->slot][0] = -1;
                                 hid->hats[adapter->slot][1] = 0;
                                 break;
                              case 7:
                                 /* pos = up_left */
                                 hid->hats[adapter->slot][0] = -1;
                                 hid->hats[adapter->slot][1] = -1;
                                 break;
                              default:
                                 /* pos = centered */
                                 hid->hats[adapter->slot][0] = 0;
                                 hid->hats[adapter->slot][1] = 0;
                                 break;
                           }
                        }
                     }
                     break;
                  default:
                     tmp = adapter->axes;

                     while(tmp && tmp->cookie != (IOHIDElementCookie)cookie)
                        tmp = tmp->next;

                     if (tmp)
                     {
                        if(tmp->cookie == (IOHIDElementCookie)cookie)
                        {
                           CFIndex min   = IOHIDElementGetPhysicalMin(element);
                           CFIndex state = IOHIDValueGetIntegerValue(value) - min;
                           CFIndex max   = IOHIDElementGetPhysicalMax(element) - min;
                           float val     = (float)state / (float)max;

                           hid->axes[adapter->slot][tmp->id] =
                              ((val * 2.0f) - 1.0f) * 32767.0f;
                        }
                     }
                     else
                        pushed_button = 1;
                     break;
               }
               break;
         }
         break;
      case kHIDPage_Consumer:
      case kHIDPage_Button:
         switch (type)
         {
            case kIOHIDElementTypeInput_Misc:
            case kIOHIDElementTypeInput_Button:
               pushed_button = 1;
               break;
         }
         break;
   }

   if (pushed_button)
   {
      tmp = adapter->buttons;

      uint8_t bit = 0;
      while(tmp && tmp->cookie != (IOHIDElementCookie)cookie)
      {
         bit++;
         tmp = tmp->next;
      }

      if(tmp && tmp->cookie == (IOHIDElementCookie)cookie)
      {
         CFIndex state = IOHIDValueGetIntegerValue(value);
         if (state)
            BIT64_SET(hid->buttons[adapter->slot], bit);
         else
            BIT64_CLEAR(hid->buttons[adapter->slot], bit);
      }
   }
}