mirror of
https://github.com/Relintai/sdl2_frt.git
synced 2025-03-21 02:12:27 +01:00
538 lines
22 KiB
C
538 lines
22 KiB
C
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 1997-2014 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_XINPUT
|
|
|
|
/* SDL_xinputjoystick.c implements an XInput-only joystick and game controller
|
|
backend that is suitable for use on WinRT. SDL's DirectInput backend, also
|
|
XInput-capable, was not used as DirectInput is not available on WinRT (or,
|
|
at least, it isn't a public API). Some portions of this XInput backend
|
|
may copy parts of the XInput-using code from the DirectInput backend.
|
|
Refactoring the common parts into one location may be good to-do at some
|
|
point.
|
|
|
|
TODO, WinRT: add hotplug support for XInput based game controllers
|
|
*/
|
|
|
|
#include "SDL_joystick.h"
|
|
#include "../SDL_sysjoystick.h"
|
|
#include "../SDL_joystick_c.h"
|
|
#include "SDL_events.h"
|
|
#include "../../events/SDL_events_c.h"
|
|
#include "SDL_timer.h"
|
|
|
|
#include <Windows.h>
|
|
#include <Xinput.h>
|
|
|
|
struct joystick_hwdata {
|
|
//Uint8 bXInputHaptic; // Supports force feedback via XInput.
|
|
DWORD userIndex; // The XInput device index, in the range [0, XUSER_MAX_COUNT-1] (probably [0,3]).
|
|
XINPUT_STATE XInputState; // the last-read in XInputState, kept around to compare old and new values
|
|
SDL_bool isDeviceConnected; // was the device connected (on the last detection-polling, or during backend-initialization)?
|
|
SDL_bool isDeviceConnectionEventPending; // was a device added, and is the associated add-event pending?
|
|
SDL_bool isDeviceRemovalEventPending; // was the device removed, and is the associated remove-event pending?
|
|
};
|
|
|
|
/* Keep track of data on all XInput devices, regardless of whether or not
|
|
they've been opened (via SDL_JoystickOpen).
|
|
*/
|
|
static struct joystick_hwdata g_XInputData[XUSER_MAX_COUNT];
|
|
|
|
/* Device detection can be extremely costly performance-wise, in some cases.
|
|
In particular, if no devices are connected, calls to detect a single device,
|
|
via either XInputGetState() or XInputGetCapabilities(), can take upwards of
|
|
20 ms on a 1st generation Surface RT, more if devices are detected across
|
|
all of of XInput's four device slots. WinRT and XInput do not appear to
|
|
have callback-based APIs to notify an app when a device is connected, at
|
|
least as of Windows 8.1. The synchronous XInput calls must be used.
|
|
|
|
Once a device is connected, calling XInputGetState() is a much less costly
|
|
operation, with individual calls costing well under 1 ms, and often under
|
|
0.1 ms [on a 1st gen Surface RT].
|
|
|
|
With XInput's performance limitations in mind, a separate device-detection
|
|
thread will be utilized (by SDL) to try to move costly XInput calls off the
|
|
main thread. Polling of active devices still, however, occurs on the main
|
|
thread.
|
|
*/
|
|
static SDL_Thread * g_DeviceDetectionThread = NULL;
|
|
static SDL_mutex * g_DeviceInfoLock = NULL;
|
|
static SDL_bool g_DeviceDetectionQuit = SDL_FALSE;
|
|
|
|
/* Main function for the device-detection thread.
|
|
*/
|
|
static int
|
|
DeviceDetectionThreadMain(void * _data)
|
|
{
|
|
DWORD result;
|
|
XINPUT_CAPABILITIES tempXInputCaps;
|
|
int i;
|
|
|
|
while (1) {
|
|
/* See if the device-detection thread is being asked to shutdown.
|
|
*/
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
if (g_DeviceDetectionQuit) {
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
break;
|
|
}
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
|
|
/* Add a short delay to prevent the device-detection thread from eating
|
|
up too much CPU time:
|
|
*/
|
|
SDL_Delay(300);
|
|
|
|
/* TODO, WinRT: try making the device-detection thread wakeup sooner from its CPU-preserving SDL_Delay, if the thread was asked to quit.
|
|
*/
|
|
|
|
/* See if any new devices are connected. */
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
for (i = 0; i < XUSER_MAX_COUNT; ++i) {
|
|
if (!g_XInputData[i].isDeviceConnected &&
|
|
!g_XInputData[i].isDeviceConnectionEventPending &&
|
|
!g_XInputData[i].isDeviceRemovalEventPending)
|
|
{
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
result = XInputGetCapabilities(i, 0, &tempXInputCaps);
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
if (result == ERROR_SUCCESS) {
|
|
/* Yes, a device is connected. Mark it as such.
|
|
Others will be told about this (via an
|
|
SDL_JOYDEVICEADDED event) in the next call to
|
|
SDL_SYS_JoystickDetect.
|
|
*/
|
|
g_XInputData[i].isDeviceConnected = SDL_TRUE;
|
|
g_XInputData[i].isDeviceConnectionEventPending = SDL_TRUE;
|
|
}
|
|
}
|
|
}
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Function to scan the system for joysticks.
|
|
* It should return 0, or -1 on an unrecoverable fatal error.
|
|
*/
|
|
int
|
|
SDL_SYS_JoystickInit(void)
|
|
{
|
|
HRESULT result = S_OK;
|
|
XINPUT_STATE tempXInputState;
|
|
int i;
|
|
|
|
SDL_zero(g_XInputData);
|
|
|
|
/* Make initial notes on whether or not devices are connected (or not).
|
|
*/
|
|
for (i = 0; i < XUSER_MAX_COUNT; ++i) {
|
|
result = XInputGetState(i, &tempXInputState);
|
|
if (result == ERROR_SUCCESS) {
|
|
g_XInputData[i].isDeviceConnected = SDL_TRUE;
|
|
}
|
|
}
|
|
|
|
/* Start up the device-detection thread.
|
|
*/
|
|
g_DeviceDetectionQuit = SDL_FALSE;
|
|
g_DeviceInfoLock = SDL_CreateMutex();
|
|
g_DeviceDetectionThread = SDL_CreateThread(DeviceDetectionThreadMain, "SDL_joystick", NULL);
|
|
|
|
return (0);
|
|
}
|
|
|
|
int SDL_SYS_NumJoysticks()
|
|
{
|
|
int joystickCount = 0;
|
|
DWORD i;
|
|
|
|
/* Iterate through each possible XInput device and see if something
|
|
was connected (at joystick init, or during the last polling).
|
|
*/
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
for (i = 0; i < XUSER_MAX_COUNT; ++i) {
|
|
if (g_XInputData[i].isDeviceConnected) {
|
|
++joystickCount;
|
|
}
|
|
}
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
|
|
return joystickCount;
|
|
}
|
|
|
|
void SDL_SYS_JoystickDetect()
|
|
{
|
|
DWORD i;
|
|
SDL_Event event;
|
|
|
|
/* Iterate through each possible XInput device, seeing if any devices
|
|
have been connected, or if they were removed.
|
|
*/
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
for (i = 0; i < XUSER_MAX_COUNT; ++i) {
|
|
/* See if any new devices are connected. */
|
|
if (g_XInputData[i].isDeviceConnectionEventPending) {
|
|
#if !SDL_EVENTS_DISABLED
|
|
SDL_zero(event);
|
|
event.type = SDL_JOYDEVICEADDED;
|
|
|
|
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
|
|
event.jdevice.which = i;
|
|
if ((SDL_EventOK == NULL)
|
|
|| (*SDL_EventOK) (SDL_EventOKParam, &event)) {
|
|
SDL_PushEvent(&event);
|
|
}
|
|
}
|
|
#endif
|
|
g_XInputData[i].isDeviceConnectionEventPending = SDL_FALSE;
|
|
} else if (g_XInputData[i].isDeviceRemovalEventPending) {
|
|
/* A device was previously marked as removed (by
|
|
SDL_SYS_JoystickUpdate). Tell others about the device removal.
|
|
*/
|
|
|
|
g_XInputData[i].isDeviceRemovalEventPending = SDL_FALSE;
|
|
|
|
#if !SDL_EVENTS_DISABLED
|
|
SDL_zero(event);
|
|
event.type = SDL_JOYDEVICEREMOVED;
|
|
|
|
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
|
|
event.jdevice.which = i; //joystick->hwdata->userIndex;
|
|
if ((SDL_EventOK == NULL)
|
|
|| (*SDL_EventOK) (SDL_EventOKParam, &event)) {
|
|
SDL_PushEvent(&event);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
}
|
|
|
|
SDL_bool SDL_SYS_JoystickNeedsPolling()
|
|
{
|
|
/* Since XInput, or WinRT, provides any events to indicate when a game
|
|
controller gets connected, and instead indicates device availability
|
|
solely through polling, we'll poll (for new devices).
|
|
*/
|
|
return SDL_TRUE;
|
|
}
|
|
|
|
/* Internal function to retreive device capabilities.
|
|
This function will return an SDL-standard value of 0 on success
|
|
(a device is connected, and data on it was retrieved), or -1
|
|
on failure (no device was connected, or some other error
|
|
occurred. SDL_SetError() will be invoked to set an appropriate
|
|
error message.
|
|
*/
|
|
static int
|
|
SDL_XInput_GetDeviceCapabilities(int device_index, XINPUT_CAPABILITIES * pDeviceCaps)
|
|
{
|
|
HRESULT dwResult;
|
|
|
|
/* Make sure that the device index is a valid one. If not, return to the
|
|
caller with an error.
|
|
*/
|
|
if (device_index < 0 || device_index >= XUSER_MAX_COUNT) {
|
|
return SDL_SetError("invalid/unavailable device index");
|
|
}
|
|
|
|
/* See if a device exists, and if so, what its capabilities are. If a
|
|
device is not available, return to the caller with an error.
|
|
*/
|
|
switch ((dwResult = XInputGetCapabilities(device_index, 0, pDeviceCaps))) {
|
|
case ERROR_SUCCESS:
|
|
/* A device is available, and its capabilities were retrieved! */
|
|
return 0;
|
|
case ERROR_DEVICE_NOT_CONNECTED:
|
|
return SDL_SetError("no device is connected at joystick index, %d", device_index);
|
|
default:
|
|
return SDL_SetError("an unknown error occurred when retrieving info on a device at joystick index, %d", device_index);
|
|
}
|
|
}
|
|
|
|
/* Function to get the device-dependent name of a joystick */
|
|
const char *
|
|
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
|
{
|
|
XINPUT_CAPABILITIES deviceCaps;
|
|
|
|
if (SDL_XInput_GetDeviceCapabilities(device_index, &deviceCaps) != 0) {
|
|
/* Uh oh. Device capabilities couldn't be retrieved. Return to the
|
|
caller. SDL_SetError() has already been invoked (with relevant
|
|
information).
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
switch (deviceCaps.SubType) {
|
|
default:
|
|
if (deviceCaps.Type == XINPUT_DEVTYPE_GAMEPAD) {
|
|
return "Undefined game controller";
|
|
} else {
|
|
return "Undefined controller";
|
|
}
|
|
case XINPUT_DEVSUBTYPE_UNKNOWN:
|
|
if (deviceCaps.Type == XINPUT_DEVTYPE_GAMEPAD) {
|
|
return "Unknown game controller";
|
|
} else {
|
|
return "Unknown controller";
|
|
}
|
|
case XINPUT_DEVSUBTYPE_GAMEPAD:
|
|
return "Gamepad controller";
|
|
case XINPUT_DEVSUBTYPE_WHEEL:
|
|
return "Racing wheel controller";
|
|
case XINPUT_DEVSUBTYPE_ARCADE_STICK:
|
|
return "Arcade stick controller";
|
|
case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
|
|
return "Flight stick controller";
|
|
case XINPUT_DEVSUBTYPE_DANCE_PAD:
|
|
return "Dance pad controller";
|
|
case XINPUT_DEVSUBTYPE_GUITAR:
|
|
return "Guitar controller";
|
|
case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
|
|
return "Guitar controller, Alternate";
|
|
case XINPUT_DEVSUBTYPE_GUITAR_BASS:
|
|
return "Guitar controller, Bass";
|
|
case XINPUT_DEVSUBTYPE_DRUM_KIT:
|
|
return "Drum controller";
|
|
case XINPUT_DEVSUBTYPE_ARCADE_PAD:
|
|
return "Arcade pad controller";
|
|
}
|
|
}
|
|
|
|
/* 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 index field of the joystick.
|
|
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)
|
|
{
|
|
XINPUT_CAPABILITIES deviceCaps;
|
|
|
|
if (SDL_XInput_GetDeviceCapabilities(device_index, &deviceCaps) != 0) {
|
|
/* Uh oh. Device capabilities couldn't be retrieved. Return to the
|
|
caller. SDL_SetError() has already been invoked (with relevant
|
|
information).
|
|
*/
|
|
return -1;
|
|
}
|
|
|
|
/* For now, only game pads are supported. If the device is something other
|
|
than that, return an error to the caller.
|
|
*/
|
|
if (deviceCaps.Type != XINPUT_DEVTYPE_GAMEPAD) {
|
|
return SDL_SetError("a device is connected (at joystick index, %d), but it is of an unknown device type (deviceCaps.Flags=%ul)",
|
|
device_index, (unsigned int)deviceCaps.Flags);
|
|
}
|
|
|
|
/* Create the joystick data structure */
|
|
joystick->instance_id = device_index;
|
|
joystick->hwdata = &g_XInputData[device_index];
|
|
|
|
// The XInput API has a hard coded button/axis mapping, so we just match it
|
|
joystick->naxes = 6;
|
|
joystick->nbuttons = 15;
|
|
joystick->nballs = 0;
|
|
joystick->nhats = 0;
|
|
|
|
/* We're done! */
|
|
return (0);
|
|
}
|
|
|
|
/* Function to determine is this joystick is attached to the system right now */
|
|
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
|
{
|
|
SDL_bool isDeviceConnected;
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
isDeviceConnected = joystick->hwdata->isDeviceConnected;
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
return isDeviceConnected;
|
|
}
|
|
|
|
/* Function to return > 0 if a bit array of buttons differs after applying a mask
|
|
*/
|
|
static int ButtonChanged( int ButtonsNow, int ButtonsPrev, int ButtonMask )
|
|
{
|
|
return ( ButtonsNow & ButtonMask ) != ( ButtonsPrev & ButtonMask );
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
HRESULT result;
|
|
XINPUT_STATE prevXInputState;
|
|
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
|
|
/* Before polling for new data, make note of the old data */
|
|
prevXInputState = joystick->hwdata->XInputState;
|
|
|
|
/* Poll for new data */
|
|
result = XInputGetState(joystick->hwdata->userIndex, &joystick->hwdata->XInputState);
|
|
if (result == ERROR_DEVICE_NOT_CONNECTED) {
|
|
if (joystick->hwdata->isDeviceConnected) {
|
|
joystick->hwdata->isDeviceConnected = SDL_FALSE;
|
|
joystick->hwdata->isDeviceRemovalEventPending = SDL_TRUE;
|
|
/* TODO, WinRT: make sure isDeviceRemovalEventPending gets cleared as appropriate, and that quick re-plugs don't cause trouble */
|
|
}
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
return;
|
|
}
|
|
|
|
/* Make sure the device is marked as connected */
|
|
joystick->hwdata->isDeviceConnected = SDL_TRUE;
|
|
|
|
// only fire events if the data changed from last time
|
|
if ( joystick->hwdata->XInputState.dwPacketNumber != 0
|
|
&& joystick->hwdata->XInputState.dwPacketNumber != prevXInputState.dwPacketNumber )
|
|
{
|
|
XINPUT_STATE *pXInputState = &joystick->hwdata->XInputState;
|
|
XINPUT_STATE *pXInputStatePrev = &prevXInputState;
|
|
|
|
SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX );
|
|
SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-1*pXInputState->Gamepad.sThumbLY-1) );
|
|
SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX );
|
|
SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-1*pXInputState->Gamepad.sThumbRY-1) );
|
|
SDL_PrivateJoystickAxis(joystick, 4, (Sint16)((int)pXInputState->Gamepad.bLeftTrigger*32767/255) );
|
|
SDL_PrivateJoystickAxis(joystick, 5, (Sint16)((int)pXInputState->Gamepad.bRightTrigger*32767/255) );
|
|
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP ) )
|
|
SDL_PrivateJoystickButton(joystick, 0, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN ) )
|
|
SDL_PrivateJoystickButton(joystick, 1, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT ) )
|
|
SDL_PrivateJoystickButton(joystick, 2, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ) )
|
|
SDL_PrivateJoystickButton(joystick, 3, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_START ) )
|
|
SDL_PrivateJoystickButton(joystick, 4, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_START ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_BACK ) )
|
|
SDL_PrivateJoystickButton(joystick, 5, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB ) )
|
|
SDL_PrivateJoystickButton(joystick, 6, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB ) )
|
|
SDL_PrivateJoystickButton(joystick, 7, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ) )
|
|
SDL_PrivateJoystickButton(joystick, 8, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ) )
|
|
SDL_PrivateJoystickButton(joystick, 9, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_A ) )
|
|
SDL_PrivateJoystickButton(joystick, 10, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_A ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_B ) )
|
|
SDL_PrivateJoystickButton(joystick, 11, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_B ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_X ) )
|
|
SDL_PrivateJoystickButton(joystick, 12, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_X ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_Y ) )
|
|
SDL_PrivateJoystickButton(joystick, 13, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_Y ? SDL_PRESSED : SDL_RELEASED );
|
|
if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, 0x400 ) )
|
|
SDL_PrivateJoystickButton(joystick, 14, pXInputState->Gamepad.wButtons & 0x400 ? SDL_PRESSED : SDL_RELEASED ); // 0x400 is the undocumented code for the guide button
|
|
}
|
|
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
}
|
|
|
|
/* Function to close a joystick after use */
|
|
void
|
|
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
|
{
|
|
/* Clear cached button data on the joystick */
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
SDL_zero(joystick->hwdata->XInputState);
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
|
|
/* There's need to free 'hwdata', as it's a pointer to a global array.
|
|
The field will be cleared anyways, just to indicate that it's not
|
|
currently needed.
|
|
*/
|
|
joystick->hwdata = NULL;
|
|
}
|
|
|
|
/* Function to perform any system-specific joystick related cleanup */
|
|
void
|
|
SDL_SYS_JoystickQuit(void)
|
|
{
|
|
/* Tell the joystick detection thread to stop, then wait for it to finish */
|
|
SDL_LockMutex(g_DeviceInfoLock);
|
|
g_DeviceDetectionQuit = SDL_TRUE;
|
|
SDL_UnlockMutex(g_DeviceInfoLock);
|
|
SDL_WaitThread(g_DeviceDetectionThread, NULL);
|
|
|
|
/* Clean up device-detection stuff */
|
|
SDL_DestroyMutex(g_DeviceInfoLock);
|
|
g_DeviceInfoLock = NULL;
|
|
g_DeviceDetectionThread = NULL;
|
|
g_DeviceDetectionQuit = SDL_FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
SDL_bool SDL_SYS_IsXInputDeviceIndex(int device_index)
|
|
{
|
|
/* The XInput-capable DirectInput joystick backend implements the same
|
|
function (SDL_SYS_IsXInputDeviceIndex), however in that case, not all
|
|
joystick devices are XInput devices. In this case, with the
|
|
WinRT-enabled XInput-only backend, all "joystick" devices are XInput
|
|
devices.
|
|
*/
|
|
return SDL_TRUE;
|
|
}
|
|
|
|
#endif /* SDL_JOYSTICK_XINPUT */
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|