First shot at Windows XInput haptics.
--HG-- extra : rebase_source : 52e691a0917d173e891e67714a135373daea0ef5
This commit is contained in:
parent
203b9839d2
commit
3d572bdf89
6 changed files with 327 additions and 133 deletions
|
@ -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"
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue