Esempio n. 1
0
void os_updateindicators(usbdevice* kb, int force){
    if(!IS_CONNECTED(kb) || NEEDS_FW_UPDATE(kb))
        return;
    // Set NumLock on permanently
    char ileds = 1;
    // Set Caps Lock if enabled. Unlike Linux, OSX keyboards have independent caps lock states, so
    // we use the last-assigned value rather than fetching it from the system
    if(kb->eventflags & kCGEventFlagMaskAlphaShift)
        ileds |= 2;
    usbmode* mode = kb->profile.currentmode;
    if(mode && kb->active)
        ileds = (ileds & ~mode->ioff) | mode->ion;
    if(force || ileds != kb->ileds){
        kb->ileds = ileds;
        // Set the LEDs
        CFArrayRef leds = IOHIDDeviceCopyMatchingElements(kb->handles[0], 0, kIOHIDOptionsTypeNone);
        CFIndex count = CFArrayGetCount(leds);
        for(CFIndex i = 0; i < count; i++){
            IOHIDElementRef led = (void*)CFArrayGetValueAtIndex(leds, i);
            uint32_t page = IOHIDElementGetUsagePage(led);
            if(page != kHIDPage_LEDs)
                continue;
            uint32_t usage = IOHIDElementGetUsage(led);
            IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1))));
            IOHIDDeviceSetValue(kb->handles[0], led, value);
            CFRelease(value);
        }
        CFRelease(leds);
    }
}
Esempio n. 2
0
void updateindicators(usbdevice* kb, int force){
    // Set NumLock on permanently
    char ileds = 1;
    // Set Caps Lock if enabled. Unlike Linux, OSX keyboards have independent caps lock states, so
    // we use the last-assigned value rather than fetching it from the system
    if(kb->eflags & kCGEventFlagMaskAlphaShift)
        ileds |= 2;
    if(force || ileds != kb->ileds){
        kb->ileds = ileds;
        // Set the LEDs
        CFArrayRef leds = IOHIDDeviceCopyMatchingElements(kb->handles[0], 0, kIOHIDOptionsTypeNone);
        CFIndex count = CFArrayGetCount(leds);
        for(CFIndex i = 0; i < count; i++){
            IOHIDElementRef led = (void*)CFArrayGetValueAtIndex(leds, i);
            uint32_t page = IOHIDElementGetUsagePage(led);
            if(page != kHIDPage_LEDs)
                continue;
            uint32_t usage = IOHIDElementGetUsage(led);
            IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1))));
            IOHIDDeviceSetValue(kb->handles[0], led, value);
            CFRelease(value);
        }
        CFRelease(leds);
        IOHIDDeviceSetReport(kb->handles[1], kIOHIDReportTypeOutput, 0, &kb->ileds, 1);
    }
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
IOHIDElementRef GetFirstOutputElement(IOHIDDeviceRef device)
{
    IOHIDElementRef output = NULL;
    CFArrayRef arrayElements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
    CFIndex elementCount = CFArrayGetCount(arrayElements);
    for(CFIndex i = 0; i < elementCount; i++)
    {
        IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(arrayElements, i);
				if(!tIOHIDElementRef)
        {
					continue;
				}
				IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef);
				
				switch ( type )
        {
            case kIOHIDElementTypeOutput:
            {
                output = tIOHIDElementRef;
                break;
            }          
            default:
                break;
        }
        
        if(output)
        {
            break;
        }
    }

    CFRelease(arrayElements);
    return output;
}
Esempio n. 5
0
int  joy_hidlib_enumerate_elements(joy_hid_device_t *device)
{
    IOHIDDeviceRef dev = device->internal_device;
    if(dev == NULL) {
        return -1;
    }
    
    /* get all elements of device */
    CFArrayRef internal_elements = IOHIDDeviceCopyMatchingElements( dev, NULL, 0 );    
    if(!internal_elements) {
        return -1;
    }
    
    /* get number of elements */
    CFIndex cnt = CFArrayGetCount( internal_elements );
    device->num_elements = (int)cnt;
    
    /* create elements array */
    joy_hid_element_t *elements = (joy_hid_element_t *)
        lib_malloc(sizeof(joy_hid_element_t) * cnt);
    if(elements == NULL) {
        CFRelease(internal_elements);
        internal_elements = NULL;
        return -1;
    }
    
    /* enumerate and convert all elements */
    CFIndex i;
    joy_hid_element_t *e = elements;
    for(i=0;i<cnt;i++) { 
        IOHIDElementRef internal_element = 
            ( IOHIDElementRef ) CFArrayGetValueAtIndex( internal_elements, i );
        if ( internal_element ) {
            uint32_t usage_page = IOHIDElementGetUsagePage( internal_element );
            uint32_t usage = IOHIDElementGetUsage( internal_element );
            CFIndex min = IOHIDElementGetPhysicalMin( internal_element );
            CFIndex max = IOHIDElementGetPhysicalMax( internal_element );
            
            e->usage_page = (int)usage_page;
            e->usage      = (int)usage;
            e->min_value  = (int)min;
            e->max_value  = (int)max;
            e->internal_element = internal_element;
        } else {
            e->usage_page = -1;
            e->usage      = -1;
            e->min_value  = -1;
            e->max_value  = -1;
            e->internal_element = NULL;
        }
        e++;
    }
    
    /* keep the reference until the elements are free'ed again */
    device->internal_elements = internal_elements;
    device->elements = elements;
    
    return (int)cnt;
}
Esempio n. 6
0
bool JoystickOSX::configure_joystick(IOHIDDeviceRef p_device_ref, joystick *p_joy) {

	CFTypeRef refCF = NULL;

	p_joy->device_ref = p_device_ref;
	/* get device name */
	String name;
	char c_name[256];
	refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductKey));
	if (!refCF) {
		refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDManufacturerKey));
	}
	if ((!refCF) || (!CFStringGetCString((CFStringRef)refCF, c_name, sizeof(c_name), kCFStringEncodingUTF8))) {
		name = "Unidentified Joystick";
	}
	name = c_name;

	int id = input->get_unused_joy_id();
	ERR_FAIL_COND_V(id == -1, false);
	p_joy->id = id;
	int vendor = 0;
	refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDVendorIDKey));
	if (refCF) {
		CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &vendor);
	}

	int product_id = 0;
	refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductIDKey));
	if (refCF) {
		CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &product_id);
	}
	if (vendor && product_id) {
		char uid[128];
		sprintf(uid, "%04x%08x%04x%08x", OSSwapHostToBigInt32(vendor), 0, OSSwapHostToBigInt32(product_id), 0);
		input->joy_connection_changed(id, true, name, uid);
	} else {
		//bluetooth device
		String guid = "05000000";
		for (int i = 0; i < 12; i++) {
			if (i < name.size())
				guid += _hex_str(name[i]);
			else
				guid += "00";
		}
		input->joy_connection_changed(id, true, name, guid);
	}

	CFArrayRef array = NULL;
	array = IOHIDDeviceCopyMatchingElements(p_device_ref, NULL, kIOHIDOptionsTypeNone);
	if (array) {
		p_joy->add_hid_elements(array);
		CFRelease(array);
	}
	return true;
}
Esempio n. 7
0
void setKeyboard(struct __IOHIDDevice *device, CFDictionaryRef keyboardDictionary, LedState changes[])
{
    CFStringRef deviceNameRef = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
    if (!deviceNameRef) return;
    
    const char * deviceName = CFStringGetCStringPtr(deviceNameRef, kCFStringEncodingUTF8);
    
    if (nameMatch && fnmatch(nameMatch, deviceName, 0) != 0)
        return;
    
    if (verbose)
        printf("\n \"%s\" ", deviceName);
    
    CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, keyboardDictionary, kIOHIDOptionsTypeNone);
    if (elements) {
        for (CFIndex elementIndex = 0; elementIndex < CFArrayGetCount(elements); elementIndex++) {
            IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, elementIndex);
            if (element && kHIDPage_LEDs == IOHIDElementGetUsagePage(element)) {
                uint32_t led = IOHIDElementGetUsage(element);
                
                if (led >= maxLeds) break;
                
                // Get current keyboard led status
                IOHIDValueRef currentValue = 0;
                if (IOHIDDeviceGetValue(device, element, &currentValue) == kIOReturnSuccess &&
                    IOHIDValueGetLength(currentValue) < 3) {
                    long current = IOHIDValueGetIntegerValue(currentValue);
                    CFRelease(currentValue);
                    
                    // Should we try to set the led?
                    if (changes[led] != NoChange && changes[led] != current) {
                        IOHIDValueRef newValue = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, element, 0, changes[led]);
                        if (newValue) {
                            IOReturn changeResult = IOHIDDeviceSetValue(device, element, newValue);
                            
                            // Was the change successful?
                            if (kIOReturnSuccess == changeResult && verbose) {
                                printf("%s%s ", stateSymbol[changes[led]], ledNames[led - 1]);
                            }
                            CFRelease(newValue);
                        }
                    } else if (verbose) {
                        printf("%s%s ", stateSymbol[current], ledNames[led - 1]);
                    }
                }
            }
        }
        CFRelease(elements);
    }
    
    if (verbose)
        printf("\n");
}
Esempio n. 8
0
IOHIDElementRef GetNextOutputElement(IOHIDDeviceRef device, IOHIDElementRef previousElement)
{
    bool found = false;
    IOHIDElementRef output = NULL;
    CFArrayRef arrayElements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
    CFIndex elementCount = CFArrayGetCount(arrayElements);
    for(CFIndex i = 0; i < elementCount; i++)
    {
        IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(arrayElements, i);
				if(!tIOHIDElementRef)
        {
					continue;
				}
        
        if(!found)
        {
            if(previousElement == tIOHIDElementRef)
            {
                CFRelease(previousElement); // do we need this ?
                found = true;
            }
            continue;
        }
        
        
				IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef);
				
				switch ( type )
        {
            case kIOHIDElementTypeOutput:
            {
                output = tIOHIDElementRef;
                break;
            }          
            default:
                break;
        }
        
        if(output)
        {
            break;
        }
    }

    CFRelease(arrayElements);
    return output;
}
Esempio n. 9
0
void HIDGamepad::initElements()
{
    RetainPtr<CFArrayRef> elements = adoptCF(IOHIDDeviceCopyMatchingElements(m_hidDevice.get(), NULL, kIOHIDOptionsTypeNone));
    initElementsFromArray(elements.get());

    // Buttons are specified to appear highest priority first in the array.
    std::sort(m_buttons.begin(), m_buttons.end(), [](const std::unique_ptr<HIDGamepadButton>& a, const std::unique_ptr<HIDGamepadButton>& b) {
        return a->priority < b->priority;
    });

    m_axisValues.resize(m_axes.size());
    m_buttonValues.resize(m_buttons.size());

    for (auto& button : m_buttons)
        getCurrentValueForElement(*button);

    for (auto& axis : m_axes)
        getCurrentValueForElement(*axis);
}
Esempio n. 10
0
/**************************************************************************
 *                              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;
}
Esempio n. 11
0
void CInputProviderMacOsHid::SetInitialBindValues(IOHIDDeviceRef device)
{
	CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, nullptr, 0);

	for(int i = 0; i < CFArrayGetCount(elements); i++)
	{
		IOHIDElementRef elementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
		uint32 usagePage = IOHIDElementGetUsagePage(elementRef);
		if(
		    (usagePage != kHIDPage_GenericDesktop) &&
		    (usagePage != kHIDPage_Button))
		{
			continue;
		}
		IOHIDValueRef valueRef;
		if(IOHIDDeviceGetValue(device, elementRef, &valueRef) != kIOReturnSuccess)
		{
			continue;
		}

		CFIndex value = IOHIDValueGetIntegerValue(valueRef);
		IOHIDElementType type = IOHIDElementGetType(elementRef);
		uint32 usage = IOHIDElementGetUsage(elementRef);
		BINDINGTARGET tgt;
		tgt.providerId = PROVIDER_ID;
		tgt.deviceId = GetDeviceID(device);
		tgt.keyId = usage;
		tgt.keyType = GetKeyType(usage, type);
		switch(type)
		{
		case kIOHIDElementTypeInput_Misc:
		case kIOHIDElementTypeInput_Button:
		case kIOHIDElementTypeInput_Axis:
			OnInput(tgt, value);
			break;
		default:
			break;
		}
	}
}
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
// *************************************************************************
//
// HIDConfigureAction(outIOHIDDeviceRef, outIOHIDElementRef, inTimeout)
//
// Purpose: polls all devices and elements for a change greater than kPercentMove.
// Times out after given time returns 1 and pointer to device and element
// if found; returns 0 and NULL for both parameters if not found
//
// Inputs:	outIOHIDDeviceRef	- address where to store the device
// outIOHIDElementRef	- address where to store the element
// inTimeout	- the timeout
// Returns: Boolean		- if successful
// outIOHIDDeviceRef	- the device
// outIOHIDElementRef	- the element
//
Boolean HIDConfigureActionOfType(actionTypeMask		inActionTypeMask,
                                 double				inTimeout,
                                 IOHIDDeviceRef *	outIOHIDDeviceRef,
                                 IOHIDElementRef *	outIOHIDElementRef) {
	// param error?
	if (!outIOHIDDeviceRef ||
	    !outIOHIDElementRef)
	{
		return (false);
	}
	if (!gDeviceCFArrayRef) {                                                   // if we do not have a device list
		                                                                        // and	we can't build another list
		if (!HIDBuildDeviceList(0,
		                        0) ||
		    !gDeviceCFArrayRef)
		{
			return (false);                                                     // bail
		}
	}

	IOHIDDeviceRef tIOHIDDeviceRef;
	IOHIDElementRef tIOHIDElementRef;

	IOHIDElementType elementType = 0;

	switch (inActionTypeMask) {
		case kActionTypeButton:
		{
			elementType = kIOHIDElementTypeInput_Button;
			break;
		}

		case kActionTypeAxis:
		{
			elementType = kIOHIDElementTypeInput_Misc;
			break;
		}

		case kActionTypeAll:
		default:
		{
			elementType = 0;
			break;
		}
	}                                                                           // switch

	// determine the maximum number of elements
	CFIndex maxElements = 0;
	CFIndex devIndex,
	        devCount = CFArrayGetCount(gDeviceCFArrayRef);
	for (devIndex = 0; devIndex < devCount; devIndex++) {
		tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef,
		                                                          devIndex);
		if (!tIOHIDDeviceRef) {
			continue;                                                           // skip this one
		}

		// HIDDumpDeviceInfo(tIOHIDDeviceRef);
		CFIndex count = HIDCountDeviceElementsOfType(tIOHIDDeviceRef,
		                                             elementType);
		if (count > maxElements) {
			maxElements = count;
		}
	}
	if (!(devCount *
	      maxElements))
	{
		return (false);
	}

#if true
//    NSDictionary * matchDictionary = @{@(kIOHIDElementTypeKey): @(elementType)};
	const void *keys[] = {CFSTR(kIOHIDElementTypeKey)};
	const void *vals[] = {CFNumberCreate(kCFAllocatorDefault,
		                                 kCFNumberIntType,
		                                 &elementType)};
	CFDictionaryRef matchingDict = CFDictionaryCreate(kCFAllocatorDefault,
	                                                  keys,
	                                                  vals,
	                                                  1,
	                                                  &kCFTypeDictionaryKeyCallBacks,
	                                                  &kCFTypeDictionaryValueCallBacks);
	CFRelease(vals[0]);
#endif                                                                          // if 1

	// allocate an array of int's in which to store devCount * maxElements values
	double *saveValueArray = (double *) calloc(devCount *
	                                           maxElements,
	                                           sizeof(double));                 // clear 2D array to save values

	// remember when we start; used to calculate timeout
	clock_t start = clock(),
	        end;

	// on first pass store initial values / compare current values to initial values on subsequent passes
	Boolean found = false,
	        first = true;

	while (!found) {
		double maxDeltaPercent = 0;                                             // we want to find the one that moves the most
		                                                                        // (percentage wise)
		for (devIndex = 0; devIndex < devCount; devIndex++) {
			tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef,
			                                                          devIndex);
			if (!tIOHIDDeviceRef) {
				continue;                                                       // skip this one
			}

			gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef,
			                                                     matchingDict,
			                                                     kIOHIDOptionsTypeNone);
			if (gElementCFArrayRef) {
				CFIndex eleIndex,
				        eleCount = CFArrayGetCount(gElementCFArrayRef);
				for (eleIndex = 0; eleIndex < eleCount; eleIndex++) {
					tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef,
					                                                            eleIndex);
					if (!tIOHIDElementRef) {
						continue;
					}

					IOHIDElementType tIOHIDElementType = IOHIDElementGetType(tIOHIDElementRef);
					// only care about inputs (no outputs or features)
					if (tIOHIDElementType <= kIOHIDElementTypeInput_ScanCodes) {
						if (IOHIDElementIsArray(tIOHIDElementRef)) {
							// printf("ARRAY!\n");
							continue;                                           // skip array elements
						}
						if (elementType &&
						    ((tIOHIDElementType != elementType)))
						{
							continue;
						}

						uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
						uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
						uint32_t reportCount = IOHIDElementGetReportCount(tIOHIDElementRef);
#ifdef DEBUG
						if (first) {
							HIDDumpElementInfo(tIOHIDElementRef);
							fflush(stdout);
							uint32_t vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
							uint32_t productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
							IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
							if ((0x054C == vendorID) &&
							    (0x0268 == productID) &&
							    (0x001E == (uint32_t) cookie))
							{
								// printf("DING!\n");
							}
						}

#endif                                                                          // ifdef DEBUG

#if true                                                                        // work-around for IOHIDValueGetScaledValue crash
						                                                        // (when element report count > 1)
						if (reportCount > 1) {
							// printf("REPORT!\n");
							continue;                                           // skip reports
						}

#endif                                                                          // if 1
						// ignore PID elements and arrays
						if ((kHIDPage_PID != usagePage) &&
						    ((-1) != usage))
						{
							// get this elements current value
							double value = 0.0;                                 // default value is zero
							IOHIDValueRef tIOHIDValueRef;
							IOReturn ioReturn = IOHIDDeviceGetValue(tIOHIDDeviceRef,
							                                        tIOHIDElementRef,
							                                        &tIOHIDValueRef);
							if (kIOReturnSuccess == ioReturn) {
								value = IOHIDValueGetScaledValue(tIOHIDValueRef,
								                                 kIOHIDValueScaleTypePhysical);
							}
							if (first) {
								saveValueArray[(devIndex *
								                maxElements) +
								               eleIndex] = value;
							} else {
								double initialValue = saveValueArray[(devIndex *
								                                      maxElements) +
								                                     eleIndex];

								CFIndex valueMin = IOHIDElementGetPhysicalMin(tIOHIDElementRef);
								CFIndex valueMax = IOHIDElementGetPhysicalMax(tIOHIDElementRef);

								double deltaPercent = fabs((initialValue -
								                            value) *
								                           100.0 /
								                           (valueMax -
								                            valueMin));
#if false                                                                       // debug code useful to dump out value info for
								                                                // specific (vendorID, productID, usagePage and
								                                                // usage) device
								if (!first) {
									// Device: 0x13b6a0 = { Logitech Inc. - WingMan Force 3D,	vendorID:	0x046D,		productID:	0xC283,
									// usage: 0x0001:0x0004, "Generic Desktop Joystick"
									if ((vendorID == 0x046D) &&
									    (productID == 0xC283))
									{
										if ((kHIDPage_GenericDesktop == usagePage) &&
										    (kHIDUsage_GD_Rz == usage))
										{
											printf("initial: %6.2f, value: %6.2f, diff: %6.2f, delta percent: %6.2f!\n",
											       initialValue,
											       value,
											       fabs(initialValue -
											            value),
											       deltaPercent);
										}
									}
								}

								deltaPercent = 0.0;
#endif // if false
								if (deltaPercent >= kPercentMove) {
									found = true;
									if (deltaPercent > maxDeltaPercent) {
										maxDeltaPercent = deltaPercent;

										*outIOHIDDeviceRef = tIOHIDDeviceRef;
										*outIOHIDElementRef = tIOHIDElementRef;
									}

									break;
								}
							}                                                   // if first
						}                                                       // if usage
					}                                                           // if type
				}                                                               // for elements...

				CFRelease(gElementCFArrayRef);
				gElementCFArrayRef = NULL;
			}                                                                   // if (gElementCFArrayRef)
			if (found) {
				// HIDDumpElementInfo(tIOHIDElementRef);
				break;                                                          // DONE!
			}
		}                                                                       // for devices

		first = false;                                                          // no longer the first pass

		// are we done?
		end = clock();
		double secs = (double) (end -
		                        start) /
		              CLOCKS_PER_SEC;
		if (secs > inTimeout) {
			break;                                                              // (yes) timeout
		}
	}                                                                           // while (!found)
	if (saveValueArray) {
		free(saveValueArray);
	}
	// return device and element moved
	if (!found) {
		*outIOHIDDeviceRef = NULL;
		*outIOHIDElementRef = NULL;
	}

	CFRelease(matchingDict);

	return (found);
}                                                                               // HIDConfigureAction
Esempio n. 14
0
static SDL_bool
GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
{
    Uint32 *guid32 = NULL;
    CFTypeRef refCF = NULL;
    CFArrayRef array = NULL;

    /* get usage page and usage */
    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsagePageKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usagePage);
    }
    if (pDevice->usagePage != kHIDPage_GenericDesktop) {
        return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */
    }

    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsageKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usage);
    }

    if ((pDevice->usage != kHIDUsage_GD_Joystick &&
         pDevice->usage != kHIDUsage_GD_GamePad &&
         pDevice->usage != kHIDUsage_GD_MultiAxisController)) {
        return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */
    }

    pDevice->deviceRef = hidDevice;

    /* get device name */
    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey));
    if (!refCF) {
        /* Maybe we can't get "AwesomeJoystick2000", but we can get "Logitech"? */
        refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey));
    }
    if ((!refCF) || (!CFStringGetCString(refCF, pDevice->product, sizeof (pDevice->product), kCFStringEncodingUTF8))) {
        SDL_strlcpy(pDevice->product, "Unidentified joystick", sizeof (pDevice->product));
    }

    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVendorIDKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->guid.data[0]);
    }

    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductIDKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->guid.data[8]);
    }

    /* Check to make sure we have a vendor and product ID
       If we don't, use the same algorithm as the Linux code for Bluetooth devices */
    guid32 = (Uint32*)pDevice->guid.data;
    if (!guid32[0] && !guid32[1]) {
        /* If we don't have a vendor and product ID this is probably a Bluetooth device */
        const Uint16 BUS_BLUETOOTH = 0x05;
        Uint16 *guid16 = (Uint16 *)guid32;
        *guid16++ = BUS_BLUETOOTH;
        *guid16++ = 0;
        SDL_strlcpy((char*)guid16, pDevice->product, sizeof(pDevice->guid.data) - 4);
    }

    array = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone);
    if (array) {
        AddHIDElements(array, pDevice);
        CFRelease(array);
    }

    return SDL_TRUE;
}
Esempio n. 15
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;
}
Esempio n. 16
0
bool GPUSB_Open() {

    // VID = 4938  PID = 36897
    IOHIDManagerRef managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
    pGPUSB = FindDevice(managerRef, 4938, 36896);
    if(!pGPUSB)
    {
      CFRelease(managerRef);
      return false;
    }
    

    GPUSB_Model = 0;
    CFArrayRef arrayElements = IOHIDDeviceCopyMatchingElements(pGPUSB, NULL, kIOHIDOptionsTypeNone);
    CFIndex elementCount = CFArrayGetCount(arrayElements);
    int countInputElements = 0;
    for(int i = 0; i < elementCount; i++)
    {
        IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(arrayElements, i);
				if(!tIOHIDElementRef)
        {
					continue;
				}
				IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef);
				
				switch ( type )
        {
            case kIOHIDElementTypeInput_Misc:
            case kIOHIDElementTypeInput_Button:
            case kIOHIDElementTypeInput_Axis:
            case kIOHIDElementTypeInput_ScanCodes:
            {
                countInputElements++;
                break;
            }
          
            default:
                break;
        }
        
        CFRelease(tIOHIDElementRef);
    }
    
    CFRelease(arrayElements);
    if(countInputElements == 1)
         GPUSB_Model = 1;


    // now opening the device for communication
    IOReturn ioReturnValue = IOHIDDeviceOpen(pGPUSB, kIOHIDOptionsTypeSeizeDevice);
    if(ioReturnValue != kIOReturnSuccess)
    {
      CFRelease(pGPUSB);
      pGPUSB = NULL;
      CFRelease(managerRef);
      return false;
      
    }
    

    
    CFRelease(managerRef); // check if this is ok
    return true;
}
Esempio n. 17
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;
}
Esempio n. 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 */
Esempio n. 19
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;
}
Esempio n. 20
0
static SDL_bool
GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
{
    const Uint16 BUS_USB = 0x03;
    const Uint16 BUS_BLUETOOTH = 0x05;
    Sint32 vendor = 0;
    Sint32 product = 0;
    Sint32 version = 0;
    CFTypeRef refCF = NULL;
    CFArrayRef array = NULL;
    Uint16 *guid16 = (Uint16 *)pDevice->guid.data;

    /* get usage page and usage */
    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsagePageKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usagePage);
    }
    if (pDevice->usagePage != kHIDPage_GenericDesktop) {
        return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */
    }

    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsageKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usage);
    }

    if ((pDevice->usage != kHIDUsage_GD_Joystick &&
         pDevice->usage != kHIDUsage_GD_GamePad &&
         pDevice->usage != kHIDUsage_GD_MultiAxisController)) {
        return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */
    }

    pDevice->deviceRef = hidDevice;

    /* get device name */
    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey));
    if (!refCF) {
        /* Maybe we can't get "AwesomeJoystick2000", but we can get "Logitech"? */
        refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey));
    }
    if ((!refCF) || (!CFStringGetCString(refCF, pDevice->product, sizeof (pDevice->product), kCFStringEncodingUTF8))) {
        SDL_strlcpy(pDevice->product, "Unidentified joystick", sizeof (pDevice->product));
    }

    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVendorIDKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &vendor);
    }

    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductIDKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &product);
    }

    refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVersionNumberKey));
    if (refCF) {
        CFNumberGetValue(refCF, kCFNumberSInt32Type, &version);
    }

    SDL_memset(pDevice->guid.data, 0, sizeof(pDevice->guid.data));

    if (vendor && product) {
        *guid16++ = SDL_SwapLE16(BUS_USB);
        *guid16++ = 0;
        *guid16++ = SDL_SwapLE16((Uint16)vendor);
        *guid16++ = 0;
        *guid16++ = SDL_SwapLE16((Uint16)product);
        *guid16++ = 0;
        *guid16++ = SDL_SwapLE16((Uint16)version);
        *guid16++ = 0;
    } else {
        *guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
        *guid16++ = 0;
        SDL_strlcpy((char*)guid16, pDevice->product, sizeof(pDevice->guid.data) - 4);
    }

    array = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone);
    if (array) {
        AddHIDElements(array, pDevice);
        CFRelease(array);
    }

    return SDL_TRUE;
}
Esempio n. 21
0
// ----------------------------------------------------
int main(int			argc,
         const char *	argv[]) {
#pragma unused ( argc, argv )

	IOHIDManagerRef tIOHIDManagerRef = NULL;
	CFSetRef deviceCFSetRef = NULL;
	IOHIDDeviceRef *tIOHIDDeviceRefs = nil;

	do {
		tIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault,
		                                      kIOHIDOptionsTypeNone);
		if (!tIOHIDManagerRef) {
			break;
		}

		IOHIDManagerSetDeviceMatching(tIOHIDManagerRef,
		                              NULL);

		IOReturn tIOReturn = IOHIDManagerOpen(tIOHIDManagerRef,
		                                      kIOHIDOptionsTypeNone);
		if (noErr != tIOReturn) {
			break;
		}

		deviceCFSetRef = IOHIDManagerCopyDevices(tIOHIDManagerRef);
		if (!deviceCFSetRef) {
			break;
		}

		CFIndex deviceIndex,
		        deviceCount = CFSetGetCount(deviceCFSetRef);

		tIOHIDDeviceRefs = malloc(sizeof(IOHIDDeviceRef) *
		                          deviceCount);
		if (!tIOHIDDeviceRefs) {
			break;
		}

		CFSetGetValues(deviceCFSetRef,
		               (const void **)tIOHIDDeviceRefs);
		CFRelease(deviceCFSetRef);
		deviceCFSetRef = NULL;
		for (deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) {
			if (!tIOHIDDeviceRefs[deviceIndex]) {
				continue;
			}

			HIDDumpDeviceInfo(tIOHIDDeviceRefs[deviceIndex]);
#if true
			// and copy all the elements
			CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRefs[deviceIndex],
			                                                               NULL /* matchingCFDictRef */,
			                                                               kIOHIDOptionsTypeNone);
			if (elementCFArrayRef) {
				// iterate over all the elements
				CFIndex elementIndex,
				        elementCount = CFArrayGetCount(elementCFArrayRef);
				for (elementIndex = 0; elementIndex < elementCount; elementIndex++) {
					IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(elementCFArrayRef,
					                                                                           elementIndex);
					if (tIOHIDElementRef) {
						HIDDumpElementInfo(tIOHIDElementRef);
					}
				}

				CFRelease(elementCFArrayRef);
			}
#endif
		}
	} while (false);

	if (tIOHIDDeviceRefs) {
		free(tIOHIDDeviceRefs);
	}
	if (deviceCFSetRef) {
		CFRelease(deviceCFSetRef);
		deviceCFSetRef = NULL;
	}
	if (tIOHIDManagerRef) {
		CFRelease(tIOHIDManagerRef);
	}

	return (0);
} // main
Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo,
                                IOHIDDeviceRef *	outFoundDevice,
                                IOHIDElementRef *	outFoundElement) {
	Boolean result = false;

	IOHIDDeviceRef bestIOHIDDeviceRef = NULL;
	IOHIDElementRef bestIOHIDElementRef = NULL;
	int bestScore = 0;

	CFIndex devIndex,
	        devCount = CFArrayGetCount(gDeviceCFArrayRef);

	for (devIndex = 0; devIndex < devCount; devIndex++) {
		int deviceScore = 1;

		IOHIDDeviceRef tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef,
		                                                                         devIndex);
		if (!tIOHIDDeviceRef) {
			continue;
		}
		// match vendorID, productID (+10, +8)
		if (inSearchInfo->device.vendorID) {
			uint32_t vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
			if (vendorID) {
				if (inSearchInfo->device.vendorID == vendorID) {
					deviceScore += 10;
					if (inSearchInfo->device.productID) {
						uint32_t productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
						if (productID) {
							if (inSearchInfo->device.productID == productID) {
								deviceScore += 8;
							}                                                   // if (inSearchInfo->device.productID == productID)
						}                                                       // if (productID)
					}                                                           // if (inSearchInfo->device.productID)
				}                                                               // if (inSearchInfo->device.vendorID == vendorID)
			}                                                                   // if vendorID
		}                                                                       // if search->device.vendorID
		                                                                        // match usagePage & usage (+9)
		if (inSearchInfo->device.usagePage &&
		    inSearchInfo->device.usage)
		{
			uint32_t usagePage = IOHIDDevice_GetUsagePage(tIOHIDDeviceRef);
			uint32_t usage = IOHIDDevice_GetUsage(tIOHIDDeviceRef);
			if (!usagePage ||
			    !usage)
			{
				usagePage = IOHIDDevice_GetPrimaryUsagePage(tIOHIDDeviceRef);
				usage = IOHIDDevice_GetPrimaryUsage(tIOHIDDeviceRef);
			}
			if (usagePage) {
				if (inSearchInfo->device.usagePage == usagePage) {
					if (usage) {
						if (inSearchInfo->device.usage == usage) {
							deviceScore += 9;
						}                                                       // if (inSearchInfo->usage == usage)
					}                                                           // if (usage)
				}                                                               // if (inSearchInfo->usagePage == usagePage)
			}                                                                   // if (usagePage)
		}                                                                       // if (inSearchInfo->usagePage &&
		                                                                        // inSearchInfo->usage)
		                                                                        // match location ID (+5)
		if (inSearchInfo->device.locID) {
			uint32_t locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef);
			if (locID) {
				if (inSearchInfo->device.locID == locID) {
					deviceScore += 5;
				}
			}
		}

		// iterate over all elements of this device
		gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef,
		                                                     NULL,
		                                                     0);
		if (gElementCFArrayRef) {
			CFIndex eleIndex,
			        eleCount = CFArrayGetCount(gElementCFArrayRef);
			for (eleIndex = 0; eleIndex < eleCount; eleIndex++) {
				IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef,
				                                                                            eleIndex);
				if (!tIOHIDElementRef) {
					continue;
				}

				int score = deviceScore;
				// match usage page, usage & cookie
				if (inSearchInfo->element.usagePage &&
				    inSearchInfo->element.usage)
				{
					uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
					if (inSearchInfo->element.usagePage == usagePage) {
						uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
						if (inSearchInfo->element.usage == usage) {
							score += 5;
							IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
							if (inSearchInfo->element.cookie == cookie) {
								score += 4;
							}                                                   // cookies match
						} else {
							score = 0;
						}                                                       // usages match
					} else {
						score = 0;
					}                                                           // usage pages match
				}                                                               // if (search usage page & usage)

#if LOG_SCORING
				if (kHIDPage_KeyboardOrKeypad != tElementRef->usagePage) {      // skip keyboards here
					printf("%s: (%ld:%ld)-I-Debug, score: %ld\t",
					       __PRETTY_FUNCTION__,
					       inSearchInfo->element.usagePage,
					       inSearchInfo->element.usage,
					       score);
					HIDPrintElement(tIOHIDElementRef);
				}

#endif                                                                          // LOG_SCORING
				if (score > bestScore) {
					bestIOHIDDeviceRef = tIOHIDDeviceRef;
					bestIOHIDElementRef = tIOHIDElementRef;
					bestScore = score;
#if LOG_SCORING
					printf("%s: (%ld:%ld)-I-Debug, better score: %ld\t",
					       __PRETTY_FUNCTION__,
					       inSearchInfo->element.usagePage,
					       inSearchInfo->element.usage,
					       score);
					HIDPrintElement(bestIOHIDElementRef);
#endif                                                                          // LOG_SCORING
				}
			}                                                                   // for elements...

			CFRelease(gElementCFArrayRef);
			gElementCFArrayRef = NULL;
		}                                                                       // if (gElementCFArrayRef)
	}                                                                           // for (devIndex = 0; devIndex < devCount;
	                                                                            // devIndex++)
	if (bestIOHIDDeviceRef ||
	    bestIOHIDElementRef)
	{
		*outFoundDevice = bestIOHIDDeviceRef;
		*outFoundElement = bestIOHIDElementRef;
#if LOG_SCORING
		printf("%s: (%ld:%ld)-I-Debug, best score: %ld\t",
		       __PRETTY_FUNCTION__,
		       inSearchInfo->element.usagePage,
		       inSearchInfo->element.usage,
		       bestScore);
		HIDPrintElement(bestIOHIDElementRef);
#endif                                                                          // LOG_SCORING
		result = true;
	}

	return (result);
}                                                                               // HIDFindDeviceAndElement
// Get matching element from config record
// takes a pre-allocated and filled out config record
// search for matching device
// return IOHIDDeviceRef, IOHIDElementRef and cookie for action
IOHIDElementCookie HIDGetElementConfig(HID_info_ptr		inHIDInfoPtr,
                                       IOHIDDeviceRef * outIOHIDDeviceRef,
                                       IOHIDElementRef *outIOHIDElementRef) {
	if (!inHIDInfoPtr->device.locID &&
	    !inHIDInfoPtr->device.vendorID &&
	    !inHIDInfoPtr->device.productID &&
	    !inHIDInfoPtr->device.usage &&
	    !inHIDInfoPtr->device.usagePage)                                        //
	{                                                                           //
		                                                                        // early out
		*outIOHIDDeviceRef = NULL;
		*outIOHIDElementRef = NULL;

		return (inHIDInfoPtr->actionCookie);
	}

	IOHIDDeviceRef tIOHIDDeviceRef = NULL,
	               foundIOHIDDeviceRef = NULL;
	IOHIDElementRef tIOHIDElementRef = NULL,
	                foundIOHIDElementRef = NULL;

	CFIndex devIdx,
	        devCnt,
	        idx,
	        cnt;
	// compare to current device list for matches
	// look for device
	if (inHIDInfoPtr->device.locID &&
	    inHIDInfoPtr->device.vendorID &&
	    inHIDInfoPtr->device.productID)                                         // look for specific
	{                                                                           // device
		                                                                        // type plug in to same
		                                                                        // port
		devCnt = CFArrayGetCount(gDeviceCFArrayRef);
		for (devIdx = 0; devIdx < devCnt; devIdx++) {
			tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef,
			                                                          devIdx);
			if (!tIOHIDDeviceRef) {
				continue;                                                       // skip this device
			}

			uint32_t locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef);
			uint32_t vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
			uint32_t productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
			if ((inHIDInfoPtr->device.locID == locID) &&
			    (inHIDInfoPtr->device.vendorID == vendorID) &&
			    (inHIDInfoPtr->device.productID == productID))
			{
				foundIOHIDDeviceRef = tIOHIDDeviceRef;
			}
			if (foundIOHIDDeviceRef) {
				break;
			}
		}                                                                       // next devIdx
		if (foundIOHIDDeviceRef) {
			CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef,
			                                                               NULL,
			                                                               kIOHIDOptionsTypeNone);
			if (elementCFArrayRef) {
				cnt = CFArrayGetCount(elementCFArrayRef);
				for (idx = 0; idx < cnt; idx++) {
					tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef,
					                                                            idx);
					if (!tIOHIDElementRef) {
						continue;                                               // skip this element
					}

					IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
					if (inHIDInfoPtr->element.cookie == cookie) {
						foundIOHIDElementRef = tIOHIDElementRef;
					}
					if (foundIOHIDElementRef) {
						break;
					}
				}
				if (!foundIOHIDElementRef) {
					cnt = CFArrayGetCount(elementCFArrayRef);
					for (idx = 0; idx < cnt; idx++) {
						tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef,
						                                                            idx);
						if (!tIOHIDElementRef) {
							continue;                                           // skip this element
						}

						uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
						uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
						if ((inHIDInfoPtr->element.usage == usage) &&
						    (inHIDInfoPtr->element.usagePage == usagePage))
						{
							foundIOHIDElementRef = tIOHIDElementRef;
						}
						if (foundIOHIDElementRef) {
							break;
						}
					}                                                           // next idx
				}                                                               // if (!foundIOHIDElementRef)
				if (foundIOHIDElementRef) {                                     // if same device
					                                                            // setup the calibration
					IOHIDElement_SetupCalibration(tIOHIDElementRef);

					IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef,
					                                         inHIDInfoPtr->element.minReport);
					IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef,
					                                         inHIDInfoPtr->element.maxReport);
				}

				CFRelease(elementCFArrayRef);
			}                                                                   // if (elementCFArrayRef)
		}                                                                       // if (foundIOHIDDeviceRef)
		                                                                        // if we have not found a match, look at just vendor
		                                                                        // and product
		if ((!foundIOHIDDeviceRef) &&
		    (inHIDInfoPtr->device.vendorID &&
		     inHIDInfoPtr->device.productID))
		{
			devCnt = CFArrayGetCount(gDeviceCFArrayRef);
			for (devIdx = 0; devIdx < devCnt; devIdx++) {
				tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef,
				                                                          devIdx);
				if (!tIOHIDDeviceRef) {
					continue;                                                   // skip this device
				}

				uint32_t vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
				uint32_t productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
				if ((inHIDInfoPtr->device.vendorID == vendorID) &&
				    (inHIDInfoPtr->device.productID == productID))
				{
					foundIOHIDDeviceRef = tIOHIDDeviceRef;
				}
				if (foundIOHIDDeviceRef) {
					break;
				}
			}
			// match elements by cookie since same device type
			if (foundIOHIDDeviceRef) {
				CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef,
				                                                               NULL,
				                                                               kIOHIDOptionsTypeNone);
				if (elementCFArrayRef) {
					cnt = CFArrayGetCount(elementCFArrayRef);
					for (idx = 0; idx < cnt; idx++) {
						tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef,
						                                                            idx);
						if (!tIOHIDElementRef) {
							continue;                                           // skip this element
						}

						IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
						if (inHIDInfoPtr->element.cookie == cookie) {
							foundIOHIDElementRef = tIOHIDElementRef;
						}
						if (foundIOHIDElementRef) {
							break;
						}
					}
					// if no cookie match (should NOT occur) match on usage
					if (!foundIOHIDElementRef) {
						cnt = CFArrayGetCount(elementCFArrayRef);
						for (idx = 0; idx < cnt; idx++) {
							tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef,
							                                                            idx);
							if (!tIOHIDElementRef) {
								continue;                                       // skip this element
							}

							uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
							uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
							if ((inHIDInfoPtr->element.usage == usage) &&
							    (inHIDInfoPtr->element.usagePage == usagePage))
							{
								foundIOHIDElementRef = tIOHIDElementRef;
							}
							if (foundIOHIDElementRef) {
								break;
							}
						}                                                       // next idx
					}                                                           // if (!foundIOHIDElementRef)
					if (foundIOHIDElementRef) {                                 // if same device
						                                                        // setup the calibration
						IOHIDElement_SetupCalibration(tIOHIDElementRef);
						IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef,
						                                         inHIDInfoPtr->element.minReport);
						IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef,
						                                         inHIDInfoPtr->element.maxReport);
					}

					CFRelease(elementCFArrayRef);
				}                                                               // if (elementCFArrayRef)
			}                                                                   // if (foundIOHIDDeviceRef)
		}                                                                       // if (device not found & vendorID & productID)
	}                                                                           // if (inHIDInfoPtr->locID &&
	                                                                            // inHIDInfoPtr->device.vendorID &&
	                                                                            // inHIDInfoPtr->device.productID)
	                                                                            // can't find matching device return NULL, do not
	                                                                            // return first device
	if ((!foundIOHIDDeviceRef) ||
	    (!foundIOHIDElementRef))
	{
		// no HID device
		*outIOHIDDeviceRef = NULL;
		*outIOHIDElementRef = NULL;

		return (inHIDInfoPtr->actionCookie);
	} else {
		// HID device
		*outIOHIDDeviceRef = foundIOHIDDeviceRef;
		*outIOHIDElementRef = foundIOHIDElementRef;

		return (inHIDInfoPtr->actionCookie);
	}
}                                                                               // HIDGetElementConfig
Esempio n. 24
0
// get the first element of device passed in as parameter
// returns NULL if no list exists or device does not exists or is NULL
IOHIDElementRef HIDGetFirstDeviceElement( IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask )
{
	IOHIDElementRef result = NULL;

	if ( inIOHIDDeviceRef ) {
		assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef ) );

		gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone );

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

				if ( !tIOHIDElementRef ) {
					continue;
				}

				IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
				switch ( type ) {
					case kIOHIDElementTypeInput_Misc:
					case kIOHIDElementTypeInput_Button:
					case kIOHIDElementTypeInput_Axis:
					case kIOHIDElementTypeInput_ScanCodes:
					{
						if ( typeMask & kHIDElementTypeInput ) {
							result = tIOHIDElementRef;
						}
						break;
					}

					case kIOHIDElementTypeOutput:
					{
						if ( typeMask & kHIDElementTypeOutput ) {
							result = tIOHIDElementRef;
						}
						break;
					}

					case kIOHIDElementTypeFeature:
					{
						if ( typeMask & kHIDElementTypeFeature ) {
							result = tIOHIDElementRef;
						}
						break;
					}

					case kIOHIDElementTypeCollection:
					{
						if ( typeMask & kHIDElementTypeCollection ) {
							result = tIOHIDElementRef;
						}
						break;
					}
				}           // switch ( type )

				if ( result ) {
					break;  // DONE!
				}
			}               // next idx
			CFRelease( gElementCFArrayRef );
			gElementCFArrayRef = NULL;
		}                   // 		if ( gElementCFArrayRef )
	}                       // 	if ( inIOHIDDeviceRef )
	return result;
} /* HIDGetFirstDeviceElement */
Esempio n. 25
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;
}
Esempio n. 26
0
// get next element of given device in list given current element as parameter
// will walk down each collection then to next element or collection (depthwise traverse)
// returns NULL if end of list
// uses mask of HIDElementTypeMask to restrict element found
// use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality
IOHIDElementRef HIDGetNextDeviceElement( IOHIDElementRef inIOHIDElementRef, HIDElementTypeMask typeMask )
{
	IOHIDElementRef result = NULL;

	if ( inIOHIDElementRef ) {
		assert( IOHIDElementGetTypeID() == CFGetTypeID( inIOHIDElementRef ) );

		IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice( inIOHIDElementRef );

		if ( tIOHIDDeviceRef ) {
			Boolean found = FALSE;

			gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone );

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

					if ( !tIOHIDElementRef ) {
						continue;
					}

					if ( !found ) {
						if ( inIOHIDElementRef == tIOHIDElementRef ) {
							found = TRUE;
						}
						continue;   // next element
					} else {
						// we've found the current element; now find the next one of the right type
						IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
						switch ( type ) {
							case kIOHIDElementTypeInput_Misc:
							case kIOHIDElementTypeInput_Button:
							case kIOHIDElementTypeInput_Axis:
							case kIOHIDElementTypeInput_ScanCodes:
							{
								if ( typeMask & kHIDElementTypeInput ) {
									result = tIOHIDElementRef;
								}
								break;
							}

							case kIOHIDElementTypeOutput:
							{
								if ( typeMask & kHIDElementTypeOutput ) {
									result = tIOHIDElementRef;
								}
								break;
							}

							case kIOHIDElementTypeFeature:
							{
								if ( typeMask & kHIDElementTypeFeature ) {
									result = tIOHIDElementRef;
								}
								break;
							}

							case kIOHIDElementTypeCollection:
							{
								if ( typeMask & kHIDElementTypeCollection ) {
									result = tIOHIDElementRef;
								}
								break;
							}
						}           // switch ( type )

						if ( result ) {
							break;  // DONE!
						}
					}               // if ( !found )
				}                   // next idx
				CFRelease( gElementCFArrayRef );
				gElementCFArrayRef = NULL;
			}                       // 		if ( gElementCFArrayRef )
		}                           // 	if ( inIOHIDDeviceRef )
	}                               // 	if ( inIOHIDElementRef )
	return result;
} /* HIDGetNextDeviceElement */
Esempio n. 27
0
static void __deviceCallback(void * context, IOReturn result, void * sender, IOHIDDeviceRef device)
{
    boolean_t   terminated  = context == 0;
    CFStringRef debugString = CFCopyDescription(device);
    char * c_debug_string = NULL;
    
    if( debugString ){
        // DG: Bluetooth "Product" strings have Unicode encoding and no nul terminator and CFStringGetCStringPtr returns NULL
        // Need to manually copy to C string
        CFIndex length = CFStringGetLength(debugString);
        CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, CFStringGetSystemEncoding()) + 1;
        c_debug_string = (char *)malloc(maxSize);
        CFStringGetCString(debugString, c_debug_string, maxSize, CFStringGetSystemEncoding());
        CFRelease(debugString);
    }
    
    static CFMutableDictionaryRef s_timers = NULL;
    
    if ( !s_timers )
        s_timers = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    
    uint64_t uuid = 0;
    CFNumberRef temp = IOHIDDeviceGetProperty( device, CFSTR(kIOHIDUniqueIDKey) );
    if ( temp && CFGetTypeID(temp)  == CFNumberGetTypeID() ) CFNumberGetValue( temp, kCFNumberLongLongType, &uuid );
    CFNumberGetValue( IOHIDDeviceGetProperty( device, CFSTR(kIOHIDUniqueIDKey) ), kCFNumberLongLongType, &uuid );
    
    printf("%-10.10s: %s UniqueID %llu\n", terminated ? "terminated" : "matched", c_debug_string ? c_debug_string : "", uuid );
    
    if ( c_debug_string )
        free(c_debug_string);
    
    if ( terminated ) {
        CFDictionaryRemoveValue(gOutputElements, device);
        
        
        CFRunLoopTimerRef timer = (CFRunLoopTimerRef)CFDictionaryGetValue(s_timers, device);
        if ( timer ) {
            CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
        }
        CFDictionaryRemoveValue(s_timers, device);
        
    } else {
        CFArrayRef              outputElements  = NULL;
        CFMutableDictionaryRef  matching        = NULL;
        
        if ( gPrintDescriptor ) {
            CFDataRef descriptor = NULL;
            
            descriptor = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDReportDescriptorKey));
            if ( descriptor ) {
                PrintHIDDescriptor(CFDataGetBytePtr(descriptor), CFDataGetLength(descriptor));
            }
        }
        
        if ( gPollInterval != 0.0 ) {
            CFRunLoopTimerContext   context = {.info=device};
            CFRunLoopTimerRef       timer   = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), gPollInterval, 0, 0, __timerCallback, &context);
            
            CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
            
            CFDictionaryAddValue(s_timers, device, timer);
            CFRelease(timer);
            
            printf("Adding polling timer @ %4.6f s\n", gPollInterval);
        }
        
        matching = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        if ( matching ) {
            uint32_t    value   = kIOHIDElementTypeOutput;
            CFNumberRef number  = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
            
            if ( number ) {
                CFDictionarySetValue(matching, CFSTR(kIOHIDElementTypeKey), number);
                
                outputElements = IOHIDDeviceCopyMatchingElements(device, matching, 0);
                if ( outputElements ) {
                    CFDictionarySetValue(gOutputElements, device, outputElements);
                    CFRelease(outputElements);
                }
                
                CFRelease(number);
            }
            CFRelease(matching);
        }
    }
Esempio n. 28
0
  void
  osxHIDInputDevice::AddDevice(void *context,
			       IOReturn /*result*/, void */*sender*/, IOHIDDeviceRef device) {
    osxHIDInputDevice *self = (osxHIDInputDevice*)context ;

    URI devUri = hidDeviceURI(device) ;

    // std::cerr << std::endl << self->uri.asString() << std::endl << devUri.asString() << std::endl << std::endl ;

    bool match = self->theDevice==0 && (self->uri.isEmpty() || self->uri.scheme=="any" || self->uri.resemble(devUri)) ;
    if (self->debugLevel>0) {
      std::cerr << (match?"+ ":"  ") ;
      hidDebugDevice(device, std::cerr) ;
      std::cerr << std::endl ;
    }
    if (!match) return ;

    self->theDevice = new __device(device) ;
    self->uri = devUri ;

    CFDataRef descriptor = (CFDataRef)IOHIDDeviceGetProperty(self->theDevice->device, CFSTR(kIOHIDReportDescriptorKey)) ;
    if (descriptor) {
      const UInt8 *bytes = CFDataGetBytePtr(descriptor) ;
      CFIndex length = CFDataGetLength(descriptor) ;
      if (self->inputreport_callback && !self->parser->setDescriptor(bytes, length))
        std::cerr << "osxHIDInputDevice::AddDevice: unable to parse the HID report descriptor" << std::endl;
      if (self->debugLevel > 1) {
        std::cerr << "    HID report descriptor: [ " << std::flush ;
        for (int i=0; i<length; ++i)
          std::cerr << std::hex << std::setfill('0') << std::setw(2) << (int)bytes[i] << " " ;
        std::cerr << "]" << std::endl ;
      }
    }

#if DEBUG_MODE
      std::cerr << "Setting up callbacks" << std::endl ;
#endif

    // ----------------------------------------------------------------
    
    if (self->inputreport_callback) {
#if DEBUG_MODE
      std::cerr << "Setting up report callback" << std::endl ;
#endif
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
      IOHIDDeviceRegisterInputReportWithTimeStampCallback(device,
					     self->theDevice->report, sizeof(self->theDevice->report),
					     self->inputreport_callback, self->inputreport_context) ;
#else
      IOHIDDeviceRegisterInputReportCallback(device,
					     self->theDevice->report, sizeof(self->theDevice->report),
					     self->inputreport_callback, self->inputreport_context) ;
#endif
    }

    // ----------------------------------------------------------------
    
    if (self->value_callback) {
#if DEBUG_MODE
      std::cerr << "Setting up value callback" << std::endl ;
#endif     
      IOHIDDeviceSetInputValueMatchingMultiple(device, self->elements_match) ; 
      IOHIDDeviceRegisterInputValueCallback(device, self->value_callback, self->value_context) ;
    }

    // ----------------------------------------------------------------
    
    if (self->queue_callback) {
#if DEBUG_MODE
      std::cerr << "Setting up queue callback" << std::endl ;
#endif
      self->theDevice->queue = IOHIDQueueCreate(kCFAllocatorDefault, device, queueSize, kIOHIDOptionsTypeNone) ;
      if (self->elements_match) {
#if DEBUG && DEBUG_MATCHING_ELEMENTS	
	std::cerr << "Queue, elements_match" << std::endl ;
#endif
	CFIndex mcount = CFArrayGetCount(self->elements_match) ;
	for (CFIndex mindex=0; mindex<mcount; ++mindex) {
	  CFDictionaryRef matching = (CFDictionaryRef)CFArrayGetValueAtIndex(self->elements_match, mindex) ;
	  CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, matching, kIOHIDOptionsTypeNone) ;
	  if (!elements) continue ;
	  CFIndex ecount = CFArrayGetCount(elements) ;
	  for (CFIndex eindex=0; eindex<ecount; ++eindex) {
	    IOHIDElementRef e = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, eindex) ;
	    IOHIDQueueAddElement(self->theDevice->queue, e) ;
#if DEBUG && DEBUG_MATCHING_ELEMENTS
	    std::cerr << "elements_match EINDEX: " << eindex
		      << ", usagepage: " << IOHIDElementGetUsagePage(e)
		      << ", usage: " << IOHIDElementGetUsage(e)
		      << std::endl ;
#endif
	  }
	}
      } else {
#if DEBUG && DEBUG_MATCHING_ELEMENTS	
	std::cerr << "Queue, no elements_match" << std::endl ;
#endif
	CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, 0, kIOHIDOptionsTypeNone) ;
	if (elements) {
	  CFIndex ecount = CFArrayGetCount(elements) ;
	  for (CFIndex eindex=0; eindex<ecount; ++eindex) {
	    IOHIDElementRef e = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, eindex) ;
	    IOHIDQueueAddElement(self->theDevice->queue, e) ;
#if DEBUG && DEBUG_MATCHING_ELEMENTS
	    std::cerr << "!elements_match EINDEX: " << eindex
		      << ", usagepage: " << IOHIDElementGetUsagePage(e)
		      << ", usage: " << IOHIDElementGetUsage(e)
		      << std::endl ;
#endif
	  }
	}
      }
      IOHIDQueueRegisterValueAvailableCallback(self->theDevice->queue, self->queue_callback, self->queue_context) ;
      IOHIDQueueScheduleWithRunLoop(self->theDevice->queue, CFRunLoopGetMain(), kCFRunLoopDefaultMode) ;
      IOHIDQueueStart(self->theDevice->queue) ;
    }

    // ----------------------------------------------------------------
  }
Boolean HIDConfigureAction( IOHIDDeviceRef* outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float inTimeout )
{
	// param error?
	if ( !outIOHIDDeviceRef || !outIOHIDElementRef ) {
		return 0;
	}
	
	if ( !gDeviceCFArrayRef ) { // if we do not have a device list
		// and  we can't build another list
		if ( !HIDBuildDeviceList( 0, 0 ) || !gDeviceCFArrayRef ) {
			return FALSE;	// bail
		}
	}
	
	IOHIDDeviceRef tIOHIDDeviceRef;	
	IOHIDElementRef tIOHIDElementRef;	
	
	// remember when we start; used to calculate timeout
	clock_t start = clock(), end;
	
	// determine the maximum number of elements
	CFIndex maxElements = 0;
	CFIndex devIndex, devCount = CFArrayGetCount( gDeviceCFArrayRef );
	for ( devIndex = 0; devIndex < devCount; devIndex++ ) {
		tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, devIndex );
		
		if ( !tIOHIDDeviceRef ) {
			continue;               // skip this one
		}
		
		UInt32 count = HIDCountDeviceElements( tIOHIDDeviceRef, kHIDElementTypeInput );
		if ( count > maxElements ) {
			maxElements = count;
		}
	}
	
	// allocate an array of int's in which to store devCount * maxElements values
	double* saveValueArray = ( double * ) calloc( devCount * maxElements, sizeof( double ) ); // clear 2D array to save values
	
	// on first pass store initial values / compare current values to initial values on subsequent passes
	Boolean found = FALSE, first = TRUE;
	while ( !found ) {
		double maxDeltaPercent = 0;	// we want to find the one that moves the most ( percentage wise )
		for ( devIndex = 0; devIndex < devCount; devIndex++ ) {
			IOHIDDeviceRef tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, devIndex );
			
			if ( !tIOHIDDeviceRef ) {
				continue;                       // skip this one
			}
#ifdef DEBUG
			long vendorID = IOHIDDevice_GetVendorID( tIOHIDDeviceRef );
			long productID = IOHIDDevice_GetProductID( tIOHIDDeviceRef );
#endif
			gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone );
			
			if ( gElementCFArrayRef ) {
				CFIndex eleIndex, eleCount = CFArrayGetCount( gElementCFArrayRef );
				for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) {
					tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, eleIndex );
					
					if ( !tIOHIDElementRef ) {
						continue;
					}
					
					IOHIDElementType tIOHIDElementType = IOHIDElementGetType( tIOHIDElementRef );
					
					// only care about inputs (no outputs or features)
					if ( tIOHIDElementType <= kIOHIDElementTypeInput_ScanCodes ) {

						if ( IOHIDElementIsArray( tIOHIDElementRef ) ) {
							//printf( "ARRAY!\n" );
							continue;	// skip array elements
						}
						uint32_t usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
						uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
						uint32_t reportCount = IOHIDElementGetReportCount( tIOHIDElementRef );
#ifdef DEBUG
						if ( first ) {
							IOHIDElementCookie cookie = IOHIDElementGetCookie( tIOHIDElementRef );
							printf( "%s, dev: {ref:%p, ven: 0x%08lX, pro: 0x%08lX}, ele: {ref:%p, cookie: %p, usage:%04lX:%08lX}\n",
								   __PRETTY_FUNCTION__,
								   tIOHIDDeviceRef,
								   vendorID,
								   productID,
								   tIOHIDElementRef,
								   cookie,
								   (long unsigned int) usagePage,
								   (long unsigned int) usage ); fflush( stdout );
							
							if ( ( 0x054C == vendorID ) && ( 0x0268 == productID ) && ( 0x001E == (UInt32) cookie ) ) {
								//printf( "DING!\n" );
							}
						}
#endif
#if 1					// work-around for IOHIDValueGetScaledValue crash (when element report count > 1)
						if ( reportCount > 1 ) {
							//printf( "REPORT!\n" );
							continue; // skip reports
						}
#endif					
						// ignore PID elements and arrays
						if ( ( kHIDPage_PID != usagePage ) && ( -1 != usage ) ) {
							// get this elements current value
							double value = 0.0;	// default value is zero
							IOHIDValueRef tIOHIDValueRef;
							IOReturn ioReturn = IOHIDDeviceGetValue( tIOHIDDeviceRef, tIOHIDElementRef, &tIOHIDValueRef );
							if ( kIOReturnSuccess == ioReturn ) {
								value = IOHIDValueGetScaledValue( tIOHIDValueRef, kIOHIDValueScaleTypePhysical );
							}
							
							if ( first ) {
								saveValueArray[( devIndex * maxElements ) + eleIndex] = value;
							} else {
								double initialValue = saveValueArray[( devIndex * maxElements ) + eleIndex];
								
								CFIndex valueMin = IOHIDElementGetPhysicalMin( tIOHIDElementRef );
								CFIndex valueMax = IOHIDElementGetPhysicalMax( tIOHIDElementRef );
								
								double deltaPercent = fabs( ( initialValue - value ) * 100.0 / (valueMax - valueMin) );
#if 0
								if ( !first ) {
								// Device: 0x13b6a0 = { Logitech Inc. - WingMan Force 3D, 	vendorID:	0x046D, 	productID:	0xC283, usage: 0x0001:0x0004, "Generic Desktop Joystick"
									if ( ( vendorID == 0x046D ) && ( productID == 0xC283 ) ) {
										if ( ( kHIDPage_GenericDesktop == usagePage ) && ( kHIDUsage_GD_Rz == usage ) ) {
											printf( "initial: %6.2f, value: %6.2f, diff: %6.2f, delta percent: %6.2f!\n", initialValue, value, fabs( initialValue - value ), deltaPercent );
										}
									}
								}
								deltaPercent = 0.0;
#endif
								if ( deltaPercent >= kPercentMove ) {
									found = TRUE;
									if ( deltaPercent > maxDeltaPercent ) {
										maxDeltaPercent = deltaPercent;
										
										*outIOHIDDeviceRef = tIOHIDDeviceRef;
										*outIOHIDElementRef = tIOHIDElementRef;
									}
									break;
								}
							}   // if first
						}       // if usage
					}           // if type
				}               // for elements...
				CFRelease( gElementCFArrayRef );
				gElementCFArrayRef = NULL;
			}	// if ( gElementCFArrayRef )
			if ( found ) {
				// HIDDumpElementInfo( tIOHIDElementRef );
				break; // DONE!
			}
		}                   // for devices
		
		first = FALSE;          // no longer the first pass
		
		// are we done?
		end = clock();
		double secs = (double)( end - start ) / CLOCKS_PER_SEC;
		
		if ( secs > inTimeout ) {
			break;              // ( yes ) timeout
		}
	}	//	while ( !found )
	
	// return device and element moved
	if ( !found ) {
		*outIOHIDDeviceRef = NULL;
		*outIOHIDElementRef = NULL;
	}
	return found;
}   // HIDConfigureAction
Esempio n. 30
0
static void iohidmanager_hid_device_add(void *data, IOReturn result,
      void* sender, IOHIDDeviceRef device)
{
   int i;
   IOReturn ret;
   uint16_t dev_vid, dev_pid;
   CFArrayRef elements_raw;
   int count;
   CFMutableArrayRef elements;
   CFRange range;
   bool found_axis[6] =
   { false, false, false, false, false, false };
   apple_input_rec_t *tmp                   = NULL;
   apple_input_rec_t *tmpButtons            = NULL;
   apple_input_rec_t *tmpAxes               = NULL;
   iohidmanager_hid_t                  *hid = (iohidmanager_hid_t*)
      hid_driver_get_data();
   struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)
      calloc(1, sizeof(*adapter));

   if (!adapter)
      return;
   if (!hid)
      goto error;

   adapter->handle        = device;

   ret = IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone);

   if (ret != kIOReturnSuccess)
      goto error;

   /* Move the device's run loop to this thread. */
   IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(),
         kCFRunLoopCommonModes);
   IOHIDDeviceRegisterRemovalCallback(device,
         iohidmanager_hid_device_remove, adapter);

#ifndef IOS
   iohidmanager_hid_device_get_product_string(device, adapter->name,
         sizeof(adapter->name));
#endif

   dev_vid = iohidmanager_hid_device_get_vendor_id  (device);
   dev_pid = iohidmanager_hid_device_get_product_id (device);

   adapter->slot = pad_connection_pad_init(hid->slots,
         adapter->name, dev_vid, dev_pid, adapter,
         &iohidmanager_hid);

   if (adapter->slot == -1)
      goto error;

   if (pad_connection_has_interface(hid->slots, adapter->slot))
      IOHIDDeviceRegisterInputReportCallback(device,
            adapter->data + 1, sizeof(adapter->data) - 1,
            iohidmanager_hid_device_report, adapter);
   else
      IOHIDDeviceRegisterInputValueCallback(device,
            iohidmanager_hid_device_input_callback, adapter);

   if (string_is_empty(adapter->name))
      goto error;

   /* scan for buttons, axis, hats */
   elements_raw = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
   count        = (int)CFArrayGetCount(elements_raw);
   elements     = CFArrayCreateMutableCopy(
         kCFAllocatorDefault,(CFIndex)count,elements_raw);
   range        = CFRangeMake(0,count);

   CFArraySortValues(elements,
         range, iohidmanager_sort_elements, NULL);

   for (i = 0; i < count; i++)
   {
      IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);

      if (!element)
         continue;

      IOHIDElementType type = IOHIDElementGetType(element);
      uint32_t page         = (uint32_t)IOHIDElementGetUsagePage(element);
      uint32_t use          = (uint32_t)IOHIDElementGetUsage(element);
      uint32_t cookie       = (uint32_t)IOHIDElementGetCookie(element);

      int detected_button = 0;

      switch (page)
      {
         case kHIDPage_GenericDesktop:
            switch (type)
            {
               case kIOHIDElementTypeCollection:
               case kIOHIDElementTypeInput_ScanCodes:
               case kIOHIDElementTypeFeature:
               case kIOHIDElementTypeInput_Button:
               case kIOHIDElementTypeOutput:
               case kIOHIDElementTypeInput_Axis:
                  /* TODO/FIXME */
                  break;
               case kIOHIDElementTypeInput_Misc:
                  switch (use)
                  {
                     case kHIDUsage_GD_Hatswitch:
                        {
                           /* as far as I can tell, OSX only reports one Hat */
                           apple_input_rec_t *hat = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
                           hat->id                = 0;
                           hat->cookie            = (IOHIDElementCookie)cookie;
                           hat->next              = NULL;
                           adapter->hats          = hat;
                        }
                        break;
                     default:
                        {
                           uint32_t i = 0;
                           static const uint32_t axis_use_ids[6] =
                           { 48, 49, 51, 52, 50, 53 };

                           while (i < 6 && axis_use_ids[i] != use)
                              i++;

                           if (i < 6)
                           {

                              apple_input_rec_t *axis = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
                              axis->id                = i;
                              axis->cookie            = (IOHIDElementCookie)cookie;
                              axis->next              = NULL;

                              if(iohidmanager_check_for_id(adapter->axes,i))
                              {
                                 /* axis ID already exists, save to tmp for appending later */
                                 if(tmpAxes)
                                    iohidmanager_append_record(tmpAxes, axis);
                                 else
                                    tmpAxes = axis;
                              }
                              else
                              {
                                 found_axis[axis->id] = true;
                                 if(adapter->axes)
                                    iohidmanager_append_record(adapter->axes, axis);
                                 else
                                    adapter->axes = axis;
                              }
                           }
                           else
                              detected_button = 1;
                        }
                        break;
                  }
                  break;
            }
            break;
         case kHIDPage_Consumer:
         case kHIDPage_Button:
            switch (type)
            {
               case kIOHIDElementTypeCollection:
               case kIOHIDElementTypeFeature:
               case kIOHIDElementTypeInput_ScanCodes:
               case kIOHIDElementTypeInput_Axis:
               case kIOHIDElementTypeOutput:
                  /* TODO/FIXME */
                  break;
               case kIOHIDElementTypeInput_Misc:
               case kIOHIDElementTypeInput_Button:
                  detected_button = 1;
                  break;
            }
            break;
      }

      if (detected_button)
      {
         apple_input_rec_t *btn = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
         btn->id                = (uint32_t)use;
         btn->cookie            = (IOHIDElementCookie)cookie;
         btn->next              = NULL;

         if(iohidmanager_check_for_id(adapter->buttons,btn->id))
         {
            if(tmpButtons)
               iohidmanager_append_record_ordered(&tmpButtons, btn);
            else
               tmpButtons = btn;
         }
         else
         {
            if(adapter->buttons)
               iohidmanager_append_record_ordered(&adapter->buttons, btn);
            else
               adapter->buttons = btn;
         }
      }
   }

   /* take care of buttons/axes with duplicate 'use' values */
   for (i = 0; i < 6; i++)
   {
      if(found_axis[i] == false && tmpAxes)
      {
         apple_input_rec_t *next = tmpAxes->next;
         tmpAxes->id             = i;
         tmpAxes->next           = NULL;
         iohidmanager_append_record(adapter->axes, tmpAxes);
         tmpAxes = next;
      }
   }

   tmp = adapter->buttons;

   if (tmp)
   {
      while(tmp->next)
         tmp = tmp->next;
   }

   while(tmpButtons)
   {
      apple_input_rec_t *next = tmpButtons->next;

      tmpButtons->id          = tmp->id;
      tmpButtons->next        = NULL;
      tmp->next               = tmpButtons;

      tmp                     = tmp->next;
      tmpButtons              = next;
   }


   iohidmanager_hid_device_add_autodetect(adapter->slot,
         adapter->name, iohidmanager_hid.ident, dev_vid, dev_pid);

   return;

error:
   {
      apple_input_rec_t *tmp = NULL;
      while(adapter->hats != NULL)
      {
         tmp           = adapter->hats;
         adapter->hats = adapter->hats->next;
         free(tmp);
      }
      while(adapter->axes != NULL)
      {
         tmp           = adapter->axes;
         adapter->axes = adapter->axes->next;
         free(tmp);
      }
      while(adapter->buttons != NULL)
      {
         tmp              = adapter->buttons;
         adapter->buttons = adapter->buttons->next;
         free(tmp);
      }
      while(tmpAxes != NULL)
      {
         tmp     = tmpAxes;
         tmpAxes = tmpAxes->next;
         free(tmp);
      }
      while(tmpButtons != NULL)
      {
         tmp        = tmpButtons;
         tmpButtons = tmpButtons->next;
         free(tmp);
      }
      free(adapter);
   }
}