| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2015 Sam Lantinga <[email protected]>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "../../SDL_internal.h"
- #ifdef SDL_JOYSTICK_IOKIT
- #include <IOKit/hid/IOHIDLib.h>
- /* For force feedback testing. */
- #include <ForceFeedback/ForceFeedback.h>
- #include <ForceFeedback/ForceFeedbackConstants.h>
- #include "SDL_joystick.h"
- #include "../SDL_sysjoystick.h"
- #include "../SDL_joystick_c.h"
- #include "SDL_sysjoystick_c.h"
- #include "SDL_events.h"
- #include "../../haptic/darwin/SDL_syshaptic_c.h" /* For haptic hot plugging */
- #if !SDL_EVENTS_DISABLED
- #include "../../events/SDL_events_c.h"
- #endif
- #define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick")
- /* The base object of the HID Manager API */
- static IOHIDManagerRef hidman = NULL;
- /* Linked list of all available devices */
- static recDevice *gpDeviceList = NULL;
- /* 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 recDevice *GetDeviceForIndex(int device_index)
- {
- recDevice *device = gpDeviceList;
- while (device) {
- if (!device->removed) {
- if (device_index == 0)
- break;
- --device_index;
- }
- device = device->pNext;
- }
- return device;
- }
- static void
- FreeElementList(recElement *pElement)
- {
- while (pElement) {
- recElement *pElementNext = pElement->pNext;
- SDL_free(pElement);
- pElement = pElementNext;
- }
- }
- static recDevice *
- FreeDevice(recDevice *removeDevice)
- {
- recDevice *pDeviceNext = NULL;
- if (removeDevice) {
- if (removeDevice->deviceRef) {
- IOHIDDeviceUnscheduleFromRunLoop(removeDevice->deviceRef, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE);
- removeDevice->deviceRef = NULL;
- }
- /* save next device prior to disposing of this device */
- pDeviceNext = removeDevice->pNext;
- 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
- GetHIDElementState(recDevice *pDevice, recElement *pElement)
- {
- SInt32 value = 0;
- if (pDevice && pElement) {
- IOHIDValueRef valueRef;
- if (IOHIDDeviceGetValue(pDevice->deviceRef, pElement->elementRef, &valueRef) == kIOReturnSuccess) {
- value = (SInt32) IOHIDValueGetIntegerValue(valueRef);
- /* record min and max for auto calibration */
- if (value < pElement->minReport) {
- pElement->minReport = value;
- }
- if (value > pElement->maxReport) {
- pElement->maxReport = value;
- }
- }
- }
- return value;
- }
- static SInt32
- GetHIDScaledCalibratedState(recDevice * pDevice, recElement * pElement, SInt32 min, SInt32 max)
- {
- 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 */
- }
- return ((value - pElement->minReport) * deviceScale / readScale) + min;
- }
- static void
- JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender)
- {
- recDevice *device = (recDevice *) ctx;
- device->removed = SDL_TRUE;
- device->deviceRef = NULL; // deviceRef was invalidated due to the remove
- #if SDL_HAPTIC_IOKIT
- MacHaptic_MaybeRemoveDevice(device->ffservice);
- #endif
- /* !!! 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 = device->instance_id;
- if ((SDL_EventOK == NULL)
- || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
- SDL_PushEvent(&event);
- }
- }
- }
- #endif /* !SDL_EVENTS_DISABLED */
- }
- static void AddHIDElement(const void *value, void *parameter);
- /* Call AddHIDElement() on all elements in an array of IOHIDElementRefs */
- static void
- AddHIDElements(CFArrayRef array, recDevice *pDevice)
- {
- const CFRange range = { 0, CFArrayGetCount(array) };
- CFArrayApplyFunction(array, range, AddHIDElement, pDevice);
- }
- static SDL_bool
- ElementAlreadyAdded(const IOHIDElementCookie cookie, const recElement *listitem) {
- while (listitem) {
- if (listitem->cookie == cookie) {
- return SDL_TRUE;
- }
- listitem = listitem->pNext;
- }
- return SDL_FALSE;
- }
- /* 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;
- 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 (!ElementAlreadyAdded(cookie, pDevice->firstButton)) {
- element = (recElement *) SDL_calloc(1, sizeof (recElement));
- if (element) {
- pDevice->buttons++;
- headElement = &(pDevice->firstButton);
- }
- }
- 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:
- case kHIDPage_Consumer: /* e.g. 'pause' button on Steelseries MFi gamepads. */
- 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++;
- }
- }
- }
- 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 SDL_bool
- JoystickAlreadyKnown(IOHIDDeviceRef ioHIDDeviceObject)
- {
- recDevice *i;
- for (i = gpDeviceList; i != NULL; i = i->pNext) {
- if (i->deviceRef == ioHIDDeviceObject) {
- return SDL_TRUE;
- }
- }
- return SDL_FALSE;
- }
- static void
- JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject)
- {
- recDevice *device;
- int device_index = 0;
- if (res != kIOReturnSuccess) {
- return;
- }
- if (JoystickAlreadyKnown(ioHIDDeviceObject)) {
- return; /* IOKit sent us a duplicate. */
- }
- device = (recDevice *) SDL_calloc(1, sizeof(recDevice));
- if (!device) {
- SDL_OutOfMemory();
- return;
- }
- 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(), SDL_JOYSTICK_RUNLOOP_MODE);
- /* 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 MAC_OS_X_VERSION_MIN_REQUIRED < 1060
- if (IOHIDDeviceGetService != NULL) { /* weak reference: available in 10.6 and later. */
- #endif
- const io_service_t ioservice = IOHIDDeviceGetService(ioHIDDeviceObject);
- #if SDL_HAPTIC_IOKIT
- if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) {
- device->ffservice = ioservice;
- MacHaptic_MaybeAddDevice(ioservice);
- }
- #endif
- #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
- }
- #endif
- /* Add device to the end of the list */
- if ( !gpDeviceList ) {
- gpDeviceList = device;
- } else {
- recDevice *curdevice;
- curdevice = gpDeviceList;
- while ( curdevice->pNext ) {
- ++device_index;
- curdevice = curdevice->pNext;
- }
- curdevice->pNext = device;
- ++device_index; /* bump by one since we counted by pNext. */
- }
- /* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceAdded()? */
- #if !SDL_EVENTS_DISABLED
- {
- SDL_Event event;
- event.type = SDL_JOYDEVICEADDED;
- if (SDL_GetEventState(event.type) == SDL_ENABLE) {
- event.jdevice.which = device_index;
- if ((SDL_EventOK == NULL)
- || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
- SDL_PushEvent(&event);
- }
- }
- }
- #endif /* !SDL_EVENTS_DISABLED */
- }
- static SDL_bool
- ConfigHIDManager(CFArrayRef matchingArray)
- {
- CFRunLoopRef runloop = CFRunLoopGetCurrent();
- if (IOHIDManagerOpen(hidman, kIOHIDOptionsTypeNone) != kIOReturnSuccess) {
- return SDL_FALSE;
- }
- IOHIDManagerSetDeviceMatchingMultiple(hidman, matchingArray);
- IOHIDManagerRegisterDeviceMatchingCallback(hidman, JoystickDeviceWasAddedCallback, NULL);
- IOHIDManagerScheduleWithRunLoop(hidman, runloop, SDL_JOYSTICK_RUNLOOP_MODE);
- while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) {
- /* no-op. Callback fires once per existing device. */
- }
- /* future hotplug events will come through SDL_JOYSTICK_RUNLOOP_MODE now. */
- return SDL_TRUE; /* good to go. */
- }
- static CFDictionaryRef
- CreateHIDDeviceMatchDictionary(const UInt32 page, const UInt32 usage, int *okay)
- {
- 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 };
- if (pageNumRef && usageNumRef) {
- retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- }
- if (pageNumRef) {
- CFRelease(pageNumRef);
- }
- if (usageNumRef) {
- CFRelease(usageNumRef);
- }
- 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;
- }
- /* Function to scan the system for joysticks.
- * Joystick 0 should be the system default joystick.
- * This function should return the number of available joysticks, or -1
- * on an unrecoverable fatal error.
- */
- int
- SDL_SYS_JoystickInit(void)
- {
- if (gpDeviceList) {
- return SDL_SetError("Joystick: Device list already inited.");
- }
- if (!CreateHIDManager()) {
- return SDL_SetError("Joystick: Couldn't initialize HID Manager");
- }
- return SDL_SYS_NumJoysticks();
- }
- /* Function to return the number of joystick devices plugged in right now */
- int
- SDL_SYS_NumJoysticks()
- {
- recDevice *device = gpDeviceList;
- int nJoySticks = 0;
- while (device) {
- if (!device->removed) {
- nJoySticks++;
- }
- device = device->pNext;
- }
- return nJoySticks;
- }
- /* Function to cause any queued joystick insertions to be processed
- */
- void
- SDL_SYS_JoystickDetect()
- {
- recDevice *device = gpDeviceList;
- while (device) {
- if (device->removed) {
- device = FreeDevice(device);
- } else {
- device = device->pNext;
- }
- }
- // run this after the checks above so we don't set device->removed and delete the device before
- // SDL_SYS_JoystickUpdate can run to clean up the SDL_Joystick object that owns this device
- while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) {
- /* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */
- }
- }
- /* Function to get the device-dependent name of a joystick */
- const char *
- SDL_SYS_JoystickNameForDeviceIndex(int device_index)
- {
- recDevice *device = GetDeviceForIndex(device_index);
- return device ? device->product : "UNKNOWN";
- }
- /* Function to return the instance id of the joystick at device_index
- */
- SDL_JoystickID
- SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
- {
- recDevice *device = GetDeviceForIndex(device_index);
- return device ? device->instance_id : 0;
- }
- /* Function to open a joystick for use.
- * The joystick to open is specified by the device index.
- * This should fill the nbuttons and naxes fields of the joystick structure.
- * It returns 0, or -1 if there is an error.
- */
- int
- SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
- {
- recDevice *device = GetDeviceForIndex(device_index);
- joystick->instance_id = device->instance_id;
- joystick->hwdata = device;
- joystick->name = device->product;
- joystick->naxes = device->axes;
- joystick->nhats = device->hats;
- joystick->nballs = 0;
- joystick->nbuttons = device->buttons;
- return 0;
- }
- /* Function to query if the joystick is currently attached
- * It returns SDL_TRUE if attached, SDL_FALSE otherwise.
- */
- SDL_bool
- SDL_SYS_JoystickAttached(SDL_Joystick * joystick)
- {
- return joystick->hwdata != NULL;
- }
- /* Function to update the state of a joystick - called as a device poll.
- * This function shouldn't update the joystick structure directly,
- * but instead should call SDL_PrivateJoystick*() to deliver events
- * and update joystick device state.
- */
- void
- SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
- {
- recDevice *device = joystick->hwdata;
- recElement *element;
- SInt32 value, range;
- int i;
- if (!device) {
- return;
- }
- if (device->removed) { /* device was unplugged; ignore it. */
- if (joystick->hwdata) {
- joystick->force_recentering = SDL_TRUE;
- joystick->hwdata = NULL;
- }
- return;
- }
- element = device->firstAxis;
- i = 0;
- while (element) {
- value = GetHIDScaledCalibratedState(device, element, -32768, 32767);
- if (value != joystick->axes[i]) {
- SDL_PrivateJoystickAxis(joystick, i, value);
- }
- element = element->pNext;
- ++i;
- }
- element = device->firstButton;
- i = 0;
- while (element) {
- value = GetHIDElementState(device, element);
- if (value > 1) { /* handle pressure-sensitive buttons */
- value = 1;
- }
- if (value != joystick->buttons[i]) {
- SDL_PrivateJoystickButton(joystick, i, value);
- }
- element = element->pNext;
- ++i;
- }
- element = device->firstHat;
- i = 0;
- while (element) {
- Uint8 pos = 0;
- range = (element->max - element->min + 1);
- 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) */
- value = -1;
- }
- switch (value) {
- case 0:
- pos = SDL_HAT_UP;
- break;
- case 1:
- pos = SDL_HAT_RIGHTUP;
- break;
- case 2:
- pos = SDL_HAT_RIGHT;
- break;
- case 3:
- pos = SDL_HAT_RIGHTDOWN;
- break;
- case 4:
- pos = SDL_HAT_DOWN;
- break;
- case 5:
- pos = SDL_HAT_LEFTDOWN;
- break;
- case 6:
- pos = SDL_HAT_LEFT;
- break;
- case 7:
- pos = SDL_HAT_LEFTUP;
- break;
- default:
- /* Every other value is mapped to center. We do that because some
- * joysticks use 8 and some 15 for this value, and apparently
- * there are even more variants out there - so we try to be generous.
- */
- pos = SDL_HAT_CENTERED;
- break;
- }
- if (pos != joystick->hats[i]) {
- SDL_PrivateJoystickHat(joystick, i, pos);
- }
- element = element->pNext;
- ++i;
- }
- }
- /* Function to close a joystick after use */
- void
- SDL_SYS_JoystickClose(SDL_Joystick * joystick)
- {
- }
- /* Function to perform any system-specific joystick related cleanup */
- void
- SDL_SYS_JoystickQuit(void)
- {
- while (FreeDevice(gpDeviceList)) {
- /* spin */
- }
- if (hidman) {
- IOHIDManagerUnscheduleFromRunLoop(hidman, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE);
- IOHIDManagerClose(hidman, kIOHIDOptionsTypeNone);
- CFRelease(hidman);
- hidman = NULL;
- }
- }
- SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
- {
- recDevice *device = GetDeviceForIndex(device_index);
- SDL_JoystickGUID guid;
- if (device) {
- guid = device->guid;
- } else {
- SDL_zero(guid);
- }
- return guid;
- }
- SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
- {
- return joystick->hwdata->guid;
- }
- #endif /* SDL_JOYSTICK_IOKIT */
- /* vi: set ts=4 sw=4 expandtab: */
|