summaryrefslogtreecommitdiff
path: root/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-01-31 18:38:35 +0800
committerchai <chaifix@163.com>2019-01-31 18:38:35 +0800
commit2ec55fd974a63b705a4777c256d2222c874fa043 (patch)
tree48f1fea59ee9fc713a28a9aac3f05b98dc5ae66f /Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c
parentc581dfbf1e849f393861d15e82aa6446c0c1c310 (diff)
*SDL project
Diffstat (limited to 'Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c')
-rw-r--r--Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c354
1 files changed, 268 insertions, 86 deletions
diff --git a/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c b/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c
index abfb1c6..8af3b96 100644
--- a/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c
+++ b/Source/3rdParty/SDL2/src/joystick/darwin/SDL_sysjoystick.c
@@ -22,29 +22,79 @@
#ifdef SDL_JOYSTICK_IOKIT
-#include <IOKit/hid/IOHIDLib.h>
-
-/* For force feedback testing. */
-#include <ForceFeedback/ForceFeedback.h>
-#include <ForceFeedback/ForceFeedbackConstants.h>
-
+#include "SDL_events.h"
#include "SDL_joystick.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
#include "SDL_sysjoystick_c.h"
-#include "SDL_events.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;
-/* static incrementing counter for new joystick devices seen on the system. Devices should start with index 0 */
-static int s_joystick_instance_id = -1;
+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)
{
@@ -157,6 +207,19 @@ 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
@@ -333,8 +396,6 @@ AddHIDElement(const void *value, void *parameter)
static SDL_bool
GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
{
- const Uint16 BUS_USB = 0x03;
- const Uint16 BUS_BLUETOOTH = 0x05;
Sint32 vendor = 0;
Sint32 product = 0;
Sint32 version = 0;
@@ -389,10 +450,17 @@ GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
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(BUS_USB);
+ *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
*guid16++ = 0;
*guid16++ = SDL_SwapLE16((Uint16)vendor);
*guid16++ = 0;
@@ -401,7 +469,7 @@ GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
*guid16++ = SDL_SwapLE16((Uint16)version);
*guid16++ = 0;
} else {
- *guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
+ *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH);
*guid16++ = 0;
SDL_strlcpy((char*)guid16, pDevice->product, sizeof(pDevice->guid.data) - 4);
}
@@ -444,7 +512,6 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
}
device = (recDevice *) SDL_calloc(1, sizeof(recDevice));
-
if (!device) {
SDL_OutOfMemory();
return;
@@ -455,8 +522,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
return; /* not a device we care about, probably. */
}
- if (SDL_IsGameControllerNameAndGUID(device->product, device->guid) &&
- SDL_ShouldIgnoreGameController(device->product, device->guid)) {
+ if (SDL_ShouldIgnoreJoystick(device->product, device->guid)) {
SDL_free(device);
return;
}
@@ -466,16 +532,16 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
IOHIDDeviceScheduleWithRunLoop(ioHIDDeviceObject, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE);
/* Allocate an instance ID for this device */
- device->instance_id = ++s_joystick_instance_id;
+ device->instance_id = SDL_GetNextJoystickInstanceID();
/* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */
ioservice = IOHIDDeviceGetService(ioHIDDeviceObject);
-#if SDL_HAPTIC_IOKIT
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 ) {
@@ -492,7 +558,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
++device_index; /* bump by one since we counted by pNext. */
}
- SDL_PrivateJoystickAdded(device_index);
+ SDL_PrivateJoystickAdded(device->instance_id);
}
static SDL_bool
@@ -577,13 +643,8 @@ CreateHIDManager(void)
}
-/* 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)
+static int
+DARWIN_JoystickInit(void)
{
if (gpDeviceList) {
return SDL_SetError("Joystick: Device list already inited.");
@@ -593,12 +654,11 @@ SDL_SYS_JoystickInit(void)
return SDL_SetError("Joystick: Couldn't initialize HID Manager");
}
- return SDL_SYS_NumJoysticks();
+ return 0;
}
-/* Function to return the number of joystick devices plugged in right now */
-int
-SDL_SYS_NumJoysticks(void)
+static int
+DARWIN_JoystickGetCount(void)
{
recDevice *device = gpDeviceList;
int nJoySticks = 0;
@@ -613,10 +673,8 @@ SDL_SYS_NumJoysticks(void)
return nJoySticks;
}
-/* Function to cause any queued joystick insertions to be processed
- */
-void
-SDL_SYS_JoystickDetect(void)
+static void
+DARWIN_JoystickDetect(void)
{
recDevice *device = gpDeviceList;
while (device) {
@@ -627,37 +685,49 @@ SDL_SYS_JoystickDetect(void)
}
}
- /* 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(). */
- }
+ /* 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 *
-SDL_SYS_JoystickNameForDeviceIndex(int device_index)
+DARWIN_JoystickGetDeviceName(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)
+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;
}
-/* 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)
+static int
+DARWIN_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
recDevice *device = GetDeviceForIndex(device_index);
@@ -672,22 +742,138 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
return 0;
}
-/* Function to query if the joystick is currently attached
- * It returns SDL_TRUE if attached, SDL_FALSE otherwise.
+/*
+ * Like strerror but for force feedback errors.
*/
-SDL_bool
-SDL_SYS_JoystickAttached(SDL_Joystick * joystick)
+static const char *
+FFStrError(unsigned int err)
{
- return joystick->hwdata != NULL;
+ 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";
+ }
}
-/* 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)
+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;
@@ -792,15 +978,13 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
}
}
-/* Function to close a joystick after use */
-void
-SDL_SYS_JoystickClose(SDL_Joystick * joystick)
+static void
+DARWIN_JoystickClose(SDL_Joystick * joystick)
{
}
-/* Function to perform any system-specific joystick related cleanup */
-void
-SDL_SYS_JoystickQuit(void)
+static void
+DARWIN_JoystickQuit(void)
{
while (FreeDevice(gpDeviceList)) {
/* spin */
@@ -814,23 +998,21 @@ SDL_SYS_JoystickQuit(void)
}
}
-
-SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
+SDL_JoystickDriver SDL_DARWIN_JoystickDriver =
{
- 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;
-}
+ 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 */