diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index 4be016237..716b3e426 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -22,22 +22,7 @@ #ifdef SDL_JOYSTICK_IOKIT -/* SDL joystick driver for Darwin / Mac OS X, based on the IOKit HID API */ -/* Written 2001 by Max Horn */ - -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include /* for NewPtrClear, DisposePtr */ -#include /* For force feedback testing. */ #include @@ -53,75 +38,99 @@ #include "../../events/SDL_events_c.h" #endif +/* The base object of the HID Manager API */ +static IOHIDManagerRef hidman = NULL; /* Linked list of all available devices */ static recDevice *gpDeviceList = NULL; -/* OSX reference to the notification object that tells us about device insertion/removal */ -IONotificationPortRef notificationPort = 0; -/* if 1 then a device was added since the last update call */ + +/* if SDL_TRUE then a device was added since the last update call */ static SDL_bool s_bDeviceAdded = SDL_FALSE; static SDL_bool s_bDeviceRemoved = SDL_FALSE; /* static incrementing counter for new joystick devices seen on the system. Devices should start with index 0 */ static int s_joystick_instance_id = -1; + static void -HIDReportErrorNum(char *strError, long numError) +FreeElementList(recElement *pElement) { - SDL_SetError(strError); + while (pElement) { + recElement *pElementNext = pElement->pNext; + SDL_free(pElement); + pElement = pElementNext; + } } -static void HIDGetCollectionElements(CFMutableDictionaryRef deviceProperties, - recDevice * pDevice); +static recDevice * +FreeDevice(recDevice *removeDevice) +{ + recDevice *pDeviceNext = NULL; + if (removeDevice) { + /* save next device prior to disposing of this device */ + pDeviceNext = removeDevice->pNext; -/* returns current value for element, polling element - * will return 0 on error conditions which should be accounted for by application - */ + if ( gpDeviceList == removeDevice ) { + gpDeviceList = pDeviceNext; + } else { + recDevice *device = gpDeviceList; + while (device->pNext != removeDevice) { + device = device->pNext; + } + device->pNext = pDeviceNext; + } + removeDevice->pNext = NULL; + + /* free element lists */ + FreeElementList(removeDevice->firstAxis); + FreeElementList(removeDevice->firstButton); + FreeElementList(removeDevice->firstHat); + + SDL_free(removeDevice); + } + return pDeviceNext; +} static SInt32 -HIDGetElementValue(recDevice * pDevice, recElement * pElement) +GetHIDElementState(recDevice *pDevice, recElement *pElement) { - IOReturn result = kIOReturnSuccess; - IOHIDEventStruct hidEvent; - hidEvent.value = 0; + SInt32 value = 0; + + if (pDevice && pElement) { + IOHIDValueRef valueRef; + if (IOHIDDeviceGetValue(pDevice->deviceRef, pElement->elementRef, &valueRef) == kIOReturnSuccess) { + value = (SInt32) IOHIDValueGetIntegerValue(valueRef); - if (NULL != pDevice && NULL != pElement && NULL != pDevice->interface) { - result = - (*(pDevice->interface))->getElementValue(pDevice->interface, - pElement->cookie, - &hidEvent); - if (kIOReturnSuccess == result) { /* record min and max for auto calibration */ - if (hidEvent.value < pElement->minReport) - pElement->minReport = hidEvent.value; - if (hidEvent.value > pElement->maxReport) - pElement->maxReport = hidEvent.value; + if (value < pElement->minReport) { + pElement->minReport = value; + } + if (value > pElement->maxReport) { + pElement->maxReport = value; + } } } - /* auto user scale */ - return hidEvent.value; + return value; } static SInt32 -HIDScaledCalibratedValue(recDevice * pDevice, recElement * pElement, - long min, long max) +GetHIDScaledCalibratedState(recDevice * pDevice, recElement * pElement, SInt32 min, SInt32 max) { - float deviceScale = max - min; - float readScale = pElement->maxReport - pElement->minReport; - SInt32 value = HIDGetElementValue(pDevice, pElement); - if (readScale == 0) + const float deviceScale = max - min; + const float readScale = pElement->maxReport - pElement->minReport; + const SInt32 value = GetHIDElementState(pDevice, pElement); + if (readScale == 0) { return value; /* no scaling at all */ - else - return ((value - pElement->minReport) * deviceScale / readScale) + - min; + } + return ((value - pElement->minReport) * deviceScale / readScale) + min; } static void -HIDRemovalCallback(void *target, IOReturn result, void *refcon, void *sender) +JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender) { - recDevice *device = (recDevice *) refcon; + recDevice *device = (recDevice *) ctx; device->removed = 1; #if SDL_HAPTIC_IOKIT MacHaptic_MaybeRemoveDevice(device->ffservice); @@ -130,567 +139,240 @@ HIDRemovalCallback(void *target, IOReturn result, void *refcon, void *sender) } -/* Called by the io port notifier on removal of this device - */ -void JoystickDeviceWasRemovedCallback( void * refcon, io_service_t service, natural_t messageType, void * messageArgument ) -{ - if( messageType == kIOMessageServiceIsTerminated && refcon ) - { - recDevice *device = (recDevice *) refcon; - device->removed = 1; -#if SDL_HAPTIC_IOKIT - MacHaptic_MaybeRemoveDevice(device->ffservice); -#endif - s_bDeviceRemoved = SDL_TRUE; - } -} - - -/* Create and open an interface to device, required prior to extracting values or building queues. - * Note: application now owns the device and must close and release it prior to exiting - */ - -static IOReturn -HIDCreateOpenDeviceInterface(io_object_t hidDevice, recDevice * pDevice) -{ - IOReturn result = kIOReturnSuccess; - HRESULT plugInResult = S_OK; - SInt32 score = 0; - IOCFPlugInInterface **ppPlugInInterface = NULL; - - if (NULL == pDevice->interface) { - result = - IOCreatePlugInInterfaceForService(hidDevice, - kIOHIDDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, - &ppPlugInInterface, &score); - if (kIOReturnSuccess == result) { - /* Call a method of the intermediate plug-in to create the device interface */ - plugInResult = - (*ppPlugInInterface)->QueryInterface(ppPlugInInterface, - CFUUIDGetUUIDBytes - (kIOHIDDeviceInterfaceID), - (void *) - &(pDevice->interface)); - if (S_OK != plugInResult) - HIDReportErrorNum - ("Couldn't query HID class device interface from plugInInterface", - plugInResult); - (*ppPlugInInterface)->Release(ppPlugInInterface); - } else - HIDReportErrorNum - ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", - result); - } - if (NULL != pDevice->interface) { - result = (*(pDevice->interface))->open(pDevice->interface, 0); - if (kIOReturnSuccess != result) - HIDReportErrorNum - ("Failed to open pDevice->interface via open.", result); - else - { - pDevice->portIterator = 0; - - /* It's okay if this fails, we have another detection method below */ - (*(pDevice->interface))->setRemovalCallback(pDevice->interface, - HIDRemovalCallback, - pDevice, pDevice); - - /* now connect notification for new devices */ - pDevice->notificationPort = IONotificationPortCreate(kIOMasterPortDefault); - - CFRunLoopAddSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(pDevice->notificationPort), - kCFRunLoopDefaultMode); - - /* Register for notifications when a serial port is added to the system */ - result = IOServiceAddInterestNotification(pDevice->notificationPort, - hidDevice, - kIOGeneralInterest, - JoystickDeviceWasRemovedCallback, - pDevice, - &pDevice->portIterator); - if (kIOReturnSuccess != result) { - HIDReportErrorNum - ("Failed to register for removal callback.", result); - } - } - - } - return result; -} - -/* Closes and releases interface to device, should be done prior to exiting application - * Note: will have no affect if device or interface do not exist - * application will "own" the device if interface is not closed - * (device may have to be plug and re-plugged in different location to get it working again without a restart) - */ - -static IOReturn -HIDCloseReleaseInterface(recDevice * pDevice) -{ - IOReturn result = kIOReturnSuccess; - - if ((NULL != pDevice) && (NULL != pDevice->interface)) { - /* close the interface */ - result = (*(pDevice->interface))->close(pDevice->interface); - if (kIOReturnNotOpen == result) { - /* do nothing as device was not opened, thus can't be closed */ - } else if (kIOReturnSuccess != result) - HIDReportErrorNum("Failed to close IOHIDDeviceInterface.", - result); - /* release the interface */ - result = (*(pDevice->interface))->Release(pDevice->interface); - if (kIOReturnSuccess != result) - HIDReportErrorNum("Failed to release IOHIDDeviceInterface.", - result); - pDevice->interface = NULL; - - if ( pDevice->portIterator ) - { - IOObjectRelease( pDevice->portIterator ); - pDevice->portIterator = 0; - } - } - return result; -} - -/* extracts actual specific element information from each element CF dictionary entry */ +static void AddHIDElement(const void *value, void *parameter); +/* Call AddHIDElement() on all elements in an array of IOHIDElementRefs */ static void -HIDGetElementInfo(CFTypeRef refElement, recElement * pElement) +AddHIDElements(CFArrayRef array, recDevice *pDevice) { - long number; - CFTypeRef refType; - - refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementCookieKey)); - if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number)) - pElement->cookie = (IOHIDElementCookie) number; - refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMinKey)); - if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number)) - pElement->minReport = pElement->min = number; - pElement->maxReport = pElement->min; - refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMaxKey)); - if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number)) - pElement->maxReport = pElement->max = number; -/* - TODO: maybe should handle the following stuff somehow? - - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey)); - if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) - pElement->scaledMin = number; - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMaxKey)); - if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) - pElement->scaledMax = number; - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementSizeKey)); - if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) - pElement->size = number; - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsRelativeKey)); - if (refType) - pElement->relative = CFBooleanGetValue (refType); - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsWrappingKey)); - if (refType) - pElement->wrapping = CFBooleanGetValue (refType); - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsNonLinearKey)); - if (refType) - pElement->nonLinear = CFBooleanGetValue (refType); - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasPreferedStateKey)); - if (refType) - pElement->preferredState = CFBooleanGetValue (refType); - refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey)); - if (refType) - pElement->nullState = CFBooleanGetValue (refType); -*/ + const CFRange range = { 0, CFArrayGetCount(array) }; + CFArrayApplyFunction(array, range, AddHIDElement, pDevice); } -/* examines CF dictionary value in device element hierarchy to determine if it is element of interest or a collection of more elements - * if element of interest allocate storage, add to list and retrieve element specific info - * if collection then pass on to deconstruction collection into additional individual elements - */ - +/* See if we care about this HID element, and if so, note it in our recDevice. */ static void -HIDAddElement(CFTypeRef refElement, recDevice * pDevice) +AddHIDElement(const void *value, void *parameter) { - recElement *element = NULL; - recElement **headElement = NULL; - long elementType, usagePage, usage; - CFTypeRef refElementType = - CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementTypeKey)); - CFTypeRef refUsagePage = - CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsagePageKey)); - CFTypeRef refUsage = - CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsageKey)); + recDevice *pDevice = (recDevice *) parameter; + IOHIDElementRef refElement = (IOHIDElementRef) value; + const CFTypeID elementTypeID = refElement ? CFGetTypeID(refElement) : 0; + if (refElement && (elementTypeID == IOHIDElementGetTypeID())) { + const uint32_t usagePage = IOHIDElementGetUsagePage(refElement); + const uint32_t usage = IOHIDElementGetUsage(refElement); + recElement *element = NULL; + recElement **headElement = NULL; - if ((refElementType) - && - (CFNumberGetValue(refElementType, kCFNumberLongType, &elementType))) { /* look at types of interest */ - if ((elementType == kIOHIDElementTypeInput_Misc) - || (elementType == kIOHIDElementTypeInput_Button) - || (elementType == kIOHIDElementTypeInput_Axis)) { - if (refUsagePage - && CFNumberGetValue(refUsagePage, kCFNumberLongType, - &usagePage) && refUsage - && CFNumberGetValue(refUsage, kCFNumberLongType, &usage)) { + 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) { /* look at usage to determine function */ - 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: - element = (recElement *) - NewPtrClear(sizeof(recElement)); - if (element) { - pDevice->axes++; - headElement = &(pDevice->firstAxis); - } - break; - case kHIDUsage_GD_Hatswitch: - element = (recElement *) - NewPtrClear(sizeof(recElement)); - if (element) { - pDevice->hats++; - headElement = &(pDevice->firstHat); - } - break; + 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: + element = (recElement *) SDL_calloc(1, sizeof (recElement)); + if (element) { + pDevice->axes++; + headElement = &(pDevice->firstAxis); + } + break; + + case kHIDUsage_GD_Hatswitch: + 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: - element = (recElement *) - NewPtrClear(sizeof(recElement)); - if (element) { - pDevice->axes++; - headElement = &(pDevice->firstAxis); - } - break; + break; - default: - break; - } - break; - case kHIDPage_Button: - element = (recElement *) - NewPtrClear(sizeof(recElement)); - if (element) { - pDevice->buttons++; - headElement = &(pDevice->firstButton); - } - break; - default: - break; + case kHIDPage_Simulation: + switch (usage) { + case kHIDUsage_Sim_Rudder: + case kHIDUsage_Sim_Throttle: + element = (recElement *) SDL_calloc(1, sizeof (recElement)); + if (element) { + pDevice->axes++; + headElement = &(pDevice->firstAxis); + } + break; + + default: + break; + } + break; + + case kHIDPage_Button: + element = (recElement *) SDL_calloc(1, sizeof (recElement)); + if (element) { + pDevice->buttons++; + headElement = &(pDevice->firstButton); + } + break; + + default: + break; } } - } else if (kIOHIDElementTypeCollection == elementType) - HIDGetCollectionElements((CFMutableDictionaryRef) refElement, - pDevice); - } + 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->usagePage = usagePage; - element->usage = usage; - element->pNext = elementCurrent; - HIDGetElementInfo(refElement, element); - pDevice->elements++; - } -} - -/* collects information from each array member in device element list (each array member = element) */ - -static void -HIDGetElementsCFArrayHandler(const void *value, void *parameter) -{ - if (CFGetTypeID(value) == CFDictionaryGetTypeID()) - HIDAddElement((CFTypeRef) value, (recDevice *) parameter); -} - -/* handles retrieval of element information from arrays of elements in device IO registry information */ - -static void -HIDGetElements(CFTypeRef refElementCurrent, recDevice * pDevice) -{ - CFTypeID type = CFGetTypeID(refElementCurrent); - if (type == CFArrayGetTypeID()) { /* if element is an array */ - CFRange range = { 0, CFArrayGetCount(refElementCurrent) }; - /* CountElementsCFArrayHandler called for each array member */ - CFArrayApplyFunction(refElementCurrent, range, - HIDGetElementsCFArrayHandler, pDevice); - } -} - -/* handles extracting element information from element collection CF types - * used from top level element decoding and hierarchy deconstruction to flatten device element list - */ - -static void -HIDGetCollectionElements(CFMutableDictionaryRef deviceProperties, - recDevice * pDevice) -{ - CFTypeRef refElementTop = - CFDictionaryGetValue(deviceProperties, CFSTR(kIOHIDElementKey)); - if (refElementTop) - HIDGetElements(refElementTop, pDevice); -} - -/* use top level element usage page and usage to discern device usage page and usage setting appropriate vlaues in device record */ - -static void -HIDTopLevelElementHandler(const void *value, void *parameter) -{ - CFTypeRef refCF = 0; - if (CFGetTypeID(value) != CFDictionaryGetTypeID()) - return; - refCF = CFDictionaryGetValue(value, CFSTR(kIOHIDElementUsagePageKey)); - if (!CFNumberGetValue - (refCF, kCFNumberLongType, &((recDevice *) parameter)->usagePage)) - SDL_SetError("CFNumberGetValue error retrieving pDevice->usagePage."); - refCF = CFDictionaryGetValue(value, CFSTR(kIOHIDElementUsageKey)); - if (!CFNumberGetValue - (refCF, kCFNumberLongType, &((recDevice *) parameter)->usage)) - SDL_SetError("CFNumberGetValue error retrieving pDevice->usage."); -} - -/* extracts device info from CF dictionary records in IO registry */ - -static void -HIDGetDeviceInfo(io_object_t hidDevice, CFMutableDictionaryRef hidProperties, - recDevice * pDevice) -{ - CFMutableDictionaryRef usbProperties = 0; - io_registry_entry_t parent1, parent2; - - /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also - * get dictionary for USB properties: step up two levels and get CF dictionary for USB properties - */ - if ((KERN_SUCCESS == IORegistryEntryGetParentEntry(hidDevice, kIOServicePlane, &parent1)) - && (KERN_SUCCESS == IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2)) - && (KERN_SUCCESS == IORegistryEntryCreateCFProperties(parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) { - if (usbProperties) { - CFTypeRef refCF = 0; - /* get device info - * try hid dictionary first, if fail then go to usb dictionary - */ - - /* get product name */ - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey)); - if (!refCF) { - refCF = CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name")); - } - if (refCF) { - if (!CFStringGetCString(refCF, pDevice->product, 256, CFStringGetSystemEncoding())) { - SDL_SetError("CFStringGetCString error retrieving pDevice->product."); + #if 0 /* !!! FIXME: this causes everything to get added twice on a DualShock 4. */ + case kIOHIDElementTypeCollection: { + CFArrayRef array = IOHIDElementGetChildren(refElement); + if (array) { + AddHIDElements(array, pDevice); } } + break; + #endif - /* get usage page and usage */ - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); - if (refCF) { - if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage)) { - SDL_SetError("CFNumberGetValue error retrieving pDevice->usagePage."); - } - - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); - if (refCF) { - if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage)) { - SDL_SetError("CFNumberGetValue error retrieving pDevice->usage."); - } - } - } - - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDVendorIDKey)); - if (refCF) { - if (!CFNumberGetValue(refCF, kCFNumberLongType, &pDevice->guid.data[0])) { - SDL_SetError("CFNumberGetValue error retrieving pDevice->guid[0]"); - } - } - - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductIDKey)); - if (refCF) { - if (!CFNumberGetValue(refCF, kCFNumberLongType, &pDevice->guid.data[8])) { - SDL_SetError("CFNumberGetValue error retrieving pDevice->guid[8]"); - } - } - - /* Check to make sure we have a vendor and product ID - If we don't, use the same algorithm as the Linux code for Bluetooth devices */ - { - Uint32 *guid32 = (Uint32*)pDevice->guid.data; - if (!guid32[0] && !guid32[1]) { - const Uint16 BUS_BLUETOOTH = 0x05; - Uint16 *guid16 = (Uint16 *)guid32; - *guid16++ = BUS_BLUETOOTH; - *guid16++ = 0; - SDL_strlcpy((char*)guid16, pDevice->product, sizeof(pDevice->guid.data) - 4); - } - } - - /* If we don't have a vendor and product ID this is probably a Bluetooth device */ - - if (NULL == refCF) { /* get top level element HID usage page or usage */ - /* use top level element instead */ - CFTypeRef refCFTopElement = 0; - refCFTopElement = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDElementKey)); - { - /* refCFTopElement points to an array of element dictionaries */ - CFRange range = { 0, CFArrayGetCount(refCFTopElement) }; - CFArrayApplyFunction(refCFTopElement, range, HIDTopLevelElementHandler, pDevice); - } - } - - CFRelease(usbProperties); - } else { - SDL_SetError("IORegistryEntryCreateCFProperties failed to create usbProperties."); + default: + break; } - if (kIOReturnSuccess != IOObjectRelease(parent2)) { - SDL_SetError("IOObjectRelease error with parent2"); - } - if (kIOReturnSuccess != IOObjectRelease(parent1)) { - SDL_SetError("IOObjectRelease error with parent1"); - } - } -} - - -static recDevice * -HIDBuildDevice(io_object_t hidDevice) -{ - recDevice *pDevice = (recDevice *) NewPtrClear(sizeof(recDevice)); - if (pDevice) { - /* get dictionary for HID properties */ - CFMutableDictionaryRef hidProperties = 0; - kern_return_t result = - IORegistryEntryCreateCFProperties(hidDevice, &hidProperties, - kCFAllocatorDefault, - kNilOptions); - if ((result == KERN_SUCCESS) && hidProperties) { - /* create device interface */ - result = HIDCreateOpenDeviceInterface(hidDevice, pDevice); - if (kIOReturnSuccess == result) { - HIDGetDeviceInfo(hidDevice, hidProperties, pDevice); /* hidDevice used to find parents in registry tree */ - HIDGetCollectionElements(hidProperties, pDevice); + 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 { - DisposePtr((Ptr) pDevice); - pDevice = NULL; + *headElement = element; } - CFRelease(hidProperties); - } else { - DisposePtr((Ptr) pDevice); - pDevice = NULL; + + 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); + + pDevice->elements++; } } - return pDevice; } -/* disposes of the element list associated with a device and the memory associated with the list - */ +static SDL_bool +GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice) +{ + Uint32 *guid32 = NULL; + CFTypeRef refCF = NULL; + CFArrayRef array = NULL; + + /* get usage page and usage */ + refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsagePageKey)); + if (refCF) { + CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usagePage); + } + if (pDevice->usagePage != kHIDPage_GenericDesktop) { + return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */ + } + + refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsageKey)); + if (refCF) { + CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usage); + } + + if ((pDevice->usage != kHIDUsage_GD_Joystick && + pDevice->usage != kHIDUsage_GD_GamePad && + pDevice->usage != kHIDUsage_GD_MultiAxisController)) { + return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */ + } + + pDevice->deviceRef = hidDevice; + + /* get device name */ + refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey)); + if (!refCF) { + /* Maybe we can't get "AwesomeJoystick2000", but we can get "Logitech"? */ + refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey)); + } + if ((!refCF) || (!CFStringGetCString(refCF, pDevice->product, sizeof (pDevice->product), kCFStringEncodingUTF8))) { + SDL_strlcpy(pDevice->product, "Unidentified joystick", sizeof (pDevice->product)); + } + + refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVendorIDKey)); + if (refCF) { + CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->guid.data[0]); + } + + refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductIDKey)); + if (refCF) { + CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->guid.data[8]); + } + + /* Check to make sure we have a vendor and product ID + If we don't, use the same algorithm as the Linux code for Bluetooth devices */ + guid32 = (Uint32*)pDevice->guid.data; + if (!guid32[0] && !guid32[1]) { + /* If we don't have a vendor and product ID this is probably a Bluetooth device */ + const Uint16 BUS_BLUETOOTH = 0x05; + Uint16 *guid16 = (Uint16 *)guid32; + *guid16++ = BUS_BLUETOOTH; + *guid16++ = 0; + SDL_strlcpy((char*)guid16, pDevice->product, sizeof(pDevice->guid.data) - 4); + } + + array = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone); + if (array) { + AddHIDElements(array, pDevice); + CFRelease(array); + } + + return SDL_TRUE; +} + static void -HIDDisposeElementList(recElement ** elementList) +JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) { - recElement *pElement = *elementList; - while (pElement) { - recElement *pElementNext = pElement->pNext; - DisposePtr((Ptr) pElement); - pElement = pElementNext; + if (res != kIOReturnSuccess) { + return; } - *elementList = NULL; -} -/* disposes of a single device, closing and releaseing interface, freeing memory fro device and elements, setting device pointer to NULL - * all your device no longer belong to us... (i.e., you do not 'own' the device anymore) - */ + recDevice *device = (recDevice *) SDL_calloc(1, sizeof(recDevice)); -static recDevice * -HIDDisposeDevice(recDevice ** ppDevice) -{ - kern_return_t result = KERN_SUCCESS; - recDevice *pDeviceNext = NULL; - if (*ppDevice) { - /* save next device prior to disposing of this device */ - pDeviceNext = (*ppDevice)->pNext; - - /* free posible io_service_t */ - if ((*ppDevice)->ffservice) { - IOObjectRelease((*ppDevice)->ffservice); - (*ppDevice)->ffservice = 0; - } - - /* free element lists */ - HIDDisposeElementList(&(*ppDevice)->firstAxis); - HIDDisposeElementList(&(*ppDevice)->firstButton); - HIDDisposeElementList(&(*ppDevice)->firstHat); - - result = HIDCloseReleaseInterface(*ppDevice); /* function sanity checks interface value (now application does not own device) */ - if (kIOReturnSuccess != result) - HIDReportErrorNum - ("HIDCloseReleaseInterface failed when trying to dipose device.", - result); - DisposePtr((Ptr) * ppDevice); - *ppDevice = NULL; + if (!device) { + SDL_OutOfMemory(); + return; } - return pDeviceNext; -} - -/* Given an io_object_t from OSX adds a joystick device to our list if appropriate - */ -int -AddDeviceHelper( io_object_t ioHIDDeviceObject ) -{ - recDevice *device; - - /* build a device record */ - device = HIDBuildDevice(ioHIDDeviceObject); - if (!device) - return 0; - - /* Filter device list to non-keyboard/mouse stuff */ - if ((device->usagePage != kHIDPage_GenericDesktop) || - ((device->usage != kHIDUsage_GD_Joystick && - device->usage != kHIDUsage_GD_GamePad && - device->usage != kHIDUsage_GD_MultiAxisController))) { - - /* release memory for the device */ - HIDDisposeDevice(&device); - DisposePtr((Ptr) device); - return 0; + if (!GetDeviceInfo(ioHIDDeviceObject, device)) { + SDL_free(device); + return; /* not a device we care about, probably. */ } + /* Get notified when this device is disconnected. */ + IOHIDDeviceRegisterRemovalCallback(ioHIDDeviceObject, JoystickDeviceWasRemovedCallback, device); + IOHIDDeviceScheduleWithRunLoop(ioHIDDeviceObject, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + /* Allocate an instance ID for this device */ device->instance_id = ++s_joystick_instance_id; - /* We have to do some storage of the io_service_t for - * SDL_HapticOpenFromJoystick */ - if (FFIsForceFeedback(ioHIDDeviceObject) == FF_OK) { - device->ffservice = ioHIDDeviceObject; + /* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */ + if (IOHIDDeviceGetService != NULL) { /* weak reference: available in 10.6 and later. */ + const io_service_t ioservice = IOHIDDeviceGetService(ioHIDDeviceObject); + if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) { + device->ffservice = ioservice; #if SDL_HAPTIC_IOKIT - MacHaptic_MaybeAddDevice(ioHIDDeviceObject); + MacHaptic_MaybeAddDevice(ioservice); #endif - } else { - device->ffservice = 0; + } } device->send_open_event = 1; @@ -712,25 +394,93 @@ AddDeviceHelper( io_object_t ioHIDDeviceObject ) } curdevice->pNext = device; } +} - return 1; +static SDL_bool +ConfigHIDManager(CFArrayRef matchingArray) +{ + CFRunLoopRef runloop = CFRunLoopGetCurrent(); + + /* Run in a custom RunLoop mode just while initializing, + so we can detect sticks without messing with everything else. */ + CFStringRef tempRunLoopMode = CFSTR("SDLJoystickInit"); + + if (IOHIDManagerOpen(hidman, kIOHIDOptionsTypeNone) != kIOReturnSuccess) { + return SDL_FALSE; + } + + IOHIDManagerRegisterDeviceMatchingCallback(hidman, JoystickDeviceWasAddedCallback, NULL); + IOHIDManagerScheduleWithRunLoop(hidman, runloop, tempRunLoopMode); + IOHIDManagerSetDeviceMatchingMultiple(hidman, matchingArray); + + while (CFRunLoopRunInMode(tempRunLoopMode,0,TRUE)==kCFRunLoopRunHandledSource) { + /* no-op. Callback fires once per existing device. */ + } + + /* Put this in the normal RunLoop mode now, for future hotplug events. */ + IOHIDManagerUnscheduleFromRunLoop(hidman, runloop, tempRunLoopMode); + IOHIDManagerScheduleWithRunLoop(hidman, runloop, kCFRunLoopDefaultMode); + + return SDL_TRUE; /* good to go. */ } -/* Called by our IO port notifier on the master port when a HID device is inserted, we iterate - * and check for new joysticks - */ -void JoystickDeviceWasAddedCallback( void *refcon, io_iterator_t iterator ) +static CFDictionaryRef +CreateHIDDeviceMatchDictionary(const UInt32 page, const UInt32 usage, int *okay) { - io_object_t ioHIDDeviceObject = 0; + CFDictionaryRef retval = NULL; + CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); + CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + const void *keys[2] = { (void *) CFSTR(kIOHIDDeviceUsagePageKey), (void *) CFSTR(kIOHIDDeviceUsageKey) }; + const void *vals[2] = { (void *) pageNumRef, (void *) usageNumRef }; - while ( ( ioHIDDeviceObject = IOIteratorNext(iterator) ) ) - { - if ( ioHIDDeviceObject ) - { - AddDeviceHelper( ioHIDDeviceObject ); + if (pageNumRef && usageNumRef) { + retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + + if (pageNumRef) { + CFRelease(pageNumRef); + } + if (usageNumRef) { + CFRelease(pageNumRef); + } + + if (!retval) { + *okay = 0; + } + + return retval; +} + +static SDL_bool +CreateHIDManager(void) +{ + SDL_bool retval = SDL_FALSE; + int okay = 1; + const void *vals[] = { + (void *) CreateHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, &okay), + (void *) CreateHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, &okay), + (void *) CreateHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay), + }; + const size_t numElements = SDL_arraysize(vals); + CFArrayRef array = okay ? CFArrayCreate(kCFAllocatorDefault, vals, numElements, &kCFTypeArrayCallBacks) : NULL; + size_t i; + + for (i = 0; i < numElements; i++) { + if (vals[i]) { + CFRelease((CFTypeRef) vals[i]); } } + + if (array) { + hidman = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (hidman != NULL) { + retval = ConfigHIDManager(array); + } + CFRelease(array); + } + + return retval; } @@ -742,82 +492,14 @@ void JoystickDeviceWasAddedCallback( void *refcon, io_iterator_t iterator ) int SDL_SYS_JoystickInit(void) { - IOReturn result = kIOReturnSuccess; - mach_port_t masterPort = 0; - io_iterator_t hidObjectIterator = 0; - CFMutableDictionaryRef hidMatchDictionary = NULL; - io_object_t ioHIDDeviceObject = 0; - io_iterator_t portIterator = 0; - if (gpDeviceList) { return SDL_SetError("Joystick: Device list already inited."); } - result = IOMasterPort(bootstrap_port, &masterPort); - if (kIOReturnSuccess != result) { - return SDL_SetError("Joystick: IOMasterPort error with bootstrap_port."); + if (!CreateHIDManager()) { + return SDL_SetError("Joystick: Couldn't initialize HID Manager"); } - /* Set up a matching dictionary to search I/O Registry by class name for all HID class devices. */ - hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey); - if (hidMatchDictionary) { - /* Add key for device type (joystick, in this case) to refine the matching dictionary. */ - - /* NOTE: we now perform this filtering later - UInt32 usagePage = kHIDPage_GenericDesktop; - UInt32 usage = kHIDUsage_GD_Joystick; - CFNumberRef refUsage = NULL, refUsagePage = NULL; - - refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage); - CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage); - refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage); - CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage); - */ - } else { - return SDL_SetError - ("Joystick: Failed to get HID CFMutableDictionaryRef via IOServiceMatching."); - } - - /* Now search I/O Registry for matching devices. */ - result = - IOServiceGetMatchingServices(masterPort, hidMatchDictionary, - &hidObjectIterator); - /* Check for errors */ - if (kIOReturnSuccess != result) { - return SDL_SetError("Joystick: Couldn't create a HID object iterator."); - } - if (!hidObjectIterator) { /* there are no joysticks */ - gpDeviceList = NULL; - return 0; - } - /* IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref. */ - - /* build flat linked list of devices from device iterator */ - - gpDeviceList = NULL; - - while ((ioHIDDeviceObject = IOIteratorNext(hidObjectIterator))) { - AddDeviceHelper( ioHIDDeviceObject ); - } - result = IOObjectRelease(hidObjectIterator); /* release the iterator */ - - /* now connect notification for new devices */ - notificationPort = IONotificationPortCreate(masterPort); - hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey); - - CFRunLoopAddSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(notificationPort), - kCFRunLoopDefaultMode); - - /* Register for notifications when a serial port is added to the system */ - result = IOServiceAddMatchingNotification(notificationPort, - kIOFirstMatchNotification, - hidMatchDictionary, - JoystickDeviceWasAddedCallback, - NULL, - &portIterator); - while (IOIteratorNext(portIterator)) {}; /* Run out the iterator or notifications won't start (you can also use it to iterate the available devices). */ - return SDL_SYS_NumJoysticks(); } @@ -828,10 +510,10 @@ SDL_SYS_NumJoysticks() recDevice *device = gpDeviceList; int nJoySticks = 0; - while ( device ) - { - if ( !device->removed ) + while (device) { + if (!device->removed) { nJoySticks++; + } device = device->pNext; } @@ -843,18 +525,16 @@ SDL_SYS_NumJoysticks() void SDL_SYS_JoystickDetect() { - if ( s_bDeviceAdded || s_bDeviceRemoved ) - { + if (s_bDeviceAdded || s_bDeviceRemoved) { recDevice *device = gpDeviceList; s_bDeviceAdded = SDL_FALSE; s_bDeviceRemoved = SDL_FALSE; int device_index = 0; /* send notifications */ - while ( device ) - { - if ( device->send_open_event ) - { + while (device) { + if (device->send_open_event) { device->send_open_event = 0; +/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceAdded()? */ #if !SDL_EVENTS_DISABLED SDL_Event event; event.type = SDL_JOYDEVICEADDED; @@ -870,43 +550,25 @@ SDL_SYS_JoystickDetect() } - if ( device->removed ) - { - recDevice *removeDevice = device; - if ( gpDeviceList == removeDevice ) - { - device = device->pNext; - gpDeviceList = device; - } - else - { - device = gpDeviceList; - while ( device->pNext != removeDevice ) - { - device = device->pNext; - } - - device->pNext = removeDevice->pNext; - } + if (device->removed) { + const int instance_id = device->instance_id; + device = FreeDevice(device); +/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceRemoved()? */ #if !SDL_EVENTS_DISABLED SDL_Event event; event.type = SDL_JOYDEVICEREMOVED; if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.jdevice.which = removeDevice->instance_id; + event.jdevice.which = instance_id; if ((SDL_EventOK == NULL) || (*SDL_EventOK) (SDL_EventOKParam, &event)) { SDL_PushEvent(&event); } } - - DisposePtr((Ptr) removeDevice); #endif /* !SDL_EVENTS_DISABLED */ - } - else - { + } else { device = device->pNext; device_index++; } @@ -926,8 +588,9 @@ SDL_SYS_JoystickNameForDeviceIndex(int device_index) { recDevice *device = gpDeviceList; - for (; device_index > 0; device_index--) + while (device_index-- > 0) { device = device->pNext; + } return device->product; } @@ -940,8 +603,9 @@ SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) recDevice *device = gpDeviceList; int index; - for (index = device_index; index > 0; index--) + for (index = device_index; index > 0; index--) { device = device->pNext; + } return device->instance_id; } @@ -957,8 +621,9 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) recDevice *device = gpDeviceList; int index; - for (index = device_index; index > 0; index--) + for (index = device_index; index > 0; index--) { device = device->pNext; + } joystick->instance_id = device->instance_id; joystick->hwdata = device; @@ -979,11 +644,10 @@ SDL_SYS_JoystickAttached(SDL_Joystick * joystick) { recDevice *device = gpDeviceList; - while ( device ) - { - if ( joystick->instance_id == device->instance_id ) + while (device) { + if (joystick->instance_id == device->instance_id) { return SDL_TRUE; - + } device = device->pNext; } @@ -1003,53 +667,24 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) SInt32 value, range; int i; - if ( !device ) + if (!device) { return; + } if (device->removed) { /* device was unplugged; ignore it. */ - recDevice *devicelist = gpDeviceList; joystick->closed = 1; joystick->uncentered = 1; - - if ( devicelist == device ) - { - gpDeviceList = device->pNext; - } - else - { - while ( devicelist->pNext != device ) - { - devicelist = devicelist->pNext; - } - - devicelist->pNext = device->pNext; - } - - DisposePtr((Ptr) device); joystick->hwdata = NULL; - -#if !SDL_EVENTS_DISABLED - SDL_Event event; - event.type = SDL_JOYDEVICEREMOVED; - - if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.jdevice.which = joystick->instance_id; - if ((SDL_EventOK == NULL) - || (*SDL_EventOK) (SDL_EventOKParam, &event)) { - SDL_PushEvent(&event); - } - } -#endif /* !SDL_EVENTS_DISABLED */ - return; } element = device->firstAxis; i = 0; while (element) { - value = HIDScaledCalibratedValue(device, element, -32768, 32767); - if (value != joystick->axes[i]) + value = GetHIDScaledCalibratedState(device, element, -32768, 32767); + if (value != joystick->axes[i]) { SDL_PrivateJoystickAxis(joystick, i, value); + } element = element->pNext; ++i; } @@ -1057,11 +692,13 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) element = device->firstButton; i = 0; while (element) { - value = HIDGetElementValue(device, element); - if (value > 1) /* handle pressure-sensitive buttons */ + value = GetHIDElementState(device, element); + if (value > 1) { /* handle pressure-sensitive buttons */ value = 1; - if (value != joystick->buttons[i]) + } + if (value != joystick->buttons[i]) { SDL_PrivateJoystickButton(joystick, i, value); + } element = element->pNext; ++i; } @@ -1072,11 +709,12 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) Uint8 pos = 0; range = (element->max - element->min + 1); - value = HIDGetElementValue(device, element) - element->min; - if (range == 4) /* 4 position hatswitch - scale up value */ + value = GetHIDElementState(device, element) - element->min; + if (range == 4) { /* 4 position hatswitch - scale up value */ value *= 2; - else if (range != 8) /* Neither a 4 nor 8 positions - fall back to default position (centered) */ + } else if (range != 8) { /* Neither a 4 nor 8 positions - fall back to default position (centered) */ value = -1; + } switch (value) { case 0: pos = SDL_HAT_UP; @@ -1110,13 +748,14 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) pos = SDL_HAT_CENTERED; break; } - if (pos != joystick->hats[i]) + + if (pos != joystick->hats[i]) { SDL_PrivateJoystickHat(joystick, i, pos); + } + element = element->pNext; ++i; } - - return; } /* Function to close a joystick after use */ @@ -1130,14 +769,17 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick) void SDL_SYS_JoystickQuit(void) { - while (NULL != gpDeviceList) - gpDeviceList = HIDDisposeDevice(&gpDeviceList); - - if ( notificationPort ) - { - IONotificationPortDestroy( notificationPort ); - notificationPort = 0; + while (FreeDevice(gpDeviceList)) { + /* spin */ } + + if (hidman) { + IOHIDManagerClose(hidman, kIOHIDOptionsTypeNone); + CFRelease(hidman); + hidman = NULL; + } + + s_bDeviceAdded = s_bDeviceRemoved = SDL_FALSE; } @@ -1146,8 +788,9 @@ SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) recDevice *device = gpDeviceList; int index; - for (index = device_index; index > 0; index--) + for (index = device_index; index > 0; index--) { device = device->pNext; + } return device->guid; } diff --git a/src/joystick/darwin/SDL_sysjoystick_c.h b/src/joystick/darwin/SDL_sysjoystick_c.h index 6f3372f2b..e1c6f719e 100644 --- a/src/joystick/darwin/SDL_sysjoystick_c.h +++ b/src/joystick/darwin/SDL_sysjoystick_c.h @@ -22,34 +22,18 @@ #ifndef SDL_JOYSTICK_IOKIT_H - #include -#include -#include - struct recElement { - IOHIDElementCookie cookie; /* unique value which identifies element, will NOT change */ - long usagePage, usage; /* HID usage */ - long min; /* reported min value possible */ - long max; /* reported max value possible */ -#if 0 - /* TODO: maybe should handle the following stuff somehow? */ - - long scaledMin; /* reported scaled min value possible */ - long scaledMax; /* reported scaled max value possible */ - long size; /* size in bits of data return from element */ - Boolean relative; /* are reports relative to last report (deltas) */ - Boolean wrapping; /* does element wrap around (one value higher than max is min) */ - Boolean nonLinear; /* are the values reported non-linear relative to element movement */ - Boolean preferredState; /* does element have a preferred state (such as a button) */ - Boolean nullState; /* does element have null state */ -#endif /* 0 */ + IOHIDElementRef elementRef; + uint32_t usagePage, usage; /* HID usage */ + SInt32 min; /* reported min value possible */ + SInt32 max; /* reported max value possible */ /* runtime variables used for auto-calibration */ - long minReport; /* min returned value */ - long maxReport; /* max returned value */ + SInt32 minReport; /* min returned value */ + SInt32 maxReport; /* max returned value */ struct recElement *pNext; /* next element in list */ }; @@ -57,19 +41,17 @@ typedef struct recElement recElement; struct joystick_hwdata { + IOHIDDeviceRef deviceRef; /* HIDManager device handle */ io_service_t ffservice; /* Interface for force feedback, 0 = no ff */ - IOHIDDeviceInterface **interface; /* interface to device, NULL = no interface */ - IONotificationPortRef notificationPort; /* port to be notified on joystick removal */ - io_iterator_t portIterator; /* iterator for removal callback */ char product[256]; /* name of product */ - long usage; /* usage page from IOUSBHID Parser.h which defines general usage */ - long usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */ + uint32_t usage; /* usage page from IOUSBHID Parser.h which defines general usage */ + uint32_t usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */ - long axes; /* number of axis (calculated, not reported by device) */ - long buttons; /* number of buttons (calculated, not reported by device) */ - long hats; /* number of hat switches (calculated, not reported by device) */ - long elements; /* number of total elements (should be total of above) (calculated, not reported by device) */ + int axes; /* number of axis (calculated, not reported by device) */ + int buttons; /* number of buttons (calculated, not reported by device) */ + int hats; /* number of hat switches (calculated, not reported by device) */ + int elements; /* number of total elements (should be total of above) (calculated, not reported by device) */ recElement *firstAxis; recElement *firstButton;