First shot at Windows XInput haptics.

--HG--
extra : rebase_source : 52e691a0917d173e891e67714a135373daea0ef5
This commit is contained in:
Ryan C. Gordon 2013-03-10 13:05:47 -04:00
parent 203b9839d2
commit 3d572bdf89
6 changed files with 327 additions and 133 deletions

View file

@ -203,7 +203,7 @@ extern "C" {
* "0" - Disable XInput timer (only uses direct input)
* "1" - Enable XInput timer (the default)
*/
#define SD_HINT_XINPUT_ENABLED "SDL_XINPUT_ENABLED"
#define SDL_HINT_XINPUT_ENABLED "SDL_XINPUT_ENABLED"
/**

View file

@ -24,10 +24,73 @@
#include "SDL_error.h"
#include "SDL_windows.h"
#include "SDL_assert.h"
#include <objbase.h> /* for CoInitialize/CoUninitialize */
XInputGetState_t SDL_XInputGetState = NULL;
XInputSetState_t SDL_XInputSetState = NULL;
XInputGetCapabilities_t SDL_XInputGetCapabilities = NULL;
DWORD SDL_XInputVersion = 0;
static HANDLE s_pXInputDLL = 0;
static int s_XInputDLLRefCount = 0;
int
WIN_LoadXInputDLL(void)
{
DWORD version = 0;
if (s_pXInputDLL) {
SDL_assert(s_XInputDLLRefCount > 0);
s_XInputDLLRefCount++;
return 0; /* already loaded */
}
version = (1 << 16) | 4;
s_pXInputDLL = LoadLibrary( L"XInput1_4.dll" ); // 1.4 Ships with Windows 8.
if (!s_pXInputDLL) {
version = (1 << 16) | 3;
s_pXInputDLL = LoadLibrary( L"XInput1_3.dll" ); // 1.3 Ships with Vista and Win7, can be installed as a restributable component.
}
if (!s_pXInputDLL) {
s_pXInputDLL = LoadLibrary( L"bin\\XInput1_3.dll" );
}
if (!s_pXInputDLL) {
return -1;
}
SDL_assert(s_XInputDLLRefCount == 0);
SDL_XInputVersion = version;
s_XInputDLLRefCount = 1;
/* 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think... */
SDL_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, (LPCSTR)100 );
SDL_XInputSetState = (XInputSetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputSetState" );
SDL_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetCapabilities" );
if ( !SDL_XInputGetState || !SDL_XInputSetState || !SDL_XInputGetCapabilities ) {
WIN_UnloadXInputDLL();
return -1;
}
return 0;
}
void
WIN_UnloadXInputDLL(void)
{
if ( s_pXInputDLL ) {
SDL_assert(s_XInputDLLRefCount > 0);
if (--s_XInputDLLRefCount == 0) {
FreeLibrary( s_pXInputDLL );
s_pXInputDLL = NULL;
}
} else {
SDL_assert(s_XInputDLLRefCount == 0);
}
}
/* Sets an error message based on GetLastError() */
void
WIN_SetError(const char *prefix)

View file

@ -33,7 +33,7 @@
#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
#include <windows.h>
#include <xinput.h>
/* Routines to convert from UTF8 to native Windows text */
#if UNICODE
@ -51,6 +51,64 @@ extern void WIN_SetError(const char *prefix);
extern HRESULT WIN_CoInitialize(void);
extern void WIN_CoUninitialize(void);
/* typedef's for XInput structs we use */
typedef struct
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
DWORD dwPaddingReserved;
} XINPUT_GAMEPAD_EX;
typedef struct
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD_EX Gamepad;
} XINPUT_STATE_EX;
/* Forward decl's for XInput API's we load dynamically and use if available */
typedef DWORD (WINAPI *XInputGetState_t)
(
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
XINPUT_STATE_EX* pState // [out] Receives the current state
);
typedef DWORD (WINAPI *XInputSetState_t)
(
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
XINPUT_VIBRATION* pVibration // [in, out] The vibration information to send to the controller
);
typedef DWORD (WINAPI *XInputGetCapabilities_t)
(
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
DWORD dwFlags, // [in] Input flags that identify the device type
XINPUT_CAPABILITIES* pCapabilities // [out] Receives the capabilities
);
extern int WIN_LoadXInputDLL(void);
extern void WIN_UnloadXInputDLL(void);
extern XInputGetState_t SDL_XInputGetState;
extern XInputSetState_t SDL_XInputSetState;
extern XInputGetCapabilities_t SDL_XInputGetCapabilities;
extern DWORD SDL_XInputVersion; // ((major << 16) & 0xFF00) | (minor & 0xFF)
#define XINPUTGETSTATE SDL_XInputGetState
#define XINPUTSETSTATE SDL_XInputSetState
#define XINPUTGETCAPABILITIES SDL_XInputGetCapabilities
#define INVALID_XINPUT_USERID 255
#define SDL_XINPUT_MAX_DEVICES 4
#ifndef XINPUT_CAPS_FFB_SUPPORTED
#define XINPUT_CAPS_FFB_SUPPORTED 0x0001
#endif
#endif /* _INCLUDED_WINDOWS_H */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -22,16 +22,16 @@
#ifdef SDL_HAPTIC_DINPUT
#include "SDL_assert.h"
#include "SDL_hints.h"
#include "SDL_haptic.h"
#include "../SDL_syshaptic.h"
#include "SDL_joystick.h"
#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
#include "../../joystick/windows/SDL_dxjoystick_c.h" /* For joystick hwdata */
#define MAX_HAPTICS 32
/*
* List of available haptic devices.
*/
@ -41,6 +41,8 @@ static struct
char *name;
SDL_Haptic *haptic;
DIDEVCAPS capabilities;
Uint8 bXInputHaptic; // Supports force feedback via XInput.
Uint8 userid; // XInput userid index for this joystick
} SDL_hapticlist[MAX_HAPTICS];
@ -52,6 +54,8 @@ struct haptic_hwdata
LPDIRECTINPUTDEVICE8 device;
DWORD axes[3]; /* Axes to use. */
int is_joystick; /* Device is loaded as joystick. */
Uint8 bXInputHaptic; // Supports force feedback via XInput.
Uint8 userid; // XInput userid index for this joystick
};
@ -62,6 +66,7 @@ struct haptic_hweffect
{
DIEFFECT effect;
LPDIRECTINPUTEFFECT ref;
XINPUT_VIBRATION vibration;
};
@ -70,6 +75,7 @@ struct haptic_hweffect
*/
static SDL_bool coinitialized = SDL_FALSE;
static LPDIRECTINPUT8 dinput = NULL;
static SDL_bool loaded_xinput = SDL_FALSE;
/*
@ -87,6 +93,7 @@ static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic,
DIDEVICEINSTANCE instance);
static int SDL_SYS_HapticOpenFromDevice8(SDL_Haptic * haptic,
LPDIRECTINPUTDEVICE8 device8);
static int SDL_SYS_HapticOpenFromXInput(SDL_Haptic * haptic, Uint8 userid);
static DWORD DIGetTriggerButton(Uint16 button);
static int SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir,
int naxes);
@ -130,6 +137,7 @@ DI_GUIDIsSame(const GUID * a, const GUID * b)
int
SDL_SYS_HapticInit(void)
{
const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED);
HRESULT ret;
HINSTANCE instance;
@ -187,6 +195,30 @@ SDL_SYS_HapticInit(void)
return -1;
}
if (!env || SDL_atoi(env)) {
loaded_xinput = (WIN_LoadXInputDLL() == 0);
}
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++;
}
}
}
}
return SDL_numhaptics;
}
@ -363,6 +395,43 @@ SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance)
return -1;
}
static int
SDL_SYS_HapticOpenFromXInput(SDL_Haptic * haptic, Uint8 userid)
{
XINPUT_VIBRATION vibration = { 0, 0 }; /* stop any current vibration */
XINPUTSETSTATE(userid, &vibration);
/* !!! FIXME: we can probably do more than SINE if we figure out how to set up the left and right motors properly. */
haptic->supported = SDL_HAPTIC_SINE;
haptic->neffects = 1;
haptic->nplaying = 1;
/* Prepare effects memory. */
haptic->effects = (struct haptic_effect *)
SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
if (haptic->effects == NULL) {
SDL_OutOfMemory();
return -1;
}
/* Clear the memory */
SDL_memset(haptic->effects, 0,
sizeof(struct haptic_effect) * haptic->neffects);
haptic->hwdata = (struct haptic_hwdata *) SDL_malloc(sizeof(*haptic->hwdata));
if (haptic->hwdata == NULL) {
SDL_free(haptic->effects);
haptic->effects = NULL;
SDL_OutOfMemory();
return -1;
}
SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
haptic->hwdata->bXInputHaptic = 1;
haptic->hwdata->userid = userid;
return 0;
}
/*
* Opens the haptic device from the file descriptor.
@ -504,9 +573,11 @@ SDL_SYS_HapticOpenFromDevice8(SDL_Haptic * haptic,
int
SDL_SYS_HapticOpen(SDL_Haptic * haptic)
{
return SDL_SYS_HapticOpenFromInstance(haptic,
SDL_hapticlist[haptic->index].
instance);
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);
}
@ -535,11 +606,9 @@ SDL_SYS_HapticMouse(void)
int
SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
{
if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
return SDL_TRUE;
}
return SDL_FALSE;
const struct joystick_hwdata *hwdata = joystick->hwdata;
return ( (hwdata->bXInputHaptic) ||
((hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) != 0) );
}
@ -549,25 +618,30 @@ SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
int
SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
{
HRESULT ret;
DIDEVICEINSTANCE hap_instance, joy_instance;
hap_instance.dwSize = sizeof(DIDEVICEINSTANCE);
joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
/* Get the device instances. */
ret = IDirectInputDevice8_GetDeviceInfo(haptic->hwdata->device,
&hap_instance);
if (FAILED(ret)) {
return 0;
}
ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice,
&joy_instance);
if (FAILED(ret)) {
return 0;
}
if (DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance))
if ((joystick->hwdata->bXInputHaptic == haptic->hwdata->bXInputHaptic) && (haptic->hwdata->userid == joystick->hwdata->userid)) {
return 1;
} else {
HRESULT ret;
DIDEVICEINSTANCE hap_instance, joy_instance;
hap_instance.dwSize = sizeof(DIDEVICEINSTANCE);
joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
/* Get the device instances. */
ret = IDirectInputDevice8_GetDeviceInfo(haptic->hwdata->device,
&hap_instance);
if (FAILED(ret)) {
return 0;
}
ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice,
&joy_instance);
if (FAILED(ret)) {
return 0;
}
if (DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance))
return 1;
}
return 0;
}
@ -585,16 +659,27 @@ SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
/* Since it comes from a joystick we have to try to match it with a haptic device on our haptic list. */
for (i=0; i<SDL_numhaptics; i++) {
idret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice,
&joy_instance);
if (FAILED(idret)) {
return -1;
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)) {
SDL_assert(joystick->hwdata->bXInputHaptic);
haptic->index = i;
break;
}
}
if (DI_GUIDIsSame(&SDL_hapticlist[i].instance.guidInstance,
&joy_instance.guidInstance)) {
haptic->index = i;
break;
} 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;
break;
}
}
}
if (i >= SDL_numhaptics) {
@ -611,14 +696,17 @@ SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
/* Now open the device. */
ret =
SDL_SYS_HapticOpenFromDevice8(haptic, joystick->hwdata->InputDevice);
if (ret < 0) {
return -1;
if (!joystick->hwdata->bXInputHaptic) {
ret = SDL_SYS_HapticOpenFromDevice8(haptic, joystick->hwdata->InputDevice);
if (ret < 0) {
return -1;
}
}
/* It's using the joystick device. */
haptic->hwdata->is_joystick = 1;
haptic->hwdata->bXInputHaptic = joystick->hwdata->bXInputHaptic;
haptic->hwdata->userid = joystick->hwdata->userid;
return 0;
}
@ -638,10 +726,12 @@ SDL_SYS_HapticClose(SDL_Haptic * haptic)
haptic->neffects = 0;
/* Clean up */
IDirectInputDevice8_Unacquire(haptic->hwdata->device);
/* Only release if isn't grabbed by a joystick. */
if (haptic->hwdata->is_joystick == 0) {
IDirectInputDevice8_Release(haptic->hwdata->device);
if (!haptic->hwdata->bXInputHaptic) {
IDirectInputDevice8_Unacquire(haptic->hwdata->device);
/* Only release if isn't grabbed by a joystick. */
if (haptic->hwdata->is_joystick == 0) {
IDirectInputDevice8_Release(haptic->hwdata->device);
}
}
/* Free */
@ -659,6 +749,11 @@ SDL_SYS_HapticQuit(void)
{
int i;
if (loaded_xinput) {
WIN_UnloadXInputDLL();
loaded_xinput = SDL_FALSE;
}
for (i = 0; i < SDL_arraysize(SDL_hapticlist); ++i) {
if (SDL_hapticlist[i].name) {
SDL_free(SDL_hapticlist[i].name);
@ -1127,9 +1222,8 @@ SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
SDL_HapticEffect * base)
{
HRESULT ret;
/* Get the type. */
REFGUID type = SDL_SYS_HapticEffectType(base);
if (type == NULL) {
goto err_hweffect;
}
@ -1142,6 +1236,13 @@ SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
goto err_hweffect;
}
SDL_zerop(effect->hweffect);
if (haptic->hwdata->bXInputHaptic) {
SDL_assert(base->type == SDL_HAPTIC_SINE); /* should catch this at higher level */
return SDL_SYS_HapticUpdateEffect(haptic, effect, base);
}
/* Get the effect. */
if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
goto err_effectdone;
@ -1181,6 +1282,23 @@ SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
DWORD flags;
DIEFFECT temp;
if (haptic->hwdata->bXInputHaptic) {
// !!! FIXME: this isn't close to right. We only support "sine" effects,
// !!! FIXME: we ignore most of the parameters, and we probably get
// !!! FIXME: the ones we don't ignore wrong, too.
// !!! FIXME: if I had a better understanding of how the two motors
// !!! FIXME: could be used in unison, perhaps I could implement other
// !!! FIXME: effect types?
/* From MSDN:
"Note that the right motor is the high-frequency motor, the left
motor is the low-frequency motor. They do not always need to be
set to the same amount, as they provide different effects." */
XINPUT_VIBRATION *vib = &effect->hweffect->vibration;
SDL_assert(data->type == SDL_HAPTIC_SINE);
vib->wLeftMotorSpeed = vib->wRightMotorSpeed = data->periodic.magnitude * 2;
return 0;
}
/* Get the effect. */
SDL_memset(&temp, 0, sizeof(DIEFFECT));
if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
@ -1226,6 +1344,11 @@ SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
HRESULT ret;
DWORD iter;
if (haptic->hwdata->bXInputHaptic) {
XINPUT_VIBRATION *vib = &effect->hweffect->vibration;
return (XINPUTSETSTATE(haptic->hwdata->userid, vib) == ERROR_SUCCESS);
}
/* Check if it's infinite. */
if (iterations == SDL_HAPTIC_INFINITY) {
iter = INFINITE;
@ -1251,6 +1374,11 @@ SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
{
HRESULT ret;
if (haptic->hwdata->bXInputHaptic) {
XINPUT_VIBRATION vibration = { 0, 0 };
return (XINPUTSETSTATE(haptic->hwdata->userid, &vibration) == ERROR_SUCCESS);
}
ret = IDirectInputEffect_Stop(effect->hweffect->ref);
if (FAILED(ret)) {
DI_SetError("Unable to stop effect", ret);
@ -1269,12 +1397,16 @@ SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
{
HRESULT ret;
ret = IDirectInputEffect_Unload(effect->hweffect->ref);
if (FAILED(ret)) {
DI_SetError("Removing effect from the device", ret);
if (haptic->hwdata->bXInputHaptic) {
SDL_SYS_HapticStopEffect(haptic, effect);
} else {
ret = IDirectInputEffect_Unload(effect->hweffect->ref);
if (FAILED(ret)) {
DI_SetError("Removing effect from the device", ret);
}
SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect,
effect->effect.type);
}
SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect,
effect->effect.type);
SDL_free(effect->hweffect);
effect->hweffect = NULL;
}
@ -1407,6 +1539,11 @@ SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
{
HRESULT ret;
if (haptic->hwdata->bXInputHaptic) {
XINPUT_VIBRATION vibration = { 0, 0 };
return (XINPUTSETSTATE(haptic->hwdata->userid, &vibration) == ERROR_SUCCESS);
}
/* Try to stop the effects. */
ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
DISFFC_STOPALL);

View file

@ -73,7 +73,6 @@ static SDL_cond *s_condJoystickThread = NULL;
static SDL_mutex *s_mutexJoyStickEnum = NULL;
static SDL_Thread *s_threadJoystick = NULL;
static SDL_bool s_bJoystickThreadQuit = SDL_FALSE;
static HANDLE s_pXInputDLL = 0;
static SDL_bool s_bXInputEnabled = SDL_TRUE;
extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
@ -91,36 +90,6 @@ struct JoyStick_DeviceData_
struct JoyStick_DeviceData_ *pNext;
};
/* Forward decl's for XInput API's we load dynamically and use if available */
typedef DWORD (WINAPI *XInputGetState_t)
(
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
XINPUT_STATE_EX* pState // [out] Receives the current state
);
typedef DWORD (WINAPI *XInputSetState_t)
(
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
XINPUT_VIBRATION* pVibration // [in, out] The vibration information to send to the controller
);
typedef DWORD (WINAPI *XInputGetCapabilities_t)
(
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
DWORD dwFlags, // [in] Input flags that identify the device type
XINPUT_CAPABILITIES* pCapabilities // [out] Receives the capabilities
);
XInputGetState_t PC_XInputGetState;
XInputSetState_t PC_XInputSetState;
XInputGetCapabilities_t PC_XInputGetCapabilities;
#define XINPUTGETSTATE PC_XInputGetState
#define XINPUTSETSTATE PC_XInputSetState
#define XINPUTGETCAPABILITIES PC_XInputGetCapabilities
#define INVALID_XINPUT_USERID 255
typedef struct JoyStick_DeviceData_ JoyStick_DeviceData;
static JoyStick_DeviceData *SYS_Joystick; /* array to hold joystick ID values */
@ -634,7 +603,7 @@ SDL_SYS_JoystickInit(void)
{
HRESULT result;
HINSTANCE instance;
const char *env = SDL_GetHint(SD_HINT_XINPUT_ENABLED);
const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED);
if (env && !SDL_atoi(env)) {
s_bXInputEnabled = SDL_FALSE;
}
@ -672,32 +641,15 @@ SDL_SYS_JoystickInit(void)
return (-1);
}
s_mutexJoyStickEnum = SDL_CreateMutex();
s_condJoystickThread = SDL_CreateCond();
s_bDeviceAdded = SDL_TRUE; // force a scan of the system for joysticks this first time
SDL_SYS_JoystickDetect();
s_mutexJoyStickEnum = SDL_CreateMutex();
s_condJoystickThread = SDL_CreateCond();
s_bDeviceAdded = SDL_TRUE; // force a scan of the system for joysticks this first time
SDL_SYS_JoystickDetect();
if (s_bXInputEnabled) {
// try to load XInput support if available
s_pXInputDLL = LoadLibrary( L"XInput1_3.dll" );
if ( !s_pXInputDLL )
s_pXInputDLL = LoadLibrary( L"bin\\XInput1_3.dll" );
if ( s_pXInputDLL )
{
// 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think...
PC_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, (LPCSTR)100 );
PC_XInputSetState = (XInputSetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputSetState" );
PC_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetCapabilities" );
if ( !PC_XInputGetState || !PC_XInputSetState || !PC_XInputGetCapabilities )
{
SDL_SYS_JoystickQuit();
SDL_SetError("GetProcAddress() failed when loading XInput.", GetLastError());
return (-1);
}
}
if ((s_bXInputEnabled) && (WIN_LoadXInputDLL() == -1)) {
s_bXInputEnabled = SDL_FALSE; /* oh well. */
}
if ( !s_threadJoystick )
{
s_bJoystickThreadQuit = SDL_FALSE;
@ -978,6 +930,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
result = XINPUTGETCAPABILITIES( userId, XINPUT_FLAG_GAMEPAD, &capabilities );
if ( result == ERROR_SUCCESS )
{
const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4));
SDL_bool bIsSupported = SDL_FALSE;
// Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad.
bIsSupported = ( capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD );
@ -990,6 +943,9 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
// valid
joystick->hwdata->bXInputDevice = SDL_TRUE;
if ((!bIs14OrLater) || (capabilities.Flags & XINPUT_CAPS_FFB_SUPPORTED)) {
joystick->hwdata->bXInputHaptic = SDL_TRUE;
}
SDL_memset( joystick->hwdata->XInputState, 0x0, sizeof(joystick->hwdata->XInputState) );
joystickdevice->XInputUserId = userId;
joystick->hwdata->userid = userId;
@ -1683,11 +1639,9 @@ SDL_SYS_JoystickQuit(void)
s_pKnownJoystickGUIDs = NULL;
}
if ( s_pXInputDLL )
{
FreeLibrary( s_pXInputDLL );
s_pXInputDLL = NULL;
}
if (s_bXInputEnabled) {
WIN_UnloadXInputDLL();
}
}

View file

@ -62,25 +62,6 @@ typedef struct input_t
Uint8 num;
} input_t;
/* typedef's for XInput structs we use */
typedef struct
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
DWORD dwPaddingReserved;
} XINPUT_GAMEPAD_EX;
typedef struct
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD_EX Gamepad;
} XINPUT_STATE_EX;
/* The private structure used to keep track of a joystick */
struct joystick_hwdata
{
@ -95,6 +76,7 @@ struct joystick_hwdata
Uint8 removed;
Uint8 send_remove_event;
Uint8 bXInputDevice; // 1 if this device supports using the xinput API rather than DirectInput
Uint8 bXInputHaptic; // Supports force feedback via XInput.
Uint8 userid; // XInput userid index for this joystick
Uint8 currentXInputSlot; // the current position to write to in XInputState below, used so we can compare old and new values
XINPUT_STATE_EX XInputState[2];