mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 13:16:40 +00:00
Initial commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
extern int SDL_DINPUT_JoystickInit(void);
|
||||
extern void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext);
|
||||
extern int SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice);
|
||||
extern int SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
extern void SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick);
|
||||
extern void SDL_DINPUT_JoystickClose(SDL_Joystick * joystick);
|
||||
extern void SDL_DINPUT_JoystickQuit(void);
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
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_WINMM
|
||||
|
||||
/* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
|
||||
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include <mmsystem.h>
|
||||
#include <regstr.h>
|
||||
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_joystick.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
|
||||
#ifdef REGSTR_VAL_JOYOEMNAME
|
||||
#undef REGSTR_VAL_JOYOEMNAME
|
||||
#endif
|
||||
#define REGSTR_VAL_JOYOEMNAME "OEMName"
|
||||
|
||||
#define MAX_JOYSTICKS 16
|
||||
#define MAX_AXES 6 /* each joystick can have up to 6 axes */
|
||||
#define MAX_BUTTONS 32 /* and 32 buttons */
|
||||
#define JOY_BUTTON_FLAG(n) (1<<n)
|
||||
|
||||
|
||||
/* array to hold joystick ID values */
|
||||
static UINT SYS_JoystickID[MAX_JOYSTICKS];
|
||||
static JOYCAPSA SYS_Joystick[MAX_JOYSTICKS];
|
||||
static char *SYS_JoystickName[MAX_JOYSTICKS];
|
||||
|
||||
/* The private structure used to keep track of a joystick */
|
||||
struct joystick_hwdata
|
||||
{
|
||||
/* joystick ID */
|
||||
UINT id;
|
||||
|
||||
/* values used to translate device-specific coordinates into
|
||||
SDL-standard ranges */
|
||||
struct _transaxis
|
||||
{
|
||||
int offset;
|
||||
float scale;
|
||||
} transaxis[6];
|
||||
};
|
||||
|
||||
/* Convert a Windows Multimedia API return code to a text message */
|
||||
static void SetMMerror(char *function, int code);
|
||||
|
||||
|
||||
static char *
|
||||
GetJoystickName(int index, const char *szRegKey)
|
||||
{
|
||||
/* added 7/24/2004 by Eckhard Stolberg */
|
||||
/*
|
||||
see if there is a joystick for the current
|
||||
index (1-16) listed in the registry
|
||||
*/
|
||||
char *name = NULL;
|
||||
HKEY hTopKey;
|
||||
HKEY hKey;
|
||||
DWORD regsize;
|
||||
LONG regresult;
|
||||
char regkey[256];
|
||||
char regvalue[256];
|
||||
char regname[256];
|
||||
|
||||
SDL_snprintf(regkey, SDL_arraysize(regkey),
|
||||
#ifdef UNICODE
|
||||
"%S\\%s\\%S",
|
||||
#else
|
||||
"%s\\%s\\%s",
|
||||
#endif
|
||||
REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
|
||||
hTopKey = HKEY_LOCAL_MACHINE;
|
||||
regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
|
||||
if (regresult != ERROR_SUCCESS) {
|
||||
hTopKey = HKEY_CURRENT_USER;
|
||||
regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
|
||||
}
|
||||
if (regresult != ERROR_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find the registry key name for the joystick's properties */
|
||||
regsize = sizeof(regname);
|
||||
SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index + 1,
|
||||
REGSTR_VAL_JOYOEMNAME);
|
||||
regresult =
|
||||
RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE) regname, ®size);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if (regresult != ERROR_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open that registry key */
|
||||
SDL_snprintf(regkey, SDL_arraysize(regkey),
|
||||
#ifdef UNICODE
|
||||
"%S\\%s",
|
||||
#else
|
||||
"%s\\%s",
|
||||
#endif
|
||||
REGSTR_PATH_JOYOEM, regname);
|
||||
regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
|
||||
if (regresult != ERROR_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find the size for the OEM name text */
|
||||
regsize = sizeof(regvalue);
|
||||
regresult =
|
||||
RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, ®size);
|
||||
if (regresult == ERROR_SUCCESS) {
|
||||
/* allocate enough memory for the OEM name text ... */
|
||||
name = (char *) SDL_malloc(regsize);
|
||||
if (name) {
|
||||
/* ... and read it from the registry */
|
||||
regresult = RegQueryValueExA(hKey,
|
||||
REGSTR_VAL_JOYOEMNAME, 0, 0,
|
||||
(LPBYTE) name, ®size);
|
||||
}
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return (name);
|
||||
}
|
||||
|
||||
static int SDL_SYS_numjoysticks = 0;
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
* It should return 0, or -1 on an unrecoverable fatal error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
{
|
||||
int i;
|
||||
int maxdevs;
|
||||
JOYINFOEX joyinfo;
|
||||
JOYCAPSA joycaps;
|
||||
MMRESULT result;
|
||||
|
||||
/* Reset the joystick ID & name mapping tables */
|
||||
for (i = 0; i < MAX_JOYSTICKS; ++i) {
|
||||
SYS_JoystickID[i] = 0;
|
||||
SYS_JoystickName[i] = NULL;
|
||||
}
|
||||
|
||||
/* Loop over all potential joystick devices */
|
||||
SDL_SYS_numjoysticks = 0;
|
||||
maxdevs = joyGetNumDevs();
|
||||
for (i = JOYSTICKID1; i < maxdevs && SDL_SYS_numjoysticks < MAX_JOYSTICKS; ++i) {
|
||||
|
||||
joyinfo.dwSize = sizeof(joyinfo);
|
||||
joyinfo.dwFlags = JOY_RETURNALL;
|
||||
result = joyGetPosEx(i, &joyinfo);
|
||||
if (result == JOYERR_NOERROR) {
|
||||
result = joyGetDevCapsA(i, &joycaps, sizeof(joycaps));
|
||||
if (result == JOYERR_NOERROR) {
|
||||
SYS_JoystickID[SDL_SYS_numjoysticks] = i;
|
||||
SYS_Joystick[SDL_SYS_numjoysticks] = joycaps;
|
||||
SYS_JoystickName[SDL_SYS_numjoysticks] =
|
||||
GetJoystickName(i, joycaps.szRegKey);
|
||||
SDL_SYS_numjoysticks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (SDL_SYS_numjoysticks);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
{
|
||||
return SDL_SYS_numjoysticks;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
{
|
||||
if (SYS_JoystickName[device_index] != NULL) {
|
||||
return (SYS_JoystickName[device_index]);
|
||||
} else {
|
||||
return (SYS_Joystick[device_index].szPname);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to perform the mapping from device index to the instance id for this index */
|
||||
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
{
|
||||
return device_index;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int index, i;
|
||||
int caps_flags[MAX_AXES - 2] =
|
||||
{ JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
|
||||
int axis_min[MAX_AXES], axis_max[MAX_AXES];
|
||||
|
||||
|
||||
/* shortcut */
|
||||
index = device_index;
|
||||
axis_min[0] = SYS_Joystick[index].wXmin;
|
||||
axis_max[0] = SYS_Joystick[index].wXmax;
|
||||
axis_min[1] = SYS_Joystick[index].wYmin;
|
||||
axis_max[1] = SYS_Joystick[index].wYmax;
|
||||
axis_min[2] = SYS_Joystick[index].wZmin;
|
||||
axis_max[2] = SYS_Joystick[index].wZmax;
|
||||
axis_min[3] = SYS_Joystick[index].wRmin;
|
||||
axis_max[3] = SYS_Joystick[index].wRmax;
|
||||
axis_min[4] = SYS_Joystick[index].wUmin;
|
||||
axis_max[4] = SYS_Joystick[index].wUmax;
|
||||
axis_min[5] = SYS_Joystick[index].wVmin;
|
||||
axis_max[5] = SYS_Joystick[index].wVmax;
|
||||
|
||||
/* allocate memory for system specific hardware data */
|
||||
joystick->instance_id = device_index;
|
||||
joystick->hwdata =
|
||||
(struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
|
||||
if (joystick->hwdata == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
|
||||
|
||||
/* set hardware data */
|
||||
joystick->hwdata->id = SYS_JoystickID[index];
|
||||
for (i = 0; i < MAX_AXES; ++i) {
|
||||
if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
|
||||
joystick->hwdata->transaxis[i].offset = SDL_JOYSTICK_AXIS_MIN - axis_min[i];
|
||||
joystick->hwdata->transaxis[i].scale =
|
||||
(float) (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) / (axis_max[i] - axis_min[i]);
|
||||
} else {
|
||||
joystick->hwdata->transaxis[i].offset = 0;
|
||||
joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
|
||||
}
|
||||
}
|
||||
|
||||
/* fill nbuttons, naxes, and nhats fields */
|
||||
joystick->nbuttons = SYS_Joystick[index].wNumButtons;
|
||||
joystick->naxes = SYS_Joystick[index].wNumAxes;
|
||||
if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
|
||||
joystick->nhats = 1;
|
||||
} else {
|
||||
joystick->nhats = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static Uint8
|
||||
TranslatePOV(DWORD value)
|
||||
{
|
||||
Uint8 pos;
|
||||
|
||||
pos = SDL_HAT_CENTERED;
|
||||
if (value != JOY_POVCENTERED) {
|
||||
if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
|
||||
pos |= SDL_HAT_UP;
|
||||
}
|
||||
if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
|
||||
pos |= SDL_HAT_RIGHT;
|
||||
}
|
||||
if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
|
||||
pos |= SDL_HAT_DOWN;
|
||||
}
|
||||
if (value > JOY_POVBACKWARD) {
|
||||
pos |= SDL_HAT_LEFT;
|
||||
}
|
||||
}
|
||||
return (pos);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
MMRESULT result;
|
||||
int i;
|
||||
DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
|
||||
JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
|
||||
};
|
||||
DWORD pos[MAX_AXES];
|
||||
struct _transaxis *transaxis;
|
||||
int value;
|
||||
JOYINFOEX joyinfo;
|
||||
|
||||
joyinfo.dwSize = sizeof(joyinfo);
|
||||
joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
|
||||
if (!joystick->hats) {
|
||||
joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
|
||||
}
|
||||
result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
|
||||
if (result != JOYERR_NOERROR) {
|
||||
SetMMerror("joyGetPosEx", result);
|
||||
return;
|
||||
}
|
||||
|
||||
/* joystick motion events */
|
||||
pos[0] = joyinfo.dwXpos;
|
||||
pos[1] = joyinfo.dwYpos;
|
||||
pos[2] = joyinfo.dwZpos;
|
||||
pos[3] = joyinfo.dwRpos;
|
||||
pos[4] = joyinfo.dwUpos;
|
||||
pos[5] = joyinfo.dwVpos;
|
||||
|
||||
transaxis = joystick->hwdata->transaxis;
|
||||
for (i = 0; i < joystick->naxes; i++) {
|
||||
if (joyinfo.dwFlags & flags[i]) {
|
||||
value = (int) (((float) pos[i] + transaxis[i].offset) * transaxis[i].scale);
|
||||
SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
|
||||
}
|
||||
}
|
||||
|
||||
/* joystick button events */
|
||||
if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
|
||||
for (i = 0; i < joystick->nbuttons; ++i) {
|
||||
if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
|
||||
SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_PRESSED);
|
||||
} else {
|
||||
SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_RELEASED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* joystick hat events */
|
||||
if (joyinfo.dwFlags & JOY_RETURNPOV) {
|
||||
SDL_PrivateJoystickHat(joystick, 0, TranslatePOV(joyinfo.dwPOV));
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_free(joystick->hwdata);
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_JOYSTICKS; i++) {
|
||||
SDL_free(SYS_JoystickName[i]);
|
||||
SYS_JoystickName[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
/* the GUID is just the first 16 chars of the name for now */
|
||||
const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
|
||||
SDL_zero( guid );
|
||||
SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
|
||||
return guid;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
/* the GUID is just the first 16 chars of the name for now */
|
||||
const char *name = joystick->name;
|
||||
SDL_zero( guid );
|
||||
SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
|
||||
return guid;
|
||||
}
|
||||
|
||||
|
||||
/* implementation functions */
|
||||
void
|
||||
SetMMerror(char *function, int code)
|
||||
{
|
||||
static char *error;
|
||||
static char errbuf[1024];
|
||||
|
||||
errbuf[0] = 0;
|
||||
switch (code) {
|
||||
case MMSYSERR_NODRIVER:
|
||||
error = "Joystick driver not present";
|
||||
break;
|
||||
|
||||
case MMSYSERR_INVALPARAM:
|
||||
case JOYERR_PARMS:
|
||||
error = "Invalid parameter(s)";
|
||||
break;
|
||||
|
||||
case MMSYSERR_BADDEVICEID:
|
||||
error = "Bad device ID";
|
||||
break;
|
||||
|
||||
case JOYERR_UNPLUGGED:
|
||||
error = "Joystick not attached";
|
||||
break;
|
||||
|
||||
case JOYERR_NOCANDO:
|
||||
error = "Can't capture joystick input";
|
||||
break;
|
||||
|
||||
default:
|
||||
SDL_snprintf(errbuf, SDL_arraysize(errbuf),
|
||||
"%s: Unknown Multimedia system error: 0x%x",
|
||||
function, code);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!errbuf[0]) {
|
||||
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
|
||||
error);
|
||||
}
|
||||
SDL_SetError("%s", errbuf);
|
||||
}
|
||||
|
||||
#endif /* SDL_JOYSTICK_WINMM */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
#if SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT
|
||||
|
||||
/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
|
||||
* A. Formiga's WINMM driver.
|
||||
*
|
||||
* Hats and sliders are completely untested; the app I'm writing this for mostly
|
||||
* doesn't use them and I don't own any joysticks with them.
|
||||
*
|
||||
* We don't bother to use event notification here. It doesn't seem to work
|
||||
* with polled devices, and it's fine to call IDirectInputDevice8_GetDeviceData and
|
||||
* let it return 0 events. */
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_mutex.h"
|
||||
#include "SDL_joystick.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../../thread/SDL_systhread.h"
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#if !defined(__WINRT__)
|
||||
#include <dbt.h>
|
||||
#endif
|
||||
|
||||
#define INITGUID /* Only set here, if set twice will cause mingw32 to break. */
|
||||
#include "SDL_windowsjoystick_c.h"
|
||||
#include "SDL_dinputjoystick_c.h"
|
||||
#include "SDL_xinputjoystick_c.h"
|
||||
|
||||
#include "../../haptic/windows/SDL_dinputhaptic_c.h" /* For haptic hot plugging */
|
||||
#include "../../haptic/windows/SDL_xinputhaptic_c.h" /* For haptic hot plugging */
|
||||
|
||||
|
||||
#ifndef DEVICE_NOTIFY_WINDOW_HANDLE
|
||||
#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000
|
||||
#endif
|
||||
|
||||
/* local variables */
|
||||
static SDL_bool s_bDeviceAdded = SDL_FALSE;
|
||||
static SDL_bool s_bDeviceRemoved = SDL_FALSE;
|
||||
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;
|
||||
|
||||
JoyStick_DeviceData *SYS_Joystick; /* array to hold joystick ID values */
|
||||
|
||||
static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE;
|
||||
|
||||
#ifdef __WINRT__
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int unused;
|
||||
} SDL_DeviceNotificationData;
|
||||
|
||||
static void
|
||||
SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
#else /* !__WINRT__ */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HRESULT coinitialized;
|
||||
WNDCLASSEX wincl;
|
||||
HWND messageWindow;
|
||||
HDEVNOTIFY hNotify;
|
||||
} SDL_DeviceNotificationData;
|
||||
|
||||
#define IDT_SDL_DEVICE_CHANGE_TIMER_1 1200
|
||||
#define IDT_SDL_DEVICE_CHANGE_TIMER_2 1201
|
||||
|
||||
/* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal */
|
||||
static LRESULT CALLBACK
|
||||
SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message) {
|
||||
case WM_DEVICECHANGE:
|
||||
switch (wParam) {
|
||||
case DBT_DEVICEARRIVAL:
|
||||
case DBT_DEVICEREMOVECOMPLETE:
|
||||
if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
|
||||
/* notify 300ms and 2 seconds later to ensure all APIs have updated status */
|
||||
SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_1, 300, NULL);
|
||||
SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_2, 2000, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
case WM_TIMER:
|
||||
KillTimer(hwnd, wParam);
|
||||
s_bWindowsDeviceChanged = SDL_TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc (hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
|
||||
{
|
||||
if (data->hNotify)
|
||||
UnregisterDeviceNotification(data->hNotify);
|
||||
|
||||
if (data->messageWindow)
|
||||
DestroyWindow(data->messageWindow);
|
||||
|
||||
UnregisterClass(data->wincl.lpszClassName, data->wincl.hInstance);
|
||||
|
||||
if (data->coinitialized == S_OK) {
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
|
||||
{
|
||||
DEV_BROADCAST_DEVICEINTERFACE dbh;
|
||||
GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
|
||||
|
||||
SDL_zerop(data);
|
||||
|
||||
data->coinitialized = WIN_CoInitialize();
|
||||
|
||||
data->wincl.hInstance = GetModuleHandle(NULL);
|
||||
data->wincl.lpszClassName = L"Message";
|
||||
data->wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc; /* This function is called by windows */
|
||||
data->wincl.cbSize = sizeof (WNDCLASSEX);
|
||||
|
||||
if (!RegisterClassEx(&data->wincl)) {
|
||||
WIN_SetError("Failed to create register class for joystick autodetect");
|
||||
SDL_CleanupDeviceNotification(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->messageWindow = (HWND)CreateWindowEx(0, L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
||||
if (!data->messageWindow) {
|
||||
WIN_SetError("Failed to create message window for joystick autodetect");
|
||||
SDL_CleanupDeviceNotification(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_zero(dbh);
|
||||
dbh.dbcc_size = sizeof(dbh);
|
||||
dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||
dbh.dbcc_classguid = GUID_DEVINTERFACE_HID;
|
||||
|
||||
data->hNotify = RegisterDeviceNotification(data->messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
if (!data->hNotify) {
|
||||
WIN_SetError("Failed to create notify device for joystick autodetect");
|
||||
SDL_CleanupDeviceNotification(data);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex)
|
||||
{
|
||||
MSG msg;
|
||||
int lastret = 1;
|
||||
|
||||
if (!data->messageWindow) {
|
||||
return SDL_FALSE; /* device notifications require a window */
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(mutex);
|
||||
while (lastret > 0 && s_bWindowsDeviceChanged == SDL_FALSE) {
|
||||
lastret = GetMessage(&msg, NULL, 0, 0); /* WM_QUIT causes return value of 0 */
|
||||
if (lastret > 0) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
SDL_LockMutex(mutex);
|
||||
return (lastret != -1) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
#endif /* __WINRT__ */
|
||||
|
||||
/* Function/thread to scan the system for joysticks. */
|
||||
static int
|
||||
SDL_JoystickThread(void *_data)
|
||||
{
|
||||
SDL_DeviceNotificationData notification_data;
|
||||
|
||||
#if SDL_JOYSTICK_XINPUT
|
||||
SDL_bool bOpenedXInputDevices[XUSER_MAX_COUNT];
|
||||
SDL_zero(bOpenedXInputDevices);
|
||||
#endif
|
||||
|
||||
if (SDL_CreateDeviceNotification(¬ification_data) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_LockMutex(s_mutexJoyStickEnum);
|
||||
while (s_bJoystickThreadQuit == SDL_FALSE) {
|
||||
SDL_bool bXInputChanged = SDL_FALSE;
|
||||
|
||||
if (SDL_WaitForDeviceNotification(¬ification_data, s_mutexJoyStickEnum) == SDL_FALSE) {
|
||||
#if SDL_JOYSTICK_XINPUT
|
||||
/* WM_DEVICECHANGE not working, poll for new XINPUT controllers */
|
||||
SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000);
|
||||
if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
|
||||
/* scan for any change in XInput devices */
|
||||
Uint8 userId;
|
||||
for (userId = 0; userId < XUSER_MAX_COUNT; userId++) {
|
||||
XINPUT_CAPABILITIES capabilities;
|
||||
const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities);
|
||||
const SDL_bool available = (result == ERROR_SUCCESS);
|
||||
if (bOpenedXInputDevices[userId] != available) {
|
||||
bXInputChanged = SDL_TRUE;
|
||||
bOpenedXInputDevices[userId] = available;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive */
|
||||
break;
|
||||
#endif /* SDL_JOYSTICK_XINPUT */
|
||||
}
|
||||
|
||||
if (s_bWindowsDeviceChanged || bXInputChanged) {
|
||||
s_bDeviceRemoved = SDL_TRUE;
|
||||
s_bDeviceAdded = SDL_TRUE;
|
||||
s_bWindowsDeviceChanged = SDL_FALSE;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(s_mutexJoyStickEnum);
|
||||
|
||||
SDL_CleanupDeviceNotification(¬ification_data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device)
|
||||
{
|
||||
device->send_add_event = SDL_TRUE;
|
||||
device->nInstanceID = SDL_GetNextJoystickInstanceID();
|
||||
device->pNext = SYS_Joystick;
|
||||
SYS_Joystick = device;
|
||||
|
||||
s_bDeviceAdded = SDL_TRUE;
|
||||
}
|
||||
|
||||
static void WINDOWS_JoystickDetect(void);
|
||||
static void WINDOWS_JoystickQuit(void);
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
* It should return 0, or -1 on an unrecoverable fatal error.
|
||||
*/
|
||||
static int
|
||||
WINDOWS_JoystickInit(void)
|
||||
{
|
||||
if (SDL_DINPUT_JoystickInit() < 0) {
|
||||
WINDOWS_JoystickQuit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SDL_XINPUT_JoystickInit() < 0) {
|
||||
WINDOWS_JoystickQuit();
|
||||
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 */
|
||||
|
||||
WINDOWS_JoystickDetect();
|
||||
|
||||
if (!s_threadJoystick) {
|
||||
/* spin up the thread to detect hotplug of devices */
|
||||
s_bJoystickThreadQuit = SDL_FALSE;
|
||||
s_threadJoystick = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return the number of joysticks that are connected right now */
|
||||
static int
|
||||
WINDOWS_JoystickGetCount(void)
|
||||
{
|
||||
int nJoysticks = 0;
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
while (device) {
|
||||
nJoysticks++;
|
||||
device = device->pNext;
|
||||
}
|
||||
|
||||
return nJoysticks;
|
||||
}
|
||||
|
||||
/* detect any new joysticks being inserted into the system */
|
||||
static void
|
||||
WINDOWS_JoystickDetect(void)
|
||||
{
|
||||
JoyStick_DeviceData *pCurList = NULL;
|
||||
|
||||
/* only enum the devices if the joystick thread told us something changed */
|
||||
if (!s_bDeviceAdded && !s_bDeviceRemoved) {
|
||||
return; /* thread hasn't signaled, nothing to do right now. */
|
||||
}
|
||||
|
||||
SDL_LockMutex(s_mutexJoyStickEnum);
|
||||
|
||||
s_bDeviceAdded = SDL_FALSE;
|
||||
s_bDeviceRemoved = SDL_FALSE;
|
||||
|
||||
pCurList = SYS_Joystick;
|
||||
SYS_Joystick = NULL;
|
||||
|
||||
/* Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. */
|
||||
SDL_DINPUT_JoystickDetect(&pCurList);
|
||||
|
||||
/* Look for XInput devices. Do this last, so they're first in the final list. */
|
||||
SDL_XINPUT_JoystickDetect(&pCurList);
|
||||
|
||||
SDL_UnlockMutex(s_mutexJoyStickEnum);
|
||||
|
||||
while (pCurList) {
|
||||
JoyStick_DeviceData *pListNext = NULL;
|
||||
|
||||
if (pCurList->bXInputDevice) {
|
||||
SDL_XINPUT_MaybeRemoveDevice(pCurList->XInputUserId);
|
||||
} else {
|
||||
SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice);
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickRemoved(pCurList->nInstanceID);
|
||||
|
||||
pListNext = pCurList->pNext;
|
||||
SDL_free(pCurList->joystickname);
|
||||
SDL_free(pCurList);
|
||||
pCurList = pListNext;
|
||||
}
|
||||
|
||||
if (s_bDeviceAdded) {
|
||||
JoyStick_DeviceData *pNewJoystick;
|
||||
int device_index = 0;
|
||||
s_bDeviceAdded = SDL_FALSE;
|
||||
pNewJoystick = SYS_Joystick;
|
||||
while (pNewJoystick) {
|
||||
if (pNewJoystick->send_add_event) {
|
||||
if (pNewJoystick->bXInputDevice) {
|
||||
SDL_XINPUT_MaybeAddDevice(pNewJoystick->XInputUserId);
|
||||
} else {
|
||||
SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice);
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAdded(pNewJoystick->nInstanceID);
|
||||
|
||||
pNewJoystick->send_add_event = SDL_FALSE;
|
||||
}
|
||||
device_index++;
|
||||
pNewJoystick = pNewJoystick->pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
static const char *
|
||||
WINDOWS_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
|
||||
for (; device_index > 0; device_index--)
|
||||
device = device->pNext;
|
||||
|
||||
return device->joystickname;
|
||||
}
|
||||
|
||||
static int
|
||||
WINDOWS_JoystickGetDevicePlayerIndex(int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
int index;
|
||||
|
||||
for (index = device_index; index > 0; index--)
|
||||
device = device->pNext;
|
||||
|
||||
return device->bXInputDevice ? (int)device->XInputUserId : -1;
|
||||
}
|
||||
|
||||
/* return the stable device guid for this device index */
|
||||
static SDL_JoystickGUID
|
||||
WINDOWS_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
int index;
|
||||
|
||||
for (index = device_index; index > 0; index--)
|
||||
device = device->pNext;
|
||||
|
||||
return device->guid;
|
||||
}
|
||||
|
||||
/* Function to perform the mapping between current device instance and this joysticks instance id */
|
||||
static SDL_JoystickID
|
||||
WINDOWS_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
int index;
|
||||
|
||||
for (index = device_index; index > 0; index--)
|
||||
device = device->pNext;
|
||||
|
||||
return device->nInstanceID;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
static int
|
||||
WINDOWS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *joystickdevice = SYS_Joystick;
|
||||
|
||||
for (; device_index > 0; device_index--)
|
||||
joystickdevice = joystickdevice->pNext;
|
||||
|
||||
/* allocate memory for system specific hardware data */
|
||||
joystick->instance_id = joystickdevice->nInstanceID;
|
||||
joystick->hwdata =
|
||||
(struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
|
||||
if (joystick->hwdata == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
SDL_zerop(joystick->hwdata);
|
||||
joystick->hwdata->guid = joystickdevice->guid;
|
||||
|
||||
if (joystickdevice->bXInputDevice) {
|
||||
return SDL_XINPUT_JoystickOpen(joystick, joystickdevice);
|
||||
} else {
|
||||
return SDL_DINPUT_JoystickOpen(joystick, joystickdevice);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
} else {
|
||||
return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WINDOWS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!joystick->hwdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
SDL_XINPUT_JoystickUpdate(joystick);
|
||||
} else {
|
||||
SDL_DINPUT_JoystickUpdate(joystick);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
static void
|
||||
WINDOWS_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
SDL_XINPUT_JoystickClose(joystick);
|
||||
} else {
|
||||
SDL_DINPUT_JoystickClose(joystick);
|
||||
}
|
||||
|
||||
SDL_free(joystick->hwdata);
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
static void
|
||||
WINDOWS_JoystickQuit(void)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
|
||||
while (device) {
|
||||
JoyStick_DeviceData *device_next = device->pNext;
|
||||
SDL_free(device->joystickname);
|
||||
SDL_free(device);
|
||||
device = device_next;
|
||||
}
|
||||
SYS_Joystick = NULL;
|
||||
|
||||
if (s_threadJoystick) {
|
||||
SDL_LockMutex(s_mutexJoyStickEnum);
|
||||
s_bJoystickThreadQuit = SDL_TRUE;
|
||||
SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */
|
||||
SDL_UnlockMutex(s_mutexJoyStickEnum);
|
||||
#ifndef __WINRT__
|
||||
PostThreadMessage(SDL_GetThreadID(s_threadJoystick), WM_QUIT, 0, 0);
|
||||
#endif
|
||||
SDL_WaitThread(s_threadJoystick, NULL); /* wait for it to bugger off */
|
||||
|
||||
SDL_DestroyMutex(s_mutexJoyStickEnum);
|
||||
SDL_DestroyCond(s_condJoystickThread);
|
||||
s_condJoystickThread= NULL;
|
||||
s_mutexJoyStickEnum = NULL;
|
||||
s_threadJoystick = NULL;
|
||||
}
|
||||
|
||||
SDL_DINPUT_JoystickQuit();
|
||||
SDL_XINPUT_JoystickQuit();
|
||||
|
||||
s_bDeviceAdded = SDL_FALSE;
|
||||
s_bDeviceRemoved = SDL_FALSE;
|
||||
}
|
||||
|
||||
SDL_JoystickDriver SDL_WINDOWS_JoystickDriver =
|
||||
{
|
||||
WINDOWS_JoystickInit,
|
||||
WINDOWS_JoystickGetCount,
|
||||
WINDOWS_JoystickDetect,
|
||||
WINDOWS_JoystickGetDeviceName,
|
||||
WINDOWS_JoystickGetDevicePlayerIndex,
|
||||
WINDOWS_JoystickGetDeviceGUID,
|
||||
WINDOWS_JoystickGetDeviceInstanceID,
|
||||
WINDOWS_JoystickOpen,
|
||||
WINDOWS_JoystickRumble,
|
||||
WINDOWS_JoystickUpdate,
|
||||
WINDOWS_JoystickClose,
|
||||
WINDOWS_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
#include "SDL_events.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include "../../core/windows/SDL_directx.h"
|
||||
|
||||
#define MAX_INPUTS 256 /* each joystick can have up to 256 inputs */
|
||||
|
||||
typedef struct JoyStick_DeviceData
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
char *joystickname;
|
||||
Uint8 send_add_event;
|
||||
SDL_JoystickID nInstanceID;
|
||||
SDL_bool bXInputDevice;
|
||||
BYTE SubType;
|
||||
Uint8 XInputUserId;
|
||||
DIDEVICEINSTANCE dxdevice;
|
||||
WCHAR hidPath[MAX_PATH];
|
||||
struct JoyStick_DeviceData *pNext;
|
||||
} JoyStick_DeviceData;
|
||||
|
||||
extern JoyStick_DeviceData *SYS_Joystick; /* array to hold joystick ID values */
|
||||
|
||||
typedef enum Type
|
||||
{
|
||||
BUTTON,
|
||||
AXIS,
|
||||
HAT
|
||||
} Type;
|
||||
|
||||
typedef struct input_t
|
||||
{
|
||||
/* DirectInput offset for this input type: */
|
||||
DWORD ofs;
|
||||
|
||||
/* Button, axis or hat: */
|
||||
Type type;
|
||||
|
||||
/* SDL input offset: */
|
||||
Uint8 num;
|
||||
} input_t;
|
||||
|
||||
/* The private structure used to keep track of a joystick */
|
||||
struct joystick_hwdata
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
Uint32 rumble_expiration;
|
||||
|
||||
#if SDL_JOYSTICK_DINPUT
|
||||
LPDIRECTINPUTDEVICE8 InputDevice;
|
||||
DIDEVCAPS Capabilities;
|
||||
SDL_bool buffered;
|
||||
input_t Inputs[MAX_INPUTS];
|
||||
int NumInputs;
|
||||
int NumSliders;
|
||||
SDL_bool ff_initialized;
|
||||
DIEFFECT *ffeffect;
|
||||
LPDIRECTINPUTEFFECT ffeffect_ref;
|
||||
#endif
|
||||
|
||||
SDL_bool bXInputDevice; /* SDL_TRUE if this device supports using the xinput API rather than DirectInput */
|
||||
SDL_bool bXInputHaptic; /* Supports force feedback via XInput. */
|
||||
Uint8 userid; /* XInput userid index for this joystick */
|
||||
DWORD dwPacketNumber;
|
||||
};
|
||||
|
||||
#if SDL_JOYSTICK_DINPUT
|
||||
extern const DIDATAFORMAT SDL_c_dfDIJoystick2;
|
||||
#endif
|
||||
|
||||
extern void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device);
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
#include "../SDL_sysjoystick.h"
|
||||
|
||||
#if SDL_JOYSTICK_XINPUT
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_windowsjoystick_c.h"
|
||||
#include "SDL_xinputjoystick_c.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
|
||||
/*
|
||||
* Internal stuff.
|
||||
*/
|
||||
static SDL_bool s_bXInputEnabled = SDL_TRUE;
|
||||
static char *s_arrXInputDevicePath[XUSER_MAX_COUNT];
|
||||
|
||||
|
||||
static SDL_bool
|
||||
SDL_XInputUseOldJoystickMapping()
|
||||
{
|
||||
#ifdef __WINRT__
|
||||
/* TODO: remove this __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
|
||||
/* FIXME: Why are Win8/10 different here? -flibit */
|
||||
return (NTDDI_VERSION < NTDDI_WIN10);
|
||||
#else
|
||||
static int s_XInputUseOldJoystickMapping = -1;
|
||||
if (s_XInputUseOldJoystickMapping < 0) {
|
||||
s_XInputUseOldJoystickMapping = SDL_GetHintBoolean(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, SDL_FALSE);
|
||||
}
|
||||
return (s_XInputUseOldJoystickMapping > 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
SDL_bool SDL_XINPUT_Enabled(void)
|
||||
{
|
||||
return s_bXInputEnabled;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickInit(void)
|
||||
{
|
||||
s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
|
||||
|
||||
if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) {
|
||||
s_bXInputEnabled = SDL_FALSE; /* oh well. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
GetXInputName(const Uint8 userid, BYTE SubType)
|
||||
{
|
||||
char name[32];
|
||||
|
||||
if (SDL_XInputUseOldJoystickMapping()) {
|
||||
SDL_snprintf(name, sizeof(name), "X360 Controller #%u", 1 + userid);
|
||||
} else {
|
||||
switch (SubType) {
|
||||
case XINPUT_DEVSUBTYPE_GAMEPAD:
|
||||
SDL_snprintf(name, sizeof(name), "XInput Controller #%u", 1 + userid);
|
||||
break;
|
||||
case XINPUT_DEVSUBTYPE_WHEEL:
|
||||
SDL_snprintf(name, sizeof(name), "XInput Wheel #%u", 1 + userid);
|
||||
break;
|
||||
case XINPUT_DEVSUBTYPE_ARCADE_STICK:
|
||||
SDL_snprintf(name, sizeof(name), "XInput ArcadeStick #%u", 1 + userid);
|
||||
break;
|
||||
case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
|
||||
SDL_snprintf(name, sizeof(name), "XInput FlightStick #%u", 1 + userid);
|
||||
break;
|
||||
case XINPUT_DEVSUBTYPE_DANCE_PAD:
|
||||
SDL_snprintf(name, sizeof(name), "XInput DancePad #%u", 1 + userid);
|
||||
break;
|
||||
case XINPUT_DEVSUBTYPE_GUITAR:
|
||||
case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
|
||||
case XINPUT_DEVSUBTYPE_GUITAR_BASS:
|
||||
SDL_snprintf(name, sizeof(name), "XInput Guitar #%u", 1 + userid);
|
||||
break;
|
||||
case XINPUT_DEVSUBTYPE_DRUM_KIT:
|
||||
SDL_snprintf(name, sizeof(name), "XInput DrumKit #%u", 1 + userid);
|
||||
break;
|
||||
case XINPUT_DEVSUBTYPE_ARCADE_PAD:
|
||||
SDL_snprintf(name, sizeof(name), "XInput ArcadePad #%u", 1 + userid);
|
||||
break;
|
||||
default:
|
||||
SDL_snprintf(name, sizeof(name), "XInput Device #%u", 1 + userid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SDL_strdup(name);
|
||||
}
|
||||
|
||||
/* We can't really tell what device is being used for XInput, but we can guess
|
||||
and we'll be correct for the case where only one device is connected.
|
||||
*/
|
||||
static void
|
||||
GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
|
||||
{
|
||||
#ifndef __WINRT__ /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
|
||||
|
||||
PRAWINPUTDEVICELIST devices = NULL;
|
||||
UINT i, j, device_count = 0;
|
||||
|
||||
if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) {
|
||||
return; /* oh well. */
|
||||
}
|
||||
|
||||
devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count);
|
||||
if (devices == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
|
||||
SDL_free(devices);
|
||||
return; /* oh well. */
|
||||
}
|
||||
|
||||
for (i = 0; i < device_count; i++) {
|
||||
RID_DEVICE_INFO rdi;
|
||||
char devName[128];
|
||||
UINT rdiSize = sizeof(rdi);
|
||||
UINT nameSize = SDL_arraysize(devName);
|
||||
|
||||
rdi.cbSize = sizeof(rdi);
|
||||
if ((devices[i].dwType == RIM_TYPEHID) &&
|
||||
(GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
|
||||
(GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
|
||||
(SDL_strstr(devName, "IG_") != NULL)) {
|
||||
SDL_bool found = SDL_FALSE;
|
||||
for (j = 0; j < SDL_arraysize(s_arrXInputDevicePath); ++j) {
|
||||
if (j == userid) {
|
||||
continue;
|
||||
}
|
||||
if (!s_arrXInputDevicePath[j]) {
|
||||
continue;
|
||||
}
|
||||
if (SDL_strcmp(devName, s_arrXInputDevicePath[j]) == 0) {
|
||||
found = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
/* We already have this device in our XInput device list */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We don't actually know if this is the right device for this
|
||||
* userid, but we'll record it so we'll at least be consistent
|
||||
* when the raw device list changes.
|
||||
*/
|
||||
*pVID = (Uint16)rdi.hid.dwVendorId;
|
||||
*pPID = (Uint16)rdi.hid.dwProductId;
|
||||
*pVersion = (Uint16)rdi.hid.dwVersionNumber;
|
||||
if (s_arrXInputDevicePath[userid]) {
|
||||
SDL_free(s_arrXInputDevicePath[userid]);
|
||||
}
|
||||
s_arrXInputDevicePath[userid] = SDL_strdup(devName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_free(devices);
|
||||
#endif /* ifndef __WINRT__ */
|
||||
}
|
||||
|
||||
static void
|
||||
AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext)
|
||||
{
|
||||
Uint16 vendor = 0;
|
||||
Uint16 product = 0;
|
||||
Uint16 version = 0;
|
||||
JoyStick_DeviceData *pPrevJoystick = NULL;
|
||||
JoyStick_DeviceData *pNewJoystick = *pContext;
|
||||
|
||||
if (SDL_XInputUseOldJoystickMapping() && SubType != XINPUT_DEVSUBTYPE_GAMEPAD)
|
||||
return;
|
||||
|
||||
if (SubType == XINPUT_DEVSUBTYPE_UNKNOWN)
|
||||
return;
|
||||
|
||||
while (pNewJoystick) {
|
||||
if (pNewJoystick->bXInputDevice && (pNewJoystick->XInputUserId == userid) && (pNewJoystick->SubType == SubType)) {
|
||||
/* if we are replacing the front of the list then update it */
|
||||
if (pNewJoystick == *pContext) {
|
||||
*pContext = pNewJoystick->pNext;
|
||||
} else if (pPrevJoystick) {
|
||||
pPrevJoystick->pNext = pNewJoystick->pNext;
|
||||
}
|
||||
|
||||
pNewJoystick->pNext = SYS_Joystick;
|
||||
SYS_Joystick = pNewJoystick;
|
||||
return; /* already in the list. */
|
||||
}
|
||||
|
||||
pPrevJoystick = pNewJoystick;
|
||||
pNewJoystick = pNewJoystick->pNext;
|
||||
}
|
||||
|
||||
pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData));
|
||||
if (!pNewJoystick) {
|
||||
return; /* better luck next time? */
|
||||
}
|
||||
SDL_zerop(pNewJoystick);
|
||||
|
||||
pNewJoystick->joystickname = GetXInputName(userid, SubType);
|
||||
if (!pNewJoystick->joystickname) {
|
||||
SDL_free(pNewJoystick);
|
||||
return; /* better luck next time? */
|
||||
}
|
||||
|
||||
pNewJoystick->bXInputDevice = SDL_TRUE;
|
||||
if (SDL_XInputUseOldJoystickMapping()) {
|
||||
SDL_zero(pNewJoystick->guid);
|
||||
} else {
|
||||
Uint16 *guid16 = (Uint16 *)pNewJoystick->guid.data;
|
||||
|
||||
GuessXInputDevice(userid, &vendor, &product, &version);
|
||||
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(vendor);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(product);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(version);
|
||||
*guid16++ = 0;
|
||||
|
||||
/* Note that this is an XInput device and what subtype it is */
|
||||
pNewJoystick->guid.data[14] = 'x';
|
||||
pNewJoystick->guid.data[15] = SubType;
|
||||
}
|
||||
pNewJoystick->SubType = SubType;
|
||||
pNewJoystick->XInputUserId = userid;
|
||||
|
||||
if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
|
||||
SDL_free(pNewJoystick);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
if (HIDAPI_IsDevicePresent(vendor, product, version)) {
|
||||
/* The HIDAPI driver is taking care of this device */
|
||||
SDL_free(pNewJoystick);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
WINDOWS_AddJoystickDevice(pNewJoystick);
|
||||
}
|
||||
|
||||
static void
|
||||
DelXInputDevice(Uint8 userid)
|
||||
{
|
||||
if (s_arrXInputDevicePath[userid]) {
|
||||
SDL_free(s_arrXInputDevicePath[userid]);
|
||||
s_arrXInputDevicePath[userid] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
|
||||
{
|
||||
int iuserid;
|
||||
|
||||
if (!s_bXInputEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* iterate in reverse, so these are in the final list in ascending numeric order. */
|
||||
for (iuserid = XUSER_MAX_COUNT - 1; iuserid >= 0; iuserid--) {
|
||||
const Uint8 userid = (Uint8)iuserid;
|
||||
XINPUT_CAPABILITIES capabilities;
|
||||
if (XINPUTGETCAPABILITIES(userid, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) {
|
||||
AddXInputDevice(userid, capabilities.SubType, pContext);
|
||||
} else {
|
||||
DelXInputDevice(userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
|
||||
{
|
||||
const Uint8 userId = joystickdevice->XInputUserId;
|
||||
XINPUT_CAPABILITIES capabilities;
|
||||
XINPUT_VIBRATION state;
|
||||
|
||||
SDL_assert(s_bXInputEnabled);
|
||||
SDL_assert(XINPUTGETCAPABILITIES);
|
||||
SDL_assert(XINPUTSETSTATE);
|
||||
SDL_assert(userId < XUSER_MAX_COUNT);
|
||||
|
||||
joystick->player_index = userId;
|
||||
|
||||
joystick->hwdata->bXInputDevice = SDL_TRUE;
|
||||
|
||||
if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) {
|
||||
SDL_free(joystick->hwdata);
|
||||
joystick->hwdata = NULL;
|
||||
return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?");
|
||||
}
|
||||
SDL_zero(state);
|
||||
joystick->hwdata->bXInputHaptic = (XINPUTSETSTATE(userId, &state) == ERROR_SUCCESS);
|
||||
joystick->hwdata->userid = userId;
|
||||
|
||||
/* The XInput API has a hard coded button/axis mapping, so we just match it */
|
||||
if (SDL_XInputUseOldJoystickMapping()) {
|
||||
joystick->naxes = 6;
|
||||
joystick->nbuttons = 15;
|
||||
} else {
|
||||
joystick->naxes = 6;
|
||||
joystick->nbuttons = 11;
|
||||
joystick->nhats = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation)
|
||||
{
|
||||
if (pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN) {
|
||||
SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN;
|
||||
if (pBatteryInformation->BatteryType == BATTERY_TYPE_WIRED) {
|
||||
ePowerLevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
} else {
|
||||
switch (pBatteryInformation->BatteryLevel) {
|
||||
case BATTERY_LEVEL_EMPTY:
|
||||
ePowerLevel = SDL_JOYSTICK_POWER_EMPTY;
|
||||
break;
|
||||
case BATTERY_LEVEL_LOW:
|
||||
ePowerLevel = SDL_JOYSTICK_POWER_LOW;
|
||||
break;
|
||||
case BATTERY_LEVEL_MEDIUM:
|
||||
ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM;
|
||||
break;
|
||||
default:
|
||||
case BATTERY_LEVEL_FULL:
|
||||
ePowerLevel = SDL_JOYSTICK_POWER_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, ePowerLevel);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation)
|
||||
{
|
||||
static WORD s_XInputButtons[] = {
|
||||
XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT,
|
||||
XINPUT_GAMEPAD_START, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB,
|
||||
XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER,
|
||||
XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y,
|
||||
XINPUT_GAMEPAD_GUIDE
|
||||
};
|
||||
WORD wButtons = pXInputState->Gamepad.wButtons;
|
||||
Uint8 button;
|
||||
|
||||
SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX);
|
||||
SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)));
|
||||
SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX);
|
||||
SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)));
|
||||
SDL_PrivateJoystickAxis(joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger * 65535 / 255) - 32768));
|
||||
SDL_PrivateJoystickAxis(joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger * 65535 / 255) - 32768));
|
||||
|
||||
for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) {
|
||||
SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation)
|
||||
{
|
||||
static WORD s_XInputButtons[] = {
|
||||
XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y,
|
||||
XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_START,
|
||||
XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB,
|
||||
XINPUT_GAMEPAD_GUIDE
|
||||
};
|
||||
WORD wButtons = pXInputState->Gamepad.wButtons;
|
||||
Uint8 button;
|
||||
Uint8 hat = SDL_HAT_CENTERED;
|
||||
|
||||
SDL_PrivateJoystickAxis(joystick, 0, pXInputState->Gamepad.sThumbLX);
|
||||
SDL_PrivateJoystickAxis(joystick, 1, ~pXInputState->Gamepad.sThumbLY);
|
||||
SDL_PrivateJoystickAxis(joystick, 2, ((int)pXInputState->Gamepad.bLeftTrigger * 257) - 32768);
|
||||
SDL_PrivateJoystickAxis(joystick, 3, pXInputState->Gamepad.sThumbRX);
|
||||
SDL_PrivateJoystickAxis(joystick, 4, ~pXInputState->Gamepad.sThumbRY);
|
||||
SDL_PrivateJoystickAxis(joystick, 5, ((int)pXInputState->Gamepad.bRightTrigger * 257) - 32768);
|
||||
|
||||
for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) {
|
||||
SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
if (wButtons & XINPUT_GAMEPAD_DPAD_UP) {
|
||||
hat |= SDL_HAT_UP;
|
||||
}
|
||||
if (wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {
|
||||
hat |= SDL_HAT_DOWN;
|
||||
}
|
||||
if (wButtons & XINPUT_GAMEPAD_DPAD_LEFT) {
|
||||
hat |= SDL_HAT_LEFT;
|
||||
}
|
||||
if (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) {
|
||||
hat |= SDL_HAT_RIGHT;
|
||||
}
|
||||
SDL_PrivateJoystickHat(joystick, 0, hat);
|
||||
|
||||
UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
XINPUT_VIBRATION XVibration;
|
||||
|
||||
if (!XINPUTSETSTATE) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
XVibration.wLeftMotorSpeed = low_frequency_rumble;
|
||||
XVibration.wRightMotorSpeed = high_frequency_rumble;
|
||||
if (XINPUTSETSTATE(joystick->hwdata->userid, &XVibration) != ERROR_SUCCESS) {
|
||||
return SDL_SetError("XInputSetState() failed");
|
||||
}
|
||||
|
||||
if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
|
||||
joystick->hwdata->rumble_expiration = SDL_GetTicks() + duration_ms;
|
||||
} else {
|
||||
joystick->hwdata->rumble_expiration = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
HRESULT result;
|
||||
XINPUT_STATE_EX XInputState;
|
||||
XINPUT_BATTERY_INFORMATION_EX XBatteryInformation;
|
||||
|
||||
if (!XINPUTGETSTATE)
|
||||
return;
|
||||
|
||||
result = XINPUTGETSTATE(joystick->hwdata->userid, &XInputState);
|
||||
if (result == ERROR_DEVICE_NOT_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_zero(XBatteryInformation);
|
||||
if (XINPUTGETBATTERYINFORMATION) {
|
||||
result = XINPUTGETBATTERYINFORMATION(joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation);
|
||||
}
|
||||
|
||||
/* only fire events if the data changed from last time */
|
||||
if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) {
|
||||
if (SDL_XInputUseOldJoystickMapping()) {
|
||||
UpdateXInputJoystickState_OLD(joystick, &XInputState, &XBatteryInformation);
|
||||
} else {
|
||||
UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation);
|
||||
}
|
||||
joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber;
|
||||
}
|
||||
|
||||
if (joystick->hwdata->rumble_expiration) {
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(now, joystick->hwdata->rumble_expiration)) {
|
||||
SDL_XINPUT_JoystickRumble(joystick, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickQuit(void)
|
||||
{
|
||||
if (s_bXInputEnabled) {
|
||||
WIN_UnloadXInputDLL();
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !SDL_JOYSTICK_XINPUT */
|
||||
|
||||
typedef struct JoyStick_DeviceData JoyStick_DeviceData;
|
||||
|
||||
SDL_bool SDL_XINPUT_Enabled(void)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickInit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickQuit(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* SDL_JOYSTICK_XINPUT */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
#include "../../core/windows/SDL_xinput.h"
|
||||
|
||||
extern SDL_bool SDL_XINPUT_Enabled(void);
|
||||
extern int SDL_XINPUT_JoystickInit(void);
|
||||
extern void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext);
|
||||
extern int SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice);
|
||||
extern int SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
extern void SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick);
|
||||
extern void SDL_XINPUT_JoystickClose(SDL_Joystick * joystick);
|
||||
extern void SDL_XINPUT_JoystickQuit(void);
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
Reference in New Issue
Block a user