diff options
author | chai <chaifix@163.com> | 2019-03-19 23:06:27 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-03-19 23:06:27 +0800 |
commit | 1497dccd63a84b7ee2b229b1ad9c5c02718f2a78 (patch) | |
tree | f8d1bff50da13e126d08c7345653e002e293202d /Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c | |
parent | 5e2a973516e0729b225da9de0b03015dc5854ac4 (diff) |
*rename
Diffstat (limited to 'Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c')
-rw-r--r-- | Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c | 1019 |
1 files changed, 0 insertions, 1019 deletions
diff --git a/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c b/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c deleted file mode 100644 index 8af3b96..0000000 --- a/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c +++ /dev/null @@ -1,1019 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> - - 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 "SDL_events.h" -#include "SDL_joystick.h" -#include "../SDL_sysjoystick.h" -#include "../SDL_joystick_c.h" -#include "SDL_sysjoystick_c.h" -#include "../hidapi/SDL_hidapijoystick_c.h" -#include "../../haptic/darwin/SDL_syshaptic_c.h" /* For haptic hot plugging */ - - -#define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick") - -#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF) - -/* The base object of the HID Manager API */ -static IOHIDManagerRef hidman = NULL; - -/* Linked list of all available devices */ -static recDevice *gpDeviceList = NULL; - -void FreeRumbleEffectData(FFEFFECT *effect) -{ - if (!effect) { - return; - } - SDL_free(effect->rgdwAxes); - SDL_free(effect->rglDirection); - SDL_free(effect->lpvTypeSpecificParams); - SDL_free(effect); -} - -FFEFFECT *CreateRumbleEffectData(Sint16 magnitude, Uint32 duration_ms) -{ - FFEFFECT *effect; - FFPERIODIC *periodic; - - /* Create the effect */ - effect = (FFEFFECT *)SDL_calloc(1, sizeof(*effect)); - if (!effect) { - return NULL; - } - effect->dwSize = sizeof(*effect); - effect->dwGain = 10000; - effect->dwFlags = FFEFF_OBJECTOFFSETS; - effect->dwDuration = duration_ms * 1000; /* In microseconds. */ - effect->dwTriggerButton = FFEB_NOTRIGGER; - - effect->cAxes = 2; - effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD)); - if (!effect->rgdwAxes) { - FreeRumbleEffectData(effect); - return NULL; - } - - effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG)); - if (!effect->rglDirection) { - FreeRumbleEffectData(effect); - return NULL; - } - effect->dwFlags |= FFEFF_CARTESIAN; - - periodic = (FFPERIODIC *)SDL_calloc(1, sizeof(*periodic)); - if (!periodic) { - FreeRumbleEffectData(effect); - return NULL; - } - periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); - periodic->dwPeriod = 1000000; - - effect->cbTypeSpecificParams = sizeof(*periodic); - effect->lpvTypeSpecificParams = periodic; - - return effect; -} - -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 SDL_bool -GetHIDElementState(recDevice *pDevice, recElement *pElement, SInt32 *pValue) -{ - SInt32 value = 0; - int returnValue = SDL_FALSE; - - 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; - } - *pValue = value; - - returnValue = SDL_TRUE; - } - } - return returnValue; -} - -static SDL_bool -GetHIDScaledCalibratedState(recDevice * pDevice, recElement * pElement, SInt32 min, SInt32 max, SInt32 *pValue) -{ - const float deviceScale = max - min; - const float readScale = pElement->maxReport - pElement->minReport; - int returnValue = SDL_FALSE; - if (GetHIDElementState(pDevice, pElement, pValue)) - { - if (readScale == 0) { - returnValue = SDL_TRUE; /* no scaling at all */ - } - else - { - *pValue = ((*pValue - pElement->minReport) * deviceScale / readScale) + min; - returnValue = SDL_TRUE; - } - } - return returnValue; -} - -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 (device->ffeffect_ref) { - FFDeviceReleaseEffect(device->ffdevice, device->ffeffect_ref); - device->ffeffect_ref = NULL; - } - if (device->ffeffect) { - FreeRumbleEffectData(device->ffeffect); - device->ffeffect = NULL; - } - if (device->ffdevice) { - FFReleaseDevice(device->ffdevice); - device->ffdevice = NULL; - device->ff_initialized = SDL_FALSE; - } -#if SDL_HAPTIC_IOKIT - MacHaptic_MaybeRemoveDevice(device->ffservice); -#endif - - SDL_PrivateJoystickRemoved(device->instance_id); -} - - -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: - case kHIDUsage_GD_SystemMainMenu: - 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: - case kHIDUsage_Sim_Accelerator: - case kHIDUsage_Sim_Brake: - 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) -{ - Sint32 vendor = 0; - Sint32 product = 0; - Sint32 version = 0; - CFTypeRef refCF = NULL; - CFArrayRef array = NULL; - Uint16 *guid16 = (Uint16 *)pDevice->guid.data; - - /* get usage page and usage */ - refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsagePageKey)); - if (refCF) { - CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usagePage); - } - if (pDevice->usagePage != kHIDPage_GenericDesktop) { - return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */ - } - - refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDPrimaryUsageKey)); - if (refCF) { - CFNumberGetValue(refCF, kCFNumberSInt32Type, &pDevice->usage); - } - - if ((pDevice->usage != kHIDUsage_GD_Joystick && - pDevice->usage != kHIDUsage_GD_GamePad && - pDevice->usage != kHIDUsage_GD_MultiAxisController)) { - return SDL_FALSE; /* Filter device list to non-keyboard/mouse stuff */ - } - - pDevice->deviceRef = hidDevice; - - /* get device name */ - refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey)); - if (!refCF) { - /* Maybe we can't get "AwesomeJoystick2000", but we can get "Logitech"? */ - refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDManufacturerKey)); - } - if ((!refCF) || (!CFStringGetCString(refCF, pDevice->product, sizeof (pDevice->product), kCFStringEncodingUTF8))) { - SDL_strlcpy(pDevice->product, "Unidentified joystick", sizeof (pDevice->product)); - } - - refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVendorIDKey)); - if (refCF) { - CFNumberGetValue(refCF, kCFNumberSInt32Type, &vendor); - } - - refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductIDKey)); - if (refCF) { - CFNumberGetValue(refCF, kCFNumberSInt32Type, &product); - } - - refCF = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVersionNumberKey)); - if (refCF) { - CFNumberGetValue(refCF, kCFNumberSInt32Type, &version); - } - -#ifdef SDL_JOYSTICK_HIDAPI - if (HIDAPI_IsDevicePresent(vendor, product, version)) { - /* The HIDAPI driver is taking care of this device */ - return 0; - } -#endif - - SDL_memset(pDevice->guid.data, 0, sizeof(pDevice->guid.data)); - - if (vendor && product) { - *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB); - *guid16++ = 0; - *guid16++ = SDL_SwapLE16((Uint16)vendor); - *guid16++ = 0; - *guid16++ = SDL_SwapLE16((Uint16)product); - *guid16++ = 0; - *guid16++ = SDL_SwapLE16((Uint16)version); - *guid16++ = 0; - } else { - *guid16++ = SDL_SwapLE16(SDL_HARDWARE_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; - io_service_t ioservice; - - 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. */ - } - - if (SDL_ShouldIgnoreJoystick(device->product, device->guid)) { - SDL_free(device); - return; - } - - /* 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 = SDL_GetNextJoystickInstanceID(); - - /* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */ - ioservice = IOHIDDeviceGetService(ioHIDDeviceObject); - if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) { - device->ffservice = ioservice; -#if SDL_HAPTIC_IOKIT - MacHaptic_MaybeAddDevice(ioservice); -#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. */ - } - - SDL_PrivateJoystickAdded(device->instance_id); -} - -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; -} - - -static int -DARWIN_JoystickInit(void) -{ - if (gpDeviceList) { - return SDL_SetError("Joystick: Device list already inited."); - } - - if (!CreateHIDManager()) { - return SDL_SetError("Joystick: Couldn't initialize HID Manager"); - } - - return 0; -} - -static int -DARWIN_JoystickGetCount(void) -{ - recDevice *device = gpDeviceList; - int nJoySticks = 0; - - while (device) { - if (!device->removed) { - nJoySticks++; - } - device = device->pNext; - } - - return nJoySticks; -} - -static void -DARWIN_JoystickDetect(void) -{ - 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 - DARWIN_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 * -DARWIN_JoystickGetDeviceName(int device_index) -{ - recDevice *device = GetDeviceForIndex(device_index); - return device ? device->product : "UNKNOWN"; -} - -static int -DARWIN_JoystickGetDevicePlayerIndex(int device_index) -{ - return -1; -} - -static SDL_JoystickGUID -DARWIN_JoystickGetDeviceGUID( int device_index ) -{ - recDevice *device = GetDeviceForIndex(device_index); - SDL_JoystickGUID guid; - if (device) { - guid = device->guid; - } else { - SDL_zero(guid); - } - return guid; -} - -static SDL_JoystickID -DARWIN_JoystickGetDeviceInstanceID(int device_index) -{ - recDevice *device = GetDeviceForIndex(device_index); - return device ? device->instance_id : 0; -} - -static int -DARWIN_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; -} - -/* - * Like strerror but for force feedback errors. - */ -static const char * -FFStrError(unsigned int err) -{ - switch (err) { - case FFERR_DEVICEFULL: - return "device full"; - /* This should be valid, but for some reason isn't defined... */ - /* case FFERR_DEVICENOTREG: - return "device not registered"; */ - case FFERR_DEVICEPAUSED: - return "device paused"; - case FFERR_DEVICERELEASED: - return "device released"; - case FFERR_EFFECTPLAYING: - return "effect playing"; - case FFERR_EFFECTTYPEMISMATCH: - return "effect type mismatch"; - case FFERR_EFFECTTYPENOTSUPPORTED: - return "effect type not supported"; - case FFERR_GENERIC: - return "undetermined error"; - case FFERR_HASEFFECTS: - return "device has effects"; - case FFERR_INCOMPLETEEFFECT: - return "incomplete effect"; - case FFERR_INTERNAL: - return "internal fault"; - case FFERR_INVALIDDOWNLOADID: - return "invalid download id"; - case FFERR_INVALIDPARAM: - return "invalid parameter"; - case FFERR_MOREDATA: - return "more data"; - case FFERR_NOINTERFACE: - return "interface not supported"; - case FFERR_NOTDOWNLOADED: - return "effect is not downloaded"; - case FFERR_NOTINITIALIZED: - return "object has not been initialized"; - case FFERR_OUTOFMEMORY: - return "out of memory"; - case FFERR_UNPLUGGED: - return "device is unplugged"; - case FFERR_UNSUPPORTED: - return "function call unsupported"; - case FFERR_UNSUPPORTEDAXIS: - return "axis unsupported"; - - default: - return "unknown error"; - } -} - -static int -DARWIN_JoystickInitRumble(recDevice *device, Sint16 magnitude, Uint32 duration_ms) -{ - HRESULT result; - - if (!device->ffdevice) { - result = FFCreateDevice(device->ffservice, &device->ffdevice); - if (result != FF_OK) { - return SDL_SetError("Unable to create force feedback device from service: %s", FFStrError(result)); - } - } - - /* Reset and then enable actuators */ - result = FFDeviceSendForceFeedbackCommand(device->ffdevice, FFSFFC_RESET); - if (result != FF_OK) { - return SDL_SetError("Unable to reset force feedback device: %s", FFStrError(result)); - } - - result = FFDeviceSendForceFeedbackCommand(device->ffdevice, FFSFFC_SETACTUATORSON); - if (result != FF_OK) { - return SDL_SetError("Unable to enable force feedback actuators: %s", FFStrError(result)); - } - - /* Create the effect */ - device->ffeffect = CreateRumbleEffectData(magnitude, duration_ms); - if (!device->ffeffect) { - return SDL_OutOfMemory(); - } - - result = FFDeviceCreateEffect(device->ffdevice, kFFEffectType_Sine_ID, - device->ffeffect, &device->ffeffect_ref); - if (result != FF_OK) { - return SDL_SetError("Haptic: Unable to create effect: %s", FFStrError(result)); - } - return 0; -} - -static int -DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) -{ - HRESULT result; - recDevice *device = joystick->hwdata; - - /* Scale and average the two rumble strengths */ - Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2); - - if (!device->ffservice) { - return SDL_Unsupported(); - } - - if (device->ff_initialized) { - FFPERIODIC *periodic = ((FFPERIODIC *)device->ffeffect->lpvTypeSpecificParams); - device->ffeffect->dwDuration = duration_ms * 1000; /* In microseconds. */ - periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); - - result = FFEffectSetParameters(device->ffeffect_ref, device->ffeffect, - (FFEP_DURATION | FFEP_TYPESPECIFICPARAMS)); - if (result != FF_OK) { - return SDL_SetError("Unable to update rumble effect: %s", FFStrError(result)); - } - } else { - if (DARWIN_JoystickInitRumble(device, magnitude, duration_ms) < 0) { - return -1; - } - device->ff_initialized = SDL_TRUE; - } - - result = FFEffectStart(device->ffeffect_ref, 1, 0); - if (result != FF_OK) { - return SDL_SetError("Unable to run the rumble effect: %s", FFStrError(result)); - } - return 0; -} - -static void -DARWIN_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; - - int goodRead = SDL_FALSE; - while (element) { - goodRead = GetHIDScaledCalibratedState(device, element, -32768, 32767, &value); - if (goodRead) { - SDL_PrivateJoystickAxis(joystick, i, value); - } - - element = element->pNext; - ++i; - } - - element = device->firstButton; - i = 0; - while (element) { - goodRead = GetHIDElementState(device, element, &value); - if (goodRead) { - if (value > 1) { /* handle pressure-sensitive buttons */ - value = 1; - } - 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); - goodRead = GetHIDElementState(device, element, &value); - if (goodRead) { - value -= 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; - } - - SDL_PrivateJoystickHat(joystick, i, pos); - } - - element = element->pNext; - ++i; - } -} - -static void -DARWIN_JoystickClose(SDL_Joystick * joystick) -{ -} - -static void -DARWIN_JoystickQuit(void) -{ - while (FreeDevice(gpDeviceList)) { - /* spin */ - } - - if (hidman) { - IOHIDManagerUnscheduleFromRunLoop(hidman, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE); - IOHIDManagerClose(hidman, kIOHIDOptionsTypeNone); - CFRelease(hidman); - hidman = NULL; - } -} - -SDL_JoystickDriver SDL_DARWIN_JoystickDriver = -{ - DARWIN_JoystickInit, - DARWIN_JoystickGetCount, - DARWIN_JoystickDetect, - DARWIN_JoystickGetDeviceName, - DARWIN_JoystickGetDevicePlayerIndex, - DARWIN_JoystickGetDeviceGUID, - DARWIN_JoystickGetDeviceInstanceID, - DARWIN_JoystickOpen, - DARWIN_JoystickRumble, - DARWIN_JoystickUpdate, - DARWIN_JoystickClose, - DARWIN_JoystickQuit, -}; - -#endif /* SDL_JOYSTICK_IOKIT */ - -/* vi: set ts=4 sw=4 expandtab: */ |