|
@@ -33,12 +33,12 @@
|
|
|
#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
|
|
|
#include "../../joystick/windows/SDL_dxjoystick_c.h" /* For joystick hwdata */
|
|
|
|
|
|
-#define MAX_HAPTICS 32
|
|
|
+#include "SDL_syshaptic_c.h"
|
|
|
|
|
|
/*
|
|
|
* List of available haptic devices.
|
|
|
*/
|
|
|
-static struct
|
|
|
+typedef struct SDL_hapticlist_item
|
|
|
{
|
|
|
DIDEVICEINSTANCE instance;
|
|
|
char *name;
|
|
@@ -46,7 +46,8 @@ static struct
|
|
|
DIDEVCAPS capabilities;
|
|
|
Uint8 bXInputHaptic; /* Supports force feedback via XInput. */
|
|
|
Uint8 userid; /* XInput userid index for this joystick */
|
|
|
-} SDL_hapticlist[MAX_HAPTICS];
|
|
|
+ struct SDL_hapticlist_item *next;
|
|
|
+} SDL_hapticlist_item;
|
|
|
|
|
|
|
|
|
/*
|
|
@@ -83,7 +84,9 @@ struct haptic_hweffect
|
|
|
static SDL_bool coinitialized = SDL_FALSE;
|
|
|
static LPDIRECTINPUT8 dinput = NULL;
|
|
|
static SDL_bool loaded_xinput = SDL_FALSE;
|
|
|
-
|
|
|
+static SDL_hapticlist_item *SDL_hapticlist = NULL;
|
|
|
+static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
|
|
|
+static int numhaptics = 0;
|
|
|
|
|
|
/*
|
|
|
* External stuff.
|
|
@@ -101,7 +104,7 @@ static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic,
|
|
|
static int SDL_SYS_HapticOpenFromDevice8(SDL_Haptic * haptic,
|
|
|
LPDIRECTINPUTDEVICE8 device8,
|
|
|
SDL_bool is_joystick);
|
|
|
-static int SDL_SYS_HapticOpenFromXInput(SDL_Haptic * haptic, Uint8 userid);
|
|
|
+static int SDL_SYS_HapticOpenFromXInput(SDL_Haptic * haptic, const Uint8 userid);
|
|
|
static DWORD DIGetTriggerButton(Uint16 button);
|
|
|
static int SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir,
|
|
|
int naxes);
|
|
@@ -155,11 +158,6 @@ SDL_SYS_HapticInit(void)
|
|
|
return SDL_SetError("Haptic: SubSystem already open.");
|
|
|
}
|
|
|
|
|
|
- /* Clear all the memory. */
|
|
|
- SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist));
|
|
|
-
|
|
|
- SDL_numhaptics = 0;
|
|
|
-
|
|
|
ret = WIN_CoInitialize();
|
|
|
if (FAILED(ret)) {
|
|
|
return DI_SetError("Coinitialize", ret);
|
|
@@ -205,73 +203,251 @@ SDL_SYS_HapticInit(void)
|
|
|
|
|
|
if (loaded_xinput) {
|
|
|
DWORD i;
|
|
|
- const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4));
|
|
|
-
|
|
|
- for (i = 0; (i < SDL_XINPUT_MAX_DEVICES) && (SDL_numhaptics < MAX_HAPTICS); i++) {
|
|
|
- XINPUT_CAPABILITIES caps;
|
|
|
- if (XINPUTGETCAPABILITIES(i, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) {
|
|
|
- if ((!bIs14OrLater) || (caps.Flags & XINPUT_CAPS_FFB_SUPPORTED)) {
|
|
|
- /* !!! FIXME: I'm not bothering to query for a real name right now. */
|
|
|
- char buf[64];
|
|
|
- SDL_snprintf(buf, sizeof (buf), "XInput Controller #%u", i+1);
|
|
|
- SDL_hapticlist[SDL_numhaptics].name = SDL_strdup(buf);
|
|
|
- SDL_hapticlist[SDL_numhaptics].bXInputHaptic = 1;
|
|
|
- SDL_hapticlist[SDL_numhaptics].userid = (Uint8) i;
|
|
|
- SDL_numhaptics++;
|
|
|
- }
|
|
|
- }
|
|
|
+ for (i = 0; i < SDL_XINPUT_MAX_DEVICES; i++) {
|
|
|
+ XInputHaptic_MaybeAddDevice(i);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return SDL_numhaptics;
|
|
|
+ return numhaptics;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Callback to find the haptic devices.
|
|
|
- */
|
|
|
-static BOOL CALLBACK
|
|
|
-EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
|
|
|
+
|
|
|
+int
|
|
|
+DirectInputHaptic_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)
|
|
|
{
|
|
|
HRESULT ret;
|
|
|
LPDIRECTINPUTDEVICE8 device;
|
|
|
+ const DWORD needflags = DIDC_ATTACHED | DIDC_FORCEFEEDBACK;
|
|
|
+ DIDEVCAPS capabilities;
|
|
|
+ SDL_hapticlist_item *item = NULL;
|
|
|
|
|
|
- /* Copy the instance over, useful for creating devices. */
|
|
|
- SDL_memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance,
|
|
|
- sizeof(DIDEVICEINSTANCE));
|
|
|
+ /* Make sure we don't already have it */
|
|
|
+ for (item = SDL_hapticlist; item; item = item->next) {
|
|
|
+ if ( (!item->bXInputHaptic) && (SDL_memcmp(&item->instance, pdidInstance, sizeof (*pdidInstance)) == 0) ) {
|
|
|
+ return -1; /* Already added */
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/* Open the device */
|
|
|
- ret = IDirectInput8_CreateDevice(dinput, &pdidInstance->guidInstance,
|
|
|
- &device, NULL);
|
|
|
+ ret = IDirectInput8_CreateDevice(dinput, &pdidInstance->guidInstance, &device, NULL);
|
|
|
if (FAILED(ret)) {
|
|
|
/* DI_SetError("Creating DirectInput device",ret); */
|
|
|
- return DIENUM_CONTINUE;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
/* Get capabilities. */
|
|
|
- SDL_hapticlist[SDL_numhaptics].capabilities.dwSize = sizeof(DIDEVCAPS);
|
|
|
- ret = IDirectInputDevice8_GetCapabilities(device,
|
|
|
- &SDL_hapticlist[SDL_numhaptics].
|
|
|
- capabilities);
|
|
|
+ SDL_zero(capabilities);
|
|
|
+ capabilities.dwSize = sizeof (DIDEVCAPS);
|
|
|
+ ret = IDirectInputDevice8_GetCapabilities(device, &capabilities);
|
|
|
+ IDirectInputDevice8_Release(device);
|
|
|
if (FAILED(ret)) {
|
|
|
/* DI_SetError("Getting device capabilities",ret); */
|
|
|
- IDirectInputDevice8_Release(device);
|
|
|
- return DIENUM_CONTINUE;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- /* Copy the name */
|
|
|
- SDL_hapticlist[SDL_numhaptics].name = WIN_StringToUTF8(SDL_hapticlist[SDL_numhaptics].instance.tszProductName);
|
|
|
+ if ((capabilities.dwFlags & needflags) != needflags) {
|
|
|
+ return -1; /* not a device we can use. */
|
|
|
+ }
|
|
|
|
|
|
- /* Close up device and count it. */
|
|
|
- IDirectInputDevice8_Release(device);
|
|
|
- SDL_numhaptics++;
|
|
|
+ item = (SDL_hapticlist_item *)SDL_malloc( sizeof(SDL_hapticlist_item));
|
|
|
+ if (item == NULL) {
|
|
|
+ return SDL_OutOfMemory();
|
|
|
+ }
|
|
|
|
|
|
- /* Watch out for hard limit. */
|
|
|
- if (SDL_numhaptics >= MAX_HAPTICS)
|
|
|
- return DIENUM_STOP;
|
|
|
+ SDL_zerop(item);
|
|
|
|
|
|
- return DIENUM_CONTINUE;
|
|
|
+ item->name = WIN_StringToUTF8(pdidInstance->tszProductName);
|
|
|
+ if (!item->name) {
|
|
|
+ SDL_free(item);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Copy the instance over, useful for creating devices. */
|
|
|
+ SDL_memcpy(&item->instance, pdidInstance, sizeof (DIDEVICEINSTANCE));
|
|
|
+ SDL_memcpy(&item->capabilities, &capabilities, sizeof (capabilities));
|
|
|
+
|
|
|
+ if (SDL_hapticlist_tail == NULL) {
|
|
|
+ SDL_hapticlist = SDL_hapticlist_tail = item;
|
|
|
+ } else {
|
|
|
+ SDL_hapticlist_tail->next = item;
|
|
|
+ SDL_hapticlist_tail = item;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Device has been added. */
|
|
|
+ ++numhaptics;
|
|
|
+
|
|
|
+ return numhaptics;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int
|
|
|
+DirectInputHaptic_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)
|
|
|
+{
|
|
|
+ SDL_hapticlist_item *item;
|
|
|
+ SDL_hapticlist_item *prev = NULL;
|
|
|
+
|
|
|
+ for (item = SDL_hapticlist; item != NULL; item = item->next) {
|
|
|
+ if ( (!item->bXInputHaptic) && (SDL_memcmp(&item->instance, pdidInstance, sizeof (*pdidInstance)) == 0) ) {
|
|
|
+ /* found it, remove it. */
|
|
|
+ const int retval = item->haptic ? item->haptic->index : -1;
|
|
|
+ if (prev != NULL) {
|
|
|
+ prev->next = item->next;
|
|
|
+ } else {
|
|
|
+ SDL_assert(SDL_hapticlist == item);
|
|
|
+ SDL_hapticlist = item->next;
|
|
|
+ }
|
|
|
+ if (item == SDL_hapticlist_tail) {
|
|
|
+ SDL_hapticlist_tail = prev;
|
|
|
+ }
|
|
|
+ --numhaptics;
|
|
|
+ /* !!! TODO: Send a haptic remove event? */
|
|
|
+ SDL_free(item);
|
|
|
+ return retval;
|
|
|
+ }
|
|
|
+ prev = item;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int
|
|
|
+XInputHaptic_MaybeAddDevice(const DWORD dwUserid)
|
|
|
+{
|
|
|
+ const Uint8 userid = (Uint8) dwUserid;
|
|
|
+ XINPUT_CAPABILITIES caps;
|
|
|
+ const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4));
|
|
|
+ SDL_hapticlist_item *item;
|
|
|
+
|
|
|
+ if ((!loaded_xinput) || (dwUserid >= SDL_XINPUT_MAX_DEVICES)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Make sure we don't already have it */
|
|
|
+ for (item = SDL_hapticlist; item; item = item->next) {
|
|
|
+ if ((item->bXInputHaptic) && (item->userid == userid)) {
|
|
|
+ return -1; /* Already added */
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (XINPUTGETCAPABILITIES(dwUserid, XINPUT_FLAG_GAMEPAD, &caps) != ERROR_SUCCESS) {
|
|
|
+ return -1; /* maybe controller isn't plugged in. */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* XInput < 1.4 is probably only for original XBox360 controllers,
|
|
|
+ which don't offer the flag, and always have force feedback */
|
|
|
+ if ( (bIs14OrLater) && ((caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) == 0) ) {
|
|
|
+ return -1; /* no force feedback on this device. */
|
|
|
+ }
|
|
|
+
|
|
|
+ item = (SDL_hapticlist_item *)SDL_malloc( sizeof(SDL_hapticlist_item));
|
|
|
+ if (item == NULL) {
|
|
|
+ return SDL_OutOfMemory();
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_zerop(item);
|
|
|
+
|
|
|
+ /* !!! FIXME: I'm not bothering to query for a real name right now (can we even?) */
|
|
|
+ {
|
|
|
+ char buf[64];
|
|
|
+ SDL_snprintf(buf, sizeof (buf), "XInput Controller #%u", (unsigned int) (userid+1));
|
|
|
+ item->name = SDL_strdup(buf);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!item->name) {
|
|
|
+ SDL_free(item);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Copy the instance over, useful for creating devices. */
|
|
|
+ item->bXInputHaptic = 1;
|
|
|
+ item->userid = userid;
|
|
|
+
|
|
|
+ if (SDL_hapticlist_tail == NULL) {
|
|
|
+ SDL_hapticlist = SDL_hapticlist_tail = item;
|
|
|
+ } else {
|
|
|
+ SDL_hapticlist_tail->next = item;
|
|
|
+ SDL_hapticlist_tail = item;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Device has been added. */
|
|
|
+ ++numhaptics;
|
|
|
+
|
|
|
+ return numhaptics;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int
|
|
|
+XInputHaptic_MaybeRemoveDevice(const DWORD dwUserid)
|
|
|
+{
|
|
|
+ const Uint8 userid = (Uint8) dwUserid;
|
|
|
+ SDL_hapticlist_item *item;
|
|
|
+ SDL_hapticlist_item *prev = NULL;
|
|
|
+
|
|
|
+ if ((!loaded_xinput) || (dwUserid >= SDL_XINPUT_MAX_DEVICES)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (item = SDL_hapticlist; item != NULL; item = item->next) {
|
|
|
+ if ((item->bXInputHaptic) && (item->userid == userid)) {
|
|
|
+ /* found it, remove it. */
|
|
|
+ const int retval = item->haptic ? item->haptic->index : -1;
|
|
|
+ if (prev != NULL) {
|
|
|
+ prev->next = item->next;
|
|
|
+ } else {
|
|
|
+ SDL_assert(SDL_hapticlist == item);
|
|
|
+ SDL_hapticlist = item->next;
|
|
|
+ }
|
|
|
+ if (item == SDL_hapticlist_tail) {
|
|
|
+ SDL_hapticlist_tail = prev;
|
|
|
+ }
|
|
|
+ --numhaptics;
|
|
|
+ /* !!! TODO: Send a haptic remove event? */
|
|
|
+ SDL_free(item);
|
|
|
+ return retval;
|
|
|
+ }
|
|
|
+ prev = item;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * Callback to find the haptic devices.
|
|
|
+ */
|
|
|
+static BOOL CALLBACK
|
|
|
+EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
|
|
|
+{
|
|
|
+ (void) pContext;
|
|
|
+ DirectInputHaptic_MaybeAddDevice(pdidInstance);
|
|
|
+ return DIENUM_CONTINUE; /* continue enumerating */
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int
|
|
|
+SDL_SYS_NumHaptics()
|
|
|
+{
|
|
|
+ return numhaptics;
|
|
|
}
|
|
|
|
|
|
+static SDL_hapticlist_item *
|
|
|
+HapticByDevIndex(int device_index)
|
|
|
+{
|
|
|
+ SDL_hapticlist_item *item = SDL_hapticlist;
|
|
|
+
|
|
|
+ if ((device_index < 0) || (device_index >= numhaptics)) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (device_index > 0) {
|
|
|
+ SDL_assert(item != NULL);
|
|
|
+ device_index--;
|
|
|
+ item = item->next;
|
|
|
+ }
|
|
|
+
|
|
|
+ return item;
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
* Return the name of a haptic device, does not need to be opened.
|
|
@@ -279,7 +455,8 @@ EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
|
|
|
const char *
|
|
|
SDL_SYS_HapticName(int index)
|
|
|
{
|
|
|
- return SDL_hapticlist[index].name;
|
|
|
+ SDL_hapticlist_item *item = HapticByDevIndex(index);
|
|
|
+ return item->name;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -384,7 +561,7 @@ SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance)
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-SDL_SYS_HapticOpenFromXInput(SDL_Haptic * haptic, Uint8 userid)
|
|
|
+SDL_SYS_HapticOpenFromXInput(SDL_Haptic *haptic, const Uint8 userid)
|
|
|
{
|
|
|
char threadName[32];
|
|
|
XINPUT_VIBRATION vibration = { 0, 0 }; /* stop any current vibration */
|
|
@@ -595,11 +772,8 @@ SDL_SYS_HapticOpenFromDevice8(SDL_Haptic * haptic,
|
|
|
int
|
|
|
SDL_SYS_HapticOpen(SDL_Haptic * haptic)
|
|
|
{
|
|
|
- if (SDL_hapticlist[haptic->index].bXInputHaptic) {
|
|
|
- return SDL_SYS_HapticOpenFromXInput(haptic, SDL_hapticlist[haptic->index].userid);
|
|
|
- }
|
|
|
-
|
|
|
- return SDL_SYS_HapticOpenFromInstance(haptic, SDL_hapticlist[haptic->index].instance);
|
|
|
+ SDL_hapticlist_item *item = HapticByDevIndex(haptic->index);
|
|
|
+ return (item->bXInputHaptic) ? SDL_SYS_HapticOpenFromXInput(haptic, item->userid) : SDL_SYS_HapticOpenFromInstance(haptic, item->instance);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -609,13 +783,16 @@ SDL_SYS_HapticOpen(SDL_Haptic * haptic)
|
|
|
int
|
|
|
SDL_SYS_HapticMouse(void)
|
|
|
{
|
|
|
- int i;
|
|
|
+ SDL_hapticlist_item *item;
|
|
|
+ int index = numhaptics-1;
|
|
|
|
|
|
/* Grab the first mouse haptic device we find. */
|
|
|
- for (i = 0; i < SDL_numhaptics; i++) {
|
|
|
- if (SDL_hapticlist[i].capabilities.dwDevType == DI8DEVCLASS_POINTER ) {
|
|
|
- return i;
|
|
|
+ for (item = SDL_hapticlist; item != NULL; item = item->next) {
|
|
|
+ SDL_assert(index >= 0);
|
|
|
+ if (item->capabilities.dwDevType == DI8DEVCLASS_POINTER ) {
|
|
|
+ return index;
|
|
|
}
|
|
|
+ index--;
|
|
|
}
|
|
|
|
|
|
return -1;
|
|
@@ -677,34 +854,39 @@ SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
|
|
|
int
|
|
|
SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
|
|
|
{
|
|
|
- int i;
|
|
|
- HRESULT idret;
|
|
|
- DIDEVICEINSTANCE joy_instance;
|
|
|
- joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
|
|
|
+ SDL_hapticlist_item *item;
|
|
|
+ int index = numhaptics-1;
|
|
|
|
|
|
/* Since it comes from a joystick we have to try to match it with a haptic device on our haptic list. */
|
|
|
if (joystick->hwdata->bXInputDevice) {
|
|
|
const Uint8 userid = joystick->hwdata->userid;
|
|
|
- for (i=0; i<SDL_numhaptics; i++) {
|
|
|
- if ((SDL_hapticlist[i].bXInputHaptic) && (SDL_hapticlist[i].userid == userid)) {
|
|
|
+ for (item = SDL_hapticlist; item != NULL; item = item->next) {
|
|
|
+ if ((item->bXInputHaptic) && (item->userid == userid)) {
|
|
|
SDL_assert(joystick->hwdata->bXInputHaptic);
|
|
|
- haptic->index = i;
|
|
|
- return SDL_SYS_HapticOpenFromXInput(haptic, SDL_hapticlist[haptic->index].userid);
|
|
|
+ haptic->index = index;
|
|
|
+ return SDL_SYS_HapticOpenFromXInput(haptic, userid);
|
|
|
}
|
|
|
+ index--;
|
|
|
}
|
|
|
} else {
|
|
|
- for (i=0; i<SDL_numhaptics; i++) {
|
|
|
- idret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, &joy_instance);
|
|
|
- if (FAILED(idret)) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (DI_GUIDIsSame(&SDL_hapticlist[i].instance.guidInstance,
|
|
|
- &joy_instance.guidInstance)) {
|
|
|
- haptic->index = i;
|
|
|
+ HRESULT idret;
|
|
|
+ DIDEVICEINSTANCE joy_instance;
|
|
|
+
|
|
|
+ joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
|
|
|
+ idret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, &joy_instance);
|
|
|
+ if (FAILED(idret)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (item = SDL_hapticlist; item != NULL; item = item->next) {
|
|
|
+ if (DI_GUIDIsSame(&item->instance.guidInstance, &joy_instance.guidInstance)) {
|
|
|
+ haptic->index = index;
|
|
|
return SDL_SYS_HapticOpenFromDevice8(haptic, joystick->hwdata->InputDevice, SDL_TRUE);
|
|
|
}
|
|
|
+ index--;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
/* No match to our haptic list */
|
|
|
return -1;
|
|
|
}
|
|
@@ -749,16 +931,20 @@ SDL_SYS_HapticClose(SDL_Haptic * haptic)
|
|
|
void
|
|
|
SDL_SYS_HapticQuit(void)
|
|
|
{
|
|
|
- int i;
|
|
|
+ SDL_hapticlist_item *item;
|
|
|
+ SDL_hapticlist_item *next = NULL;
|
|
|
|
|
|
if (loaded_xinput) {
|
|
|
WIN_UnloadXInputDLL();
|
|
|
loaded_xinput = SDL_FALSE;
|
|
|
}
|
|
|
|
|
|
- for (i = 0; i < SDL_arraysize(SDL_hapticlist); ++i) {
|
|
|
- SDL_free(SDL_hapticlist[i].name);
|
|
|
- SDL_hapticlist[i].name = NULL;
|
|
|
+ for (item = SDL_hapticlist; item; item = next) {
|
|
|
+ /* Opened and not closed haptics are leaked, this is on purpose.
|
|
|
+ * Close your haptic devices after usage. */
|
|
|
+ next = item->next;
|
|
|
+ SDL_free(item->name);
|
|
|
+ SDL_free(item);
|
|
|
}
|
|
|
|
|
|
if (dinput != NULL) {
|