Example #1
0
// NOTE: I pieced this together through trial and error, any corrections are welcome
static void hid_device_input_callback(void* context, IOReturn result, void* sender, IOHIDValueRef value)
{
    IOHIDElementRef element;
    uint32_t type, page, use;
    struct apple_pad_connection* connection = (struct apple_pad_connection*)context;
    
    element = IOHIDValueGetElement(value);
    type    = IOHIDElementGetType(element);
    page    = IOHIDElementGetUsagePage(element);
    use     = IOHIDElementGetUsage(element);
    
    // Joystick handler: TODO: Can GamePad work the same?
    if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button)
    {
        CFIndex state = IOHIDValueGetIntegerValue(value);
        
        if (state)
            g_current_input_data.pad_buttons[connection->slot] |= (1 << (use - 1));
        else
            g_current_input_data.pad_buttons[connection->slot] &= ~(1 << (use - 1));
    }
    else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop)
    {
        static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };
        int i;
        
        for (i = 0; i < 4; i ++)
        {
            if (use == axis_use_ids[i])
            {
                CFIndex min, max, state;
                float val;
                
                min = IOHIDElementGetPhysicalMin(element);
                max = IOHIDElementGetPhysicalMax(element) - min;
                state = IOHIDValueGetIntegerValue(value) - min;
                
                val = (float)state / (float)max;
                g_current_input_data.pad_axis[connection->slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
            }
        }
    }
}
/**************************************************************************
 *                              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;
}
Example #3
0
bool HIDGamepad::maybeAddButton(IOHIDElementRef element)
{
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    if (usagePage != kHIDPage_Button)
        return false;

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

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

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

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

    return true;
}
Example #4
0
bool HIDGamepad::maybeAddDPad(IOHIDElementRef element)
{
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    if (usagePage != kHIDPage_GenericDesktop)
        return false;

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

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

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

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

    return true;
}
// Put element into the dictionary and into the queue:
PsychError PsychHIDOSKbElementAdd(IOHIDElementRef element, IOHIDQueueRef queue, int deviceIndex)
{
    // If at least one keyboard style device is detected, mark this queue as keyboard queue:
    if (IOHIDElementGetUsagePage(element) == kHIDPage_KeyboardOrKeypad) queueIsAKeyboard[deviceIndex] = TRUE;
    
    // Avoid redundant assignment to same keycode:
    if (IOHIDQueueContainsElement(queue, element)) {
        if (getenv("PSYCHHID_TELLME")) printf("--> Key %i Already assigned --> Skipping.\n", IOHIDElementGetUsage(element) - 1);
        return(PsychError_none);
    }
    
    if (getenv("PSYCHHID_TELLME")) {
        printf("--> Accepting key %i as new KbQueue element%s.\n", IOHIDElementGetUsage(element) - 1, (queueIsAKeyboard) ? " for a keyboard" : "");
    }
    
    // Put the element cookie into the queue:
    IOHIDQueueAddElement(queue, element);
    
    return(PsychError_none);
}
Example #6
0
bool HIDGamepad::maybeAddAxis(IOHIDElementRef element)
{
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    if (usagePage != kHIDPage_GenericDesktop)
        return false;

    uint32_t usage = IOHIDElementGetUsage(element);
    // This range covers the standard axis usages.
    if (usage < kHIDUsage_GD_X || usage > kHIDUsage_GD_Rz)
        return false;

    CFIndex min = IOHIDElementGetPhysicalMin(element);
    CFIndex max = IOHIDElementGetPhysicalMax(element);

    m_axes.append(std::make_unique<HIDGamepadAxis>(min, max, element));

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

    return true;
}
Example #7
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;
		}
	}
}
Example #8
0
void CInputProviderMacOsHid::InputValueCallback(DEVICE_INFO* deviceInfo, IOReturn result, void* sender, IOHIDValueRef valueRef)
{
	if(!OnInput) return;

	IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
	uint32 usagePage = IOHIDElementGetUsagePage(elementRef);
	if(
	    (usagePage != kHIDPage_GenericDesktop) &&
	    (usagePage != kHIDPage_Button))
	{
		return;
	}
	uint32 usage = IOHIDElementGetUsage(elementRef);
	CFIndex value = IOHIDValueGetIntegerValue(valueRef);
	IOHIDElementType type = IOHIDElementGetType(elementRef);
	BINDINGTARGET tgt;
	tgt.providerId = PROVIDER_ID;
	tgt.deviceId = deviceInfo->deviceId;
	tgt.keyId = usage;
	tgt.keyType = GetKeyType(usage, type);
	OnInput(tgt, value);
}
Example #9
0
/* See if we care about this HID element, and if so, note it in our recDevice. */
static void
AddHIDElement(const void *value, void *parameter)
{
    recDevice *pDevice = (recDevice *) parameter;
    IOHIDElementRef refElement = (IOHIDElementRef) value;
    const CFTypeID elementTypeID = refElement ? CFGetTypeID(refElement) : 0;

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

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

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

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

                            default:
                                break;
                        }
                        break;

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

                    default:
                        break;
                }
            }
            break;

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

            default:
                break;
        }

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

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

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

            pDevice->elements++;
        }
    }
}
Example #10
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) ;
    }

    // ----------------------------------------------------------------
  }
Example #11
0
void __deviceValueCallback (void * context, IOReturn result, void * sender, IOHIDValueRef value)
{
    IOHIDElementRef element = IOHIDValueGetElement(value);
    
    printf("IOHIDDeviceRef[%p]: value=%p timestamp=%lld cookie=%d usagePage=0x%02X usage=0x%02X intValue=%ld\n", sender, value, IOHIDValueGetTimeStamp(value), (uint32_t)IOHIDElementGetCookie(element), IOHIDElementGetUsagePage(element), IOHIDElementGetUsage(element), IOHIDValueGetIntegerValue(value));
}
Example #12
0
void joypad::add_hid_element(IOHIDElementRef p_element) {
	const CFTypeID elementTypeID = p_element ? CFGetTypeID(p_element) : 0;

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

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

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

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

							default:
								break;
						}
						break;

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

					default:
						break;
				}
			} break;

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

			default:
				break;
		}

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

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

			element.min = (SInt32)IOHIDElementGetLogicalMin(p_element);
			element.max = (SInt32)IOHIDElementGetLogicalMax(p_element);
			element.cookie = IOHIDElementGetCookie(p_element);
			list->push_back(element);
			list->sort_custom<rec_element::Comparator>();
		}
	}
}
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
Example #14
0
static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
{
    IOHIDElementRef tIOHIDElementRef;
    CFArrayRef      gElementCFArrayRef;
    DWORD           axes = 0;
    DWORD           sliders = 0;
    DWORD           buttons = 0;
    DWORD           povs = 0;

    device->elementCFArrayRef = NULL;

    if (!gCollections)
        return;

    tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, device->id);

    if (!tIOHIDElementRef)
        return;

    gElementCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
    get_element_children(tIOHIDElementRef, gElementCFArrayRef);

    if (gElementCFArrayRef)
    {
        CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
        /* build our element array in the order that dinput expects */
        device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);

        for ( idx = 0; idx < cnt; idx++ )
        {
            IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
            int eleType = IOHIDElementGetType( tIOHIDElementRef );
            switch(eleType)
            {
            case kIOHIDElementTypeInput_Button:
            {
                int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
                if (usagePage != kHIDPage_Button)
                {
                    /* avoid strange elements found on the 360 controller */
                    continue;
                }

                if (buttons < 128)
                {
                    CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
                    buttons++;
                }
                break;
            }
            case kIOHIDElementTypeInput_Axis:
            {
                CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
                axes++;
                break;
            }
            case kIOHIDElementTypeInput_Misc:
            {
                uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
                switch(usage)
                {
                case kHIDUsage_GD_Hatswitch:
                {
                    CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
                    povs++;
                    break;
                }
                case kHIDUsage_GD_Slider:
                    sliders ++;
                    if (sliders > 2)
                        break;
                /* fallthrough, sliders are axis */
                case kHIDUsage_GD_X:
                case kHIDUsage_GD_Y:
                case kHIDUsage_GD_Z:
                case kHIDUsage_GD_Rx:
                case kHIDUsage_GD_Ry:
                case kHIDUsage_GD_Rz:
                {
                    CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
                    axis_map[axes]=usage;
                    axes++;
                    break;
                }
                default:
                    FIXME("Unhandled usage %i\n",usage);
                }
                break;
            }
            default:
                FIXME("Unhandled type %i\n",eleType);
            }
        }
    }

    device->generic.devcaps.dwAxes = axes;
    device->generic.devcaps.dwButtons = buttons;
    device->generic.devcaps.dwPOVs = povs;

    /* Sort buttons into correct order */
    for (buttons = 0; buttons < device->generic.devcaps.dwButtons; buttons++)
    {
        IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elementCFArrayRef, axes+povs+buttons);
        uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
        usage --; /* usage is 1 indexed we need 0 indexed */
        if (usage == buttons)
            continue;

        insert_sort_button(axes+povs, tIOHIDElementRef, device->elementCFArrayRef,buttons,usage);
    }
}
/**************************************************************************
 *                              collect_joystick_elements
 */
static void collect_joystick_elements(joystick_t* joystick, IOHIDElementRef collection)
{
    CFIndex    i, count;
    CFArrayRef children = IOHIDElementGetChildren(collection);

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

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

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

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

                /* avoid strange elements found on the 360 controller */
                if (usage_page == kHIDPage_Button)
                    CFArrayAppendValue(joystick->buttons, child);
                break;
            }
            case kIOHIDElementTypeInput_Axis:
            {
                TRACE("kIOHIDElementTypeInput_Axis; ignoring\n");
                break;
            }
            case kIOHIDElementTypeInput_Misc:
            {
                uint32_t usage = IOHIDElementGetUsage( child );
                switch(usage)
                {
                    case kHIDUsage_GD_Hatswitch:
                    {
                        TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Hatswitch\n");
                        if (joystick->hatswitch)
                            TRACE("    ignoring additional hatswitch\n");
                        else
                            joystick->hatswitch = (IOHIDElementRef)CFRetain(child);
                        break;
                    }
                    case kHIDUsage_GD_X:
                    case kHIDUsage_GD_Y:
                    case kHIDUsage_GD_Z:
                    case kHIDUsage_GD_Rx:
                    case kHIDUsage_GD_Ry:
                    case kHIDUsage_GD_Rz:
                    {
                        int axis = axis_for_usage(usage);
                        TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_<axis> (%d) axis %d\n", usage, axis);
                        if (axis < 0 || joystick->axes[axis].element)
                            TRACE("    ignoring\n");
                        else
                        {
                            joystick->axes[axis].element = (IOHIDElementRef)CFRetain(child);
                            joystick->axes[axis].min_value = IOHIDElementGetLogicalMin(child);
                            joystick->axes[axis].max_value = IOHIDElementGetLogicalMax(child);
                        }
                        break;
                    }
                    case kHIDUsage_GD_Slider:
                        TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Slider; ignoring\n");
                        break;
                    default:
                        FIXME("kIOHIDElementTypeInput_Misc / Unhandled usage %d\n", usage);
                        break;
                }
                break;
            }
            default:
                FIXME("Unhandled type %i\n",type);
                break;
        }
    }
}
PsychError PsychHIDOSKbQueueCreate(int deviceIndex, int numScankeys, int* scanKeys)
{
    pRecDevice deviceRecord;

	// Valid number of keys?
	if (scanKeys && (numScankeys != 256)) {
		PsychErrorExitMsg(PsychError_user, "Second argument to KbQueueCreate must be a vector with 256 elements.");
	}

    // Do we finally have a valid keyboard or other suitable input device?
    // PsychHIDOSGetKbQueueDevice() will error out if no suitable device
    // for deviceIndex can be found. Otherwise it will return the HID
    // device record and remapped deviceIndex for use with our KbQueues:
    deviceIndex = PsychHIDOSGetKbQueueDevice(deviceIndex, &deviceRecord);

	// Keyboard queue for this deviceIndex already created?
	if (psychHIDKbQueueFirstPress[deviceIndex]) {
		// Yep. Release it, so we can start from scratch:
		PsychHIDOSKbQueueRelease(deviceIndex);
	}

	// Allocate and zero-init memory for tracking key presses and key releases:
	psychHIDKbQueueFirstPress[deviceIndex]   = calloc(256, sizeof(double));
	psychHIDKbQueueFirstRelease[deviceIndex] = calloc(256, sizeof(double));
	psychHIDKbQueueLastPress[deviceIndex]    = calloc(256, sizeof(double));
	psychHIDKbQueueLastRelease[deviceIndex]  = calloc(256, sizeof(double));
	psychHIDKbQueueScanKeys[deviceIndex]     = calloc(256, sizeof(int));
    
	// Assign scanKeys vector, if any:
	if (scanKeys) {
		// Copy it:
		memcpy(psychHIDKbQueueScanKeys[deviceIndex], scanKeys, 256 * sizeof(int));
	} else {
		// None provided. Enable all keys by default:
		memset(psychHIDKbQueueScanKeys[deviceIndex], 1, 256 * sizeof(int));        
	}
    
    // Create HIDQueue for device:
    queue[deviceIndex] = IOHIDQueueCreate(kCFAllocatorDefault, deviceRecord, 30, 0);
    if (NULL == queue[deviceIndex]) PsychErrorExitMsg(PsychError_system, "Failed to create event queue for detecting key press.");

    // Mark as a non-keyboard device, to start with:
    queueIsAKeyboard[deviceIndex] = FALSE;

    // Parse HID device to add all detected and selected keys:
    {
        // Add deviceRecord's elements to our queue, filtering unwanted keys via 'scanList'.
        // This code is almost identical to the enumeration code in PsychHIDKbCheck, to make sure we get
        // matching performance and behaviour and hopefully that it works on the latest problematic Apple
        // hardware, e.g., late 2013 MacBookAir and OSX 10.9:
        {
            uint32_t usage, usagePage;
            pRecElement currentElement, lastElement = NULL;
            
            // Step through the elements of the device and add matching ones:
            for (currentElement = HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeInput | kHIDElementTypeCollection);
                 (currentElement != NULL) && (currentElement != lastElement);
                 currentElement = HIDGetNextDeviceElement(currentElement, kHIDElementTypeInput | kHIDElementTypeCollection))
            {
                // Keep track of last queried element:
                lastElement = currentElement;
                
                usage     = IOHIDElementGetUsage(currentElement);
                usagePage = IOHIDElementGetUsagePage(currentElement);
                if (getenv("PSYCHHID_TELLME")) {
                    printf("PTB-DEBUG: [KbQueueCreate]: ce %p page %d usage: %d isArray: %d\n", currentElement, usagePage, usage, IOHIDElementIsArray(currentElement));
                }
                
                if (IOHIDElementGetType(currentElement) == kIOHIDElementTypeCollection) {
                    CFArrayRef children = IOHIDElementGetChildren(currentElement);
                    if (!children) continue;
                    
                    CFIndex idx, cnt = CFArrayGetCount(children);
                    for (idx = 0; idx < cnt; idx++) {
                        IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(children, idx);
                        if (tIOHIDElementRef && ((IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_Button) ||
                                                 (IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_ScanCodes))) {
                            usage = IOHIDElementGetUsage(tIOHIDElementRef);
                            if ((usage <= 256) && (usage >= 1) && ( (scanKeys == NULL) || (scanKeys[usage - 1] > 0) )) {
                                // Add it for use in keyboard queue:
                                PsychHIDOSKbElementAdd(tIOHIDElementRef, queue[deviceIndex], deviceIndex);
                            }
                        }
                    }
                    
                    // Done with this currentElement, which was a collection of buttons/keys.
                    // Iterate to next currentElement:
                    continue;
                }
                
                // Classic path for non-collection elements:
                if(((usagePage == kHIDPage_KeyboardOrKeypad) || (usagePage == kHIDPage_Button)) && (usage <= 256) && (usage >= 1) &&
                   ( (scanKeys == NULL) || (scanKeys[usage - 1] > 0) ) ) {
                    // Add it for use in keyboard queue:
                    PsychHIDOSKbElementAdd(currentElement, queue[deviceIndex], deviceIndex);
                }
            }
        }
    }
    
    // Register "queue empty -> non-empty transition" callback: TODO Replace queue by reference to our keyboard queue struct:
    IOHIDQueueRegisterValueAvailableCallback(queue[deviceIndex], (IOHIDCallback) PsychHIDKbQueueCallbackFunction, (void*) (long) deviceIndex);

	// Create event buffer:
	PsychHIDCreateEventBuffer(deviceIndex);

    // Start the processing thread for this queue:
    PsychLockMutex(&KbQueueMutex);

    if (PsychCreateThread(&KbQueueThread[deviceIndex], NULL, KbQueueWorkerThreadMain, (void*) (long) deviceIndex)) {
        // We are so screwed:

        // Cleanup the mess:
        psychHIDKbQueueActive[deviceIndex] = FALSE;
        PsychUnlockMutex(&KbQueueMutex);

        // Whine a little bit:
        printf("PsychHID-ERROR: Start of keyboard queue processing for deviceIndex %i failed!\n", deviceIndex);
        PsychErrorExitMsg(PsychError_system, "Creation of keyboard queue background processing thread failed!");
    }

    PsychUnlockMutex(&KbQueueMutex);

	// Ready to use this keybord queue.
	return(PsychError_none);
}
static const char* debugstr_element(IOHIDElementRef element)
{
    return wine_dbg_sprintf("<IOHIDElement %p type %d usage %u/%u device %p>", element,
                            IOHIDElementGetType(element), IOHIDElementGetUsagePage(element),
                            IOHIDElementGetUsage(element), IOHIDElementGetDevice(element));
}
// *************************************************************************
//
// 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
Boolean HIDSaveElementPref(const CFStringRef	inKeyCFStringRef,
                           CFStringRef			inAppCFStringRef,
                           IOHIDDeviceRef		inIOHIDDeviceRef,
                           IOHIDElementRef		inIOHIDElementRef) {
	Boolean success = false;

	if (inKeyCFStringRef &&
	    inAppCFStringRef &&
	    inIOHIDDeviceRef &&
	    inIOHIDElementRef)
	{
		uint32_t vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef);
		require(vendorID,
		        Oops);

		uint32_t productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef);
		require(productID,
		        Oops);

		uint32_t locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef);
		require(locID,
		        Oops);

		uint32_t usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef);
		uint32_t usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef);
		if (!usagePage ||
		    !usage)
		{
			usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef);
			usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef);
		}

		require(usagePage &&
		        usage,
		        Oops);

		uint32_t usagePageE = IOHIDElementGetUsagePage(inIOHIDElementRef);
		uint32_t usageE = IOHIDElementGetUsage(inIOHIDElementRef);
		IOHIDElementCookie eleCookie = IOHIDElementGetCookie(inIOHIDElementRef);

		CFStringRef prefCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault,
		                                                       NULL,
		                                                       CFSTR("d:{v:%d, p:%d, l:%d, p:%d, u:%d}, e:{p:%d, u:%d, c:%d}"),
		                                                       vendorID,
		                                                       productID,
		                                                       locID,
		                                                       usagePage,
		                                                       usage,
		                                                       usagePageE,
		                                                       usageE,
		                                                       eleCookie);
		if (prefCFStringRef) {
			CFPreferencesSetAppValue(inKeyCFStringRef,
			                         prefCFStringRef,
			                         inAppCFStringRef);
			CFRelease(prefCFStringRef);
			success = true;
		}
	}

Oops:;

	return (success);
}                                                                               // HIDSaveElementPref
Example #20
0
/*************************************************************************
 *
 * hu_AddDeviceElementToUsageXML( inDevice, inElement )
 *
 * Purpose: add a device and it's elements to our usage( XML ) file
 *
 * Inputs: inDevice		- the device
 *			inElement	- the element
 *
 * Returns: Boolean		- if successful
 */
static Boolean hu_AddDeviceElementToUsageXML(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
	Boolean results = FALSE;
	if ( gUsageCFPropertyListRef ) {
		CFRelease(gUsageCFPropertyListRef);
	}
	
	gUsageCFPropertyListRef =
	hu_XMLLoad(                                 CFSTR(
													  "HID_device_usage_strings"), CFSTR("plist") );
	if ( gUsageCFPropertyListRef ) {
		CFMutableDictionaryRef tCFMutableDictionaryRef =
		CFDictionaryCreateMutableCopy(
									  kCFAllocatorDefault,
									  0,
									  gUsageCFPropertyListRef);
		if ( tCFMutableDictionaryRef ) {
			CFMutableDictionaryRef vendorCFMutableDictionaryRef;
			
			CFMutableDictionaryRef productCFMutableDictionaryRef;
			CFStringRef productKeyCFStringRef;
			
			CFStringRef usageKeyCFStringRef;
			
			// if the vendor dictionary exists...
			long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef);
			CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), vendorID);
			if ( vendorKeyCFStringRef ) {
				if ( CFDictionaryGetValueIfPresent(tCFMutableDictionaryRef, vendorKeyCFStringRef,
				                                   (const void **) &vendorCFMutableDictionaryRef) )
				{
					// ...copy it...
					vendorCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
					                                                             0,
					                                                             vendorCFMutableDictionaryRef);
				} else {        // ...otherwise...
					// ...create it.
					vendorCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault,
					                                                         0,
					                                                         &kCFTypeDictionaryKeyCallBacks,
					                                                         &kCFTypeDictionaryValueCallBacks);
					results = TRUE;
				}
				// if the vendor name key doesn't exist...
				if ( !CFDictionaryContainsKey(vendorCFMutableDictionaryRef, kNameKeyCFStringRef) ) {
					CFStringRef manCFStringRef = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef);
					// ...create it.
					CFDictionaryAddValue(vendorCFMutableDictionaryRef, kNameKeyCFStringRef, manCFStringRef);
					results = TRUE;
				}
				
				// if the product key exists in the vendor dictionary...
				long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef);
				productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), productID);
				if ( CFDictionaryGetValueIfPresent(vendorCFMutableDictionaryRef, productKeyCFStringRef,
				                                   (const void **) &productCFMutableDictionaryRef) )
				{
					// ...copy it...
					productCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
					                                                              0,
					                                                              productCFMutableDictionaryRef);
				} else {        // ...otherwise...
					// ...create it.
					productCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault,
					                                                          0,
					                                                          &kCFTypeDictionaryKeyCallBacks,
					                                                          &kCFTypeDictionaryValueCallBacks);
					results = TRUE;
				}
				// if the product name key doesn't exist...
				if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, kNameKeyCFStringRef) ) {
					CFStringRef productCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef);
					// ...create it.
					CFDictionaryAddValue(productCFMutableDictionaryRef, kNameKeyCFStringRef, productCFStringRef);
					results = TRUE;
				}
				
				// if the usage key doesn't exist in the product dictionary...
				uint32_t usagePage =  IOHIDElementGetUsagePage(inIOHIDElementRef);
				uint32_t usage =      IOHIDElementGetUsagePage(inIOHIDElementRef);
				usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld:%ld"), usagePage, usage);
				if ( usageKeyCFStringRef ) {
					if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, usageKeyCFStringRef) ) {
						// find it's generic name
						CFStringRef usageCFStringRef = HIDCopyUsageName(usagePage, usage);
						if ( usageCFStringRef ) {
							// and add that.
							CFDictionaryAddValue(productCFMutableDictionaryRef, usageKeyCFStringRef, usageCFStringRef);
							results = TRUE;
							CFRelease(usageCFStringRef);
						}
					}
					
					CFRelease(usageKeyCFStringRef);
				}
				if ( vendorCFMutableDictionaryRef ) {
					if ( productCFMutableDictionaryRef ) {
						if ( results ) {
							CFDictionarySetValue(vendorCFMutableDictionaryRef, productKeyCFStringRef, productCFMutableDictionaryRef);
						}
						
						CFRelease(productCFMutableDictionaryRef);
					}
					if ( results ) {
						CFDictionarySetValue(tCFMutableDictionaryRef, vendorKeyCFStringRef, vendorCFMutableDictionaryRef);
					}
					
					CFRelease(vendorCFMutableDictionaryRef);
				}
				
				CFRelease(vendorKeyCFStringRef);
			}
			if ( productKeyCFStringRef ) {
				CFRelease(productKeyCFStringRef);
			}
			if ( results ) {
				hu_XMLSave( tCFMutableDictionaryRef,
						   CFSTR(
								 "HID_device_usage_strings"), CFSTR("plist") );
			}
			
			CFRelease(
					  tCFMutableDictionaryRef);
		}
	}
	
	return (results);
}   // hu_AddDeviceElementToUsageXML
// 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
Example #22
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;
}
Example #23
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;
}
Example #24
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 */
Example #25
0
static void input_callback(void *context, IOReturn result, void *sender, IOHIDValueRef value)
{
	struct input_data *input = (struct input_data*)context;
	IOHIDElementRef elem = IOHIDValueGetElement(value);
	uint32_t page = IOHIDElementGetUsagePage(elem);
	uint32_t usage = IOHIDElementGetUsage(elem);
	uint32_t val = IOHIDValueGetIntegerValue(value);

	if (page == kHIDPage_GenericDesktop)
	{
		if (input->ignore_mouse)
		{
			return;
		}

		switch (usage)
		{
			case kHIDUsage_GD_X:
				pthread_mutex_lock(&input->mouse_mutex);
				input->mouse_x += val;
				pthread_mutex_unlock(&input->mouse_mutex);
				break;
			case kHIDUsage_GD_Y:
				pthread_mutex_lock(&input->mouse_mutex);
				input->mouse_y += val;
				pthread_mutex_unlock(&input->mouse_mutex);
				break;
			case kHIDUsage_GD_Wheel:
				if ((int32_t)val > 0)
				{
					add_to_event_queue(input, K_MWHEELUP, true);
					add_to_event_queue(input, K_MWHEELUP, false);
				}
				else if ((int32_t)val < 0)
				{
					add_to_event_queue(input, K_MWHEELDOWN, true);
					add_to_event_queue(input, K_MWHEELDOWN, false);
				}
				break;
			default:
				break;
		}
	}
	else if (page == kHIDPage_Button)
	{
		if (input->ignore_mouse)
		{
			return;
		}

		if (usage < 1 || usage > 10)
		{
			usage = 10;
		}

		add_to_event_queue(input, K_MOUSE1 + usage - 1, val ? true : false);
	}
	else if (page == kHIDPage_KeyboardOrKeypad)
	{
		if (usage == kHIDUsage_KeyboardLeftGUI)
		{
			input->left_cmd_key_active = val ? true : false;
		}
		else if (usage == kHIDUsage_KeyboardRightGUI)
		{
			input->right_cmd_key_active = val ? true : false;
		}

		if (usage < sizeof(keytable) && (input->left_cmd_key_active || input->right_cmd_key_active))
		{
			if (keytable[usage] == 'c' && val)
			{
				add_to_event_queue(input, K_COPY, true);
				add_to_event_queue(input, K_COPY, false);
			}
			else if (keytable[usage] == 'v' && val)
			{
				add_to_event_queue(input, K_PASTE, true);
				add_to_event_queue(input, K_PASTE, false);
			}

			return;
		}

		if (usage < sizeof(keytable))
		{
			add_to_event_queue(input, keytable[usage], val ? true : false);

			pthread_mutex_lock(&input->key_mutex);

			if (val)
			{
				input->repeatkey = keytable[usage];
				input->nextrepeattime = Sys_IntTime() + input->key_repeat_initial_delay;
			}
			else
			{
				input->repeatkey = 0;
				input->nextrepeattime = 0;
			}

			pthread_mutex_unlock(&input->key_mutex);
		}
	}
	else if (page == 0xFF)
	{
		if (usage == kHIDUsage_KeyboardErrorUndefined)
		{
			input->fn_key_active = val ? true : false;
		}
	}
}
void GamepadManager::onDeviceValueChanged(IOHIDValueRef value)
{
    
    IOHIDElementRef element = IOHIDValueGetElement(value);
    IOHIDDeviceRef device = IOHIDElementGetDevice(element);

    int vendorID = getIntDeviceProperty(device, CFSTR(kIOHIDVendorIDKey));
    int productID = getIntDeviceProperty(device, CFSTR(kIOHIDProductIDKey));
    
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    uint32_t usage = IOHIDElementGetUsage(element);

    // The following controller mapping is based on the Logitech F710, however we use it for
    // all Logitech devices on the assumption that they're likely to share the same mapping.
    if (vendorID == Logitech_F710_VendorID)
    {
        // Logitech F710 mapping.
        if (usagePage == kHIDPage_Button)
        {
            bool buttonState = IOHIDValueGetIntegerValue(value);

            switch(usage)
            {
                case kHIDUsage_Button_1:
                    manipulateBitField(State.Buttons, Gamepad_X, buttonState);
                    break;
                case kHIDUsage_Button_2:
                    manipulateBitField(State.Buttons, Gamepad_A, buttonState);
                    break;
                case kHIDUsage_Button_3:
                    manipulateBitField(State.Buttons, Gamepad_B, buttonState);
                    break;
                case kHIDUsage_Button_4:
                    manipulateBitField(State.Buttons, Gamepad_Y, buttonState);
                    break;
                case 0x05:
                    manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
                    break;
                case 0x06:
                    manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
                    break;
                case 0x07:
                    State.LT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x08:
                    State.RT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x09:
                    manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
                    break;
                case 0x0A:
                    manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
                    break;
                case 0x0B:
                    manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
                    break;
                case 0x0C:
                    manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
                    break;
                default:
                    return;
            }
        }
        else if (usagePage == kHIDPage_GenericDesktop)
        {
            float v;
            switch(usage)
            {
                case kHIDUsage_GD_X:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LX, v))
                        return;
                    break;
                case kHIDUsage_GD_Y:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LY, -v))
                        return;
                    break;
                case kHIDUsage_GD_Z:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RX, v))
                        return;
                    break;
                case kHIDUsage_GD_Rz:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RY, -v))
                        return;
                    break;
                case kHIDUsage_GD_Hatswitch:
                    {
                        CFIndex integerValue = IOHIDValueGetIntegerValue(value);
                 
                        manipulateBitField(State.Buttons,
                                           Gamepad_Up,
                                           integerValue == 7 || integerValue == 0 || integerValue == 1);
                        manipulateBitField(State.Buttons,
                                           Gamepad_Down,
                                           integerValue == 3 || integerValue == 4 || integerValue == 5);
                        manipulateBitField(State.Buttons,
                                           Gamepad_Left,
                                           integerValue == 5 || integerValue == 6 || integerValue == 7);
                        manipulateBitField(State.Buttons,
                                           Gamepad_Right,
                                           integerValue == 1 || integerValue == 2 || integerValue == 3);
                    }
                    break;
                default:
                    return;
            }
        }
    }
    // The following controller mapping is based on the Sony DualShock3, however we use it for
    // all Sony devices on the assumption that they're likely to share the same mapping.
    else if (vendorID == Sony_DualShock3_VendorID)
    {
        // PS3 Controller.
        if (usagePage == kHIDPage_Button)
        {
            bool buttonState = IOHIDValueGetIntegerValue(value);
            
            switch(usage)
            {
                case kHIDUsage_Button_1:
                    manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
                    break;
                case kHIDUsage_Button_2:
                    manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
                    break;
                case kHIDUsage_Button_3:
                    manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
                    break;
                case kHIDUsage_Button_4:
                    manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
                    break;
                case 0x05:
                    manipulateBitField(State.Buttons, Gamepad_Up, buttonState);
                    break;
                case 0x06:
                    manipulateBitField(State.Buttons, Gamepad_Right, buttonState);
                    break;
                case 0x07:
                    manipulateBitField(State.Buttons, Gamepad_Down, buttonState);
                    break;
                case 0x08:
                    manipulateBitField(State.Buttons, Gamepad_Left, buttonState);
                    break;
                case 0x09:
                    State.LT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x0A:
                    State.RT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x0B:
                    manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
                    break;
                case 0x0C:
                    manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
                    break;
                case 0x0D:
                    // PS3 Triangle.
                    manipulateBitField(State.Buttons, Gamepad_TRIANGLE, buttonState);
                    break;
                case 0x0E:
                    // PS3 Circle
                    manipulateBitField(State.Buttons, Gamepad_CIRCLE, buttonState);
                    break;
                case 0x0F:
                    // PS3 Cross
                    manipulateBitField(State.Buttons, Gamepad_CROSS, buttonState);
                    break;
                case 0x10:
                    // PS3 Square
                    manipulateBitField(State.Buttons, Gamepad_SQUARE, buttonState);
                    break;
                default:
                    return;
            }
        }
        else if (usagePage == kHIDPage_GenericDesktop)
        {
            float v;
            switch(usage)
            {
                case kHIDUsage_GD_X:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LX, v))
                        return;
                    break;
                case kHIDUsage_GD_Y:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LY, -v))
                        return;
                    break;
                case kHIDUsage_GD_Z:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RX, v))
                        return;
                    break;
                case kHIDUsage_GD_Rz:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RY, -v))
                        return;
                    break;
                default:
                    return;
            }
        }
    }
    
    bStateChanged = true;
}
Example #27
0
static void apple_hid_device_input_callback(void *data, IOReturn result,
      void* sender, IOHIDValueRef value)
{
   driver_t                  *driver = driver_get_ptr();
   apple_input_data_t         *apple = (apple_input_data_t*)driver->input_data;
   struct apple_hid_adapter *adapter = (struct apple_hid_adapter*)data;
   IOHIDElementRef element           = IOHIDValueGetElement(value);
   uint32_t type                     = IOHIDElementGetType(element);
   uint32_t page                     = IOHIDElementGetUsagePage(element);
   uint32_t use                      = IOHIDElementGetUsage(element);

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

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

   switch (page)
   {
      case kHIDPage_GenericDesktop:
         switch (type)
         {
            case kIOHIDElementTypeInput_Misc:
               switch (use)
               {
                  case kHIDUsage_GD_Hatswitch:
                     break;
                  default:
                     {
                        int i;
                        static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };

                        for (i = 0; i < 4; i ++)
                        {
                           CFIndex min   = IOHIDElementGetPhysicalMin(element);
                           CFIndex max   = IOHIDElementGetPhysicalMax(element) - min;
                           CFIndex state = IOHIDValueGetIntegerValue(value) - min;
                           float val     = (float)state / (float)max;

                           if (use != axis_use_ids[i])
                              continue;

                           apple->axes[adapter->slot][i] =
                              ((val * 2.0f) - 1.0f) * 32767.0f;
                        }
                     }
                     break;
               }
               break;
         }
         break;
      case kHIDPage_Button:
         switch (type)
         {
            case kIOHIDElementTypeInput_Button:
               {
                  CFIndex state = IOHIDValueGetIntegerValue(value);
                  unsigned id = use - 1;

                  if (state)
                     BIT64_SET(apple->buttons[adapter->slot], id);
                  else
                     BIT64_CLEAR(apple->buttons[adapter->slot], id);
               }
               break;
         }
         break;
   }
}
Example #28
0
// utility routine to dump element info
void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef) {
	if (inIOHIDElementRef) {
		printf("    Element: %p = { ", inIOHIDElementRef);
#if false
		IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice(inIOHIDElementRef);
		printf("Device: %p, ", tIOHIDDeviceRef);
#endif // if 0
		IOHIDElementRef parentIOHIDElementRef = IOHIDElementGetParent(inIOHIDElementRef);
		printf("parent: %p, ", parentIOHIDElementRef);
#if false
		CFArrayRef childrenCFArrayRef = IOHIDElementGetChildren(inIOHIDElementRef);
		printf("children: %p: { ", childrenCFArrayRef);
		fflush(stdout);
		CFShow(childrenCFArrayRef);
		fflush(stdout);
		printf(" }, ");
#endif // if 0
		IOHIDElementCookie tIOHIDElementCookie = IOHIDElementGetCookie(inIOHIDElementRef);
		printf("cookie: 0x%08lX, ", (long unsigned int) tIOHIDElementCookie);
		
		IOHIDElementType tIOHIDElementType = IOHIDElementGetType(inIOHIDElementRef);
		
		switch (tIOHIDElementType) {
			case kIOHIDElementTypeInput_Misc:
			{
				printf("type: Misc, ");
				break;
			}
				
			case kIOHIDElementTypeInput_Button:
			{
				printf("type: Button, ");
				break;
			}
				
			case kIOHIDElementTypeInput_Axis:
			{
				printf("type: Axis, ");
				break;
			}
				
			case kIOHIDElementTypeInput_ScanCodes:
			{
				printf("type: ScanCodes, ");
				break;
			}
				
			case kIOHIDElementTypeOutput:
			{
				printf("type: Output, ");
				break;
			}
				
			case kIOHIDElementTypeFeature:
			{
				printf("type: Feature, ");
				break;
			}
				
			case kIOHIDElementTypeCollection:
			{
				IOHIDElementCollectionType tIOHIDElementCollectionType = IOHIDElementGetCollectionType(inIOHIDElementRef);
				
				switch (tIOHIDElementCollectionType) {
					case kIOHIDElementCollectionTypePhysical:
					{
						printf("type: Physical Collection, ");
						break;
					}
						
					case kIOHIDElementCollectionTypeApplication:
					{
						printf("type: Application Collection, ");
						break;
					}
						
					case kIOHIDElementCollectionTypeLogical:
					{
						printf("type: Logical Collection, ");
						break;
					}
						
					case kIOHIDElementCollectionTypeReport:
					{
						printf("type: Report Collection, ");
						break;
					}
						
					case kIOHIDElementCollectionTypeNamedArray:
					{
						printf("type: Named Array Collection, ");
						break;
					}
						
					case kIOHIDElementCollectionTypeUsageSwitch:
					{
						printf("type: Usage Switch Collection, ");
						break;
					}
						
					case kIOHIDElementCollectionTypeUsageModifier:
					{
						printf("type: Usage Modifier Collection, ");
						break;
					}
						
					default:
					{
						printf("type: %p Collection, ", (void *) tIOHIDElementCollectionType);
						break;
					}
				} // switch
				
				break;
			}
				
			default:
			{
				printf("type: %p, ", (void *) tIOHIDElementType);
				break;
			}
		}     /* switch */
		
		uint32_t usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef);
		uint32_t usage     = IOHIDElementGetUsage(inIOHIDElementRef);
		printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage);

		CFStringRef tCFStringRef = HIDCopyUsageName(usagePage, usage);
		if (tCFStringRef) {
			char usageString[256] = "";
			(void) CFStringGetCString(tCFStringRef, usageString, sizeof(usageString), kCFStringEncodingUTF8);
			printf("\"%s\", ", usageString);
			CFRelease(tCFStringRef);
		}

		CFStringRef nameCFStringRef = IOHIDElementGetName(inIOHIDElementRef);
		char        buffer[256];
		if ( nameCFStringRef && CFStringGetCString(nameCFStringRef, buffer, sizeof(buffer), kCFStringEncodingUTF8) ) {
			printf("name: %s, ", buffer);
		}
		
		uint32_t reportID    = IOHIDElementGetReportID(inIOHIDElementRef);
		uint32_t reportSize  = IOHIDElementGetReportSize(inIOHIDElementRef);
		uint32_t reportCount = IOHIDElementGetReportCount(inIOHIDElementRef);
		printf("report: { ID: %lu, Size: %lu, Count: %lu }, ",
		       (long unsigned int) reportID, (long unsigned int) reportSize, (long unsigned int) reportCount);
		
		uint32_t unit    = IOHIDElementGetUnit(inIOHIDElementRef);
		uint32_t unitExp = IOHIDElementGetUnitExponent(inIOHIDElementRef);
		if (unit || unitExp) {
			printf("unit: %lu * 10^%lu, ", (long unsigned int) unit, (long unsigned int) unitExp);
		}
		
		CFIndex logicalMin = IOHIDElementGetLogicalMin(inIOHIDElementRef);
		CFIndex logicalMax = IOHIDElementGetLogicalMax(inIOHIDElementRef);
		if (logicalMin != logicalMax) {
			printf("logical: {min: %ld, max: %ld}, ", logicalMin, logicalMax);
		}
		
		CFIndex physicalMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef);
		CFIndex physicalMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef);
		if (physicalMin != physicalMax) {
			printf("physical: {min: %ld, max: %ld}, ", physicalMin, physicalMax);
		}
		
		Boolean isVirtual = IOHIDElementIsVirtual(inIOHIDElementRef);
		if (isVirtual) {
			printf("isVirtual, ");
		}
		
		Boolean isRelative = IOHIDElementIsRelative(inIOHIDElementRef);
		if (isRelative) {
			printf("isRelative, ");
		}
		
		Boolean isWrapping = IOHIDElementIsWrapping(inIOHIDElementRef);
		if (isWrapping) {
			printf("isWrapping, ");
		}
		
		Boolean isArray = IOHIDElementIsArray(inIOHIDElementRef);
		if (isArray) {
			printf("isArray, ");
		}
		
		Boolean isNonLinear = IOHIDElementIsNonLinear(inIOHIDElementRef);
		if (isNonLinear) {
			printf("isNonLinear, ");
		}
		
		Boolean hasPreferredState = IOHIDElementHasPreferredState(inIOHIDElementRef);
		if (hasPreferredState) {
			printf("hasPreferredState, ");
		}
		
		Boolean hasNullState = IOHIDElementHasNullState(inIOHIDElementRef);
		if (hasNullState) {
			printf("hasNullState, ");
		}
		
		printf(" }\n");
	}
}   // HIDDumpElementInfo
Example #29
0
void Burger::Mouse::InputCallback(void *pData, int iReturn,void * /* pSender */,IOHIDValueRef pValue)
{
	if (iReturn == kIOReturnSuccess) {
		Mouse *pMouse = static_cast<Mouse *>(pData);
		Word uCount = pMouse->m_uMiceCount;
		if (uCount) {
			IOHIDElementRef pElement = IOHIDValueGetElement(pValue);
			IOHIDDeviceRef pDevice = IOHIDElementGetDevice(pElement);
#if 0
			Word uRatNumber = BURGER_MAXUINT;
			const DeviceStruct *pRat = pMouse->m_Mice;
			do {
				if (pRat->m_pDevice == pDevice) {
					uRatNumber = pMouse->m_uMiceCount-uCount;
					break;
				}
				++pRat;
			} while (--uCount);
			if (uRatNumber==BURGER_MAXUINT) {
			}
#endif
			Word32 uTime = static_cast<Word32>(IOHIDValueGetTimeStamp(pValue));
			CFIndex iValue = IOHIDValueGetIntegerValue(pValue);
			
			uint32_t uPage = IOHIDElementGetUsagePage(pElement);
			uint32_t uUsage = IOHIDElementGetUsage(pElement);
			switch (uPage) {
			case kHIDPage_GenericDesktop:
				if (iValue) {
					switch (uUsage) {
					case kHIDUsage_GD_X:
						pMouse->PostMouseMotion(static_cast<Int32>(iValue),0,uTime);
						break;
					case kHIDUsage_GD_Y:
						pMouse->PostMouseMotion(0,static_cast<Int32>(iValue),uTime);
						break;
					case kHIDUsage_GD_Wheel:
						pMouse->PostMouseWheel(0,static_cast<Int32>(iValue),uTime);
						break;
					default:
						printf("Unknown usage %u\n",uUsage);
						break;
					}
				}
				break;
			case kHIDPage_Button:
				// iValue == down
				// Usage = which 1.2.3.4
				if (iValue) {
					pMouse->PostMouseDown(1<<(uUsage-1));
				} else {
					pMouse->PostMouseUp(1<<(uUsage-1));
				}
				break;
				// Ignore this one
			case kHIDPage_Consumer:
				break;
			default:
				printf("Unknown page found %u\n",uPage);
				break;
			}
		}
	}
}
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