GameInput backend for SDL (Gamepad-only for now)
This commit is contained in:
parent
7ed1f3554d
commit
534f753e20
8 changed files with 674 additions and 3 deletions
|
@ -438,6 +438,7 @@
|
||||||
<ClInclude Include="..\..\src\joystick\windows\SDL_rawinputjoystick_c.h" />
|
<ClInclude Include="..\..\src\joystick\windows\SDL_rawinputjoystick_c.h" />
|
||||||
<ClInclude Include="..\..\src\joystick\windows\SDL_windowsjoystick_c.h" />
|
<ClInclude Include="..\..\src\joystick\windows\SDL_windowsjoystick_c.h" />
|
||||||
<ClInclude Include="..\..\src\joystick\windows\SDL_xinputjoystick_c.h" />
|
<ClInclude Include="..\..\src\joystick\windows\SDL_xinputjoystick_c.h" />
|
||||||
|
<ClInclude Include="..\..\src\joystick\gdk\SDL_gameinputjoystick_c.h" />
|
||||||
<ClInclude Include="..\..\src\libm\math_libm.h" />
|
<ClInclude Include="..\..\src\libm\math_libm.h" />
|
||||||
<ClInclude Include="..\..\src\libm\math_private.h" />
|
<ClInclude Include="..\..\src\libm\math_private.h" />
|
||||||
<ClInclude Include="..\..\src\locale\SDL_syslocale.h" />
|
<ClInclude Include="..\..\src\locale\SDL_syslocale.h" />
|
||||||
|
@ -576,9 +577,7 @@
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_lsx.h" />
|
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_lsx.h" />
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_lsx_func.h" />
|
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_lsx_func.h" />
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_sse.h" />
|
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_sse.h" />
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_sse_func.h" />
|
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_std.h" />
|
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_std.h" />
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_std_func.h" />
|
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_sse_func.h" />
|
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_sse_func.h" />
|
||||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_std_func.h" />
|
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_std_func.h" />
|
||||||
<ClCompile Include="..\..\src\atomic\SDL_atomic.c" />
|
<ClCompile Include="..\..\src\atomic\SDL_atomic.c" />
|
||||||
|
@ -691,6 +690,10 @@
|
||||||
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'">CompileAsCpp</CompileAs>
|
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'">CompileAsCpp</CompileAs>
|
||||||
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'">CompileAsCpp</CompileAs>
|
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'">CompileAsCpp</CompileAs>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.cpp">
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\libm\e_atan2.c" />
|
<ClCompile Include="..\..\src\libm\e_atan2.c" />
|
||||||
<ClCompile Include="..\..\src\libm\e_exp.c" />
|
<ClCompile Include="..\..\src\libm\e_exp.c" />
|
||||||
<ClCompile Include="..\..\src\libm\e_fmod.c" />
|
<ClCompile Include="..\..\src\libm\e_fmod.c" />
|
||||||
|
|
|
@ -176,6 +176,16 @@
|
||||||
#define SDL_JOYSTICK_XINPUT 1
|
#define SDL_JOYSTICK_XINPUT 1
|
||||||
#define SDL_HAPTIC_DINPUT 1
|
#define SDL_HAPTIC_DINPUT 1
|
||||||
|
|
||||||
|
/* Native GameInput: */
|
||||||
|
/*#define SDL_JOYSTICK_GAMEINPUT 1*/
|
||||||
|
#if defined(SDL_JOYSTICK_GAMEINPUT) && (defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_DINPUT))
|
||||||
|
#error "GameInput cannot co-exist, choose one."
|
||||||
|
#endif /* defined(SDL_JOYSTICK_GAMEINPUT) && (defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_DINPUT)) */
|
||||||
|
#if defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT
|
||||||
|
/* TODO: Implement proper haptics for GameInput! */
|
||||||
|
#define SDL_HAPTIC_DUMMY 1
|
||||||
|
#endif /* defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT */
|
||||||
|
|
||||||
/* Enable the sensor driver */
|
/* Enable the sensor driver */
|
||||||
#ifdef HAVE_SENSORSAPI_H
|
#ifdef HAVE_SENSORSAPI_H
|
||||||
#define SDL_SENSOR_WINDOWS 1
|
#define SDL_SENSOR_WINDOWS 1
|
||||||
|
|
|
@ -173,7 +173,17 @@
|
||||||
#ifdef HAVE_WINDOWS_GAMING_INPUT_H
|
#ifdef HAVE_WINDOWS_GAMING_INPUT_H
|
||||||
#define SDL_JOYSTICK_WGI 1
|
#define SDL_JOYSTICK_WGI 1
|
||||||
#endif
|
#endif
|
||||||
#define SDL_JOYSTICK_XINPUT 1
|
/* This is XInputOnGameInput for GDK platforms: */
|
||||||
|
/*#define SDL_JOYSTICK_XINPUT 1*/
|
||||||
|
/* Native GameInput: */
|
||||||
|
#define SDL_JOYSTICK_GAMEINPUT 1
|
||||||
|
#if defined(SDL_JOYSTICK_GAMEINPUT) && (defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_DINPUT))
|
||||||
|
#error "GameInput cannot co-exist, choose one."
|
||||||
|
#endif /* defined(SDL_JOYSTICK_GAMEINPUT) && (defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_DINPUT)) */
|
||||||
|
#if defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT
|
||||||
|
/* TODO: Implement proper haptics for GameInput! */
|
||||||
|
#define SDL_HAPTIC_DUMMY 1
|
||||||
|
#endif /* defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT */
|
||||||
/*#define SDL_HAPTIC_DINPUT 1*/
|
/*#define SDL_HAPTIC_DINPUT 1*/
|
||||||
|
|
||||||
/* Enable the sensor driver */
|
/* Enable the sensor driver */
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
*/
|
*/
|
||||||
#include "SDL_internal.h"
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
|
#ifndef SDL_JOYSTICK_GAMEINPUT
|
||||||
|
|
||||||
#include "SDL_xinput.h"
|
#include "SDL_xinput.h"
|
||||||
|
|
||||||
/* Set up for C function definitions, even when using C++ */
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
@ -142,3 +144,5 @@ void WIN_UnloadXInputDLL(void)
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* !SDL_JOYSTICK_GAMEINPUT */
|
||||||
|
|
|
@ -55,6 +55,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
||||||
#ifdef SDL_JOYSTICK_RAWINPUT /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
|
#ifdef SDL_JOYSTICK_RAWINPUT /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
|
||||||
&SDL_RAWINPUT_JoystickDriver,
|
&SDL_RAWINPUT_JoystickDriver,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SDL_JOYSTICK_GAMEINPUT /* Before WINDOWS_ driver, as GameInput takes priority over XInputOnGameInput for GDK platforms */
|
||||||
|
&SDL_GAMEINPUT_JoystickDriver,
|
||||||
|
#endif
|
||||||
#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) /* Before WGI driver, as WGI wants to check if this driver is handling things */
|
#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) /* Before WGI driver, as WGI wants to check if this driver is handling things */
|
||||||
&SDL_WINDOWS_JoystickDriver,
|
&SDL_WINDOWS_JoystickDriver,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -245,6 +245,7 @@ extern SDL_JoystickDriver SDL_PS2_JoystickDriver;
|
||||||
extern SDL_JoystickDriver SDL_PSP_JoystickDriver;
|
extern SDL_JoystickDriver SDL_PSP_JoystickDriver;
|
||||||
extern SDL_JoystickDriver SDL_VITA_JoystickDriver;
|
extern SDL_JoystickDriver SDL_VITA_JoystickDriver;
|
||||||
extern SDL_JoystickDriver SDL_N3DS_JoystickDriver;
|
extern SDL_JoystickDriver SDL_N3DS_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_GAMEINPUT_JoystickDriver;
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
582
src/joystick/gdk/SDL_gameinputjoystick.cpp
Normal file
582
src/joystick/gdk/SDL_gameinputjoystick.cpp
Normal file
|
@ -0,0 +1,582 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2024 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_gameinputjoystick_c.h"
|
||||||
|
|
||||||
|
#if defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Public APIs: GAMEINPUT_Joystick... */
|
||||||
|
/* Private APIs: GAMEINPUT_InternalJoystick... */
|
||||||
|
|
||||||
|
#include "../usb_ids.h"
|
||||||
|
|
||||||
|
typedef struct GAMEINPUT_InternalDevice
|
||||||
|
{
|
||||||
|
IGameInputDevice *device;
|
||||||
|
const char *deviceName; /* this is a constant string literal */
|
||||||
|
SDL_JoystickGUID joystickGuid; /* generated by SDL. */
|
||||||
|
SDL_JoystickID instanceId; /* generated by SDL. */
|
||||||
|
int playerIndex;
|
||||||
|
Uint32 caps;
|
||||||
|
char devicePath[(APP_LOCAL_DEVICE_ID_SIZE * 2) + 1];
|
||||||
|
bool isAdded, isDeleteRequested;
|
||||||
|
} GAMEINPUT_InternalDevice;
|
||||||
|
|
||||||
|
typedef struct GAMEINPUT_InternalList
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice **devices;
|
||||||
|
int count;
|
||||||
|
} GAMEINPUT_InternalList;
|
||||||
|
|
||||||
|
typedef struct joystick_hwdata
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice *devref;
|
||||||
|
GameInputRumbleParams rumbleParams;
|
||||||
|
Uint64 lastTimestamp;
|
||||||
|
} GAMEINPUT_InternalJoystickHwdata;
|
||||||
|
|
||||||
|
|
||||||
|
static GAMEINPUT_InternalList g_GameInputList = { NULL };
|
||||||
|
static IGameInput *g_pGameInput = NULL;
|
||||||
|
static GameInputCallbackToken g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE;
|
||||||
|
|
||||||
|
|
||||||
|
static int GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice **devicelist = NULL;
|
||||||
|
GAMEINPUT_InternalDevice *elem = NULL;
|
||||||
|
const GameInputDeviceInfo *devinfo = NULL;
|
||||||
|
char tmpbuff[4];
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
if (!pDevice) {
|
||||||
|
return SDL_SetError("GAMEINPUT_InternalAddOrFind argument pDevice cannot be NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
devinfo = pDevice->GetDeviceInfo();
|
||||||
|
if (!devinfo) {
|
||||||
|
return SDL_SetError("GAMEINPUT_InternalAddOrFind GetDeviceInfo returned NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx = 0; idx < g_GameInputList.count; ++idx) {
|
||||||
|
elem = g_GameInputList.devices[idx];
|
||||||
|
if (elem && elem->device == pDevice) {
|
||||||
|
/* we're already added */
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elem = (GAMEINPUT_InternalDevice *)SDL_calloc(1, sizeof(*elem));
|
||||||
|
if (!elem) {
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate a device name */
|
||||||
|
for (idx = 0; idx < APP_LOCAL_DEVICE_ID_SIZE; ++idx) {
|
||||||
|
(void)SDL_snprintf(tmpbuff, SDL_arraysize(tmpbuff), "%02hhX", devinfo->deviceId.value[idx]);
|
||||||
|
(void)strncat_s(elem->devicePath, tmpbuff, SDL_arraysize(tmpbuff));
|
||||||
|
}
|
||||||
|
|
||||||
|
devicelist = (GAMEINPUT_InternalDevice **)SDL_realloc(g_GameInputList.devices, sizeof(elem) * (g_GameInputList.count + 1LL));
|
||||||
|
if (!devicelist) {
|
||||||
|
SDL_free(elem);
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_GameInputList.devices = devicelist;
|
||||||
|
pDevice->AddRef();
|
||||||
|
elem->device = pDevice;
|
||||||
|
elem->deviceName = "GameInput Gamepad";
|
||||||
|
elem->caps = 0;
|
||||||
|
if (devinfo->supportedRumbleMotors & (GameInputRumbleLowFrequency | GameInputRumbleHighFrequency)) {
|
||||||
|
elem->caps |= SDL_JOYSTICK_CAP_RUMBLE;
|
||||||
|
}
|
||||||
|
if (devinfo->supportedRumbleMotors & (GameInputRumbleLeftTrigger | GameInputRumbleRightTrigger)) {
|
||||||
|
elem->caps |= SDL_JOYSTICK_CAP_TRIGGER_RUMBLE;
|
||||||
|
}
|
||||||
|
elem->joystickGuid = SDL_CreateJoystickGUID(
|
||||||
|
SDL_HARDWARE_BUS_BLUETOOTH,
|
||||||
|
USB_VENDOR_MICROSOFT,
|
||||||
|
USB_PRODUCT_XBOX_SERIES_X_BLE,
|
||||||
|
1,
|
||||||
|
"GameInput",
|
||||||
|
"Gamepad",
|
||||||
|
'g',
|
||||||
|
0
|
||||||
|
);
|
||||||
|
elem->instanceId = SDL_GetNextObjectID();
|
||||||
|
g_GameInputList.devices[g_GameInputList.count] = elem;
|
||||||
|
|
||||||
|
/* finally increment the count and return */
|
||||||
|
return g_GameInputList.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_InternalRemoveByIndex(int idx)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice **devicelist = NULL;
|
||||||
|
int bytes = 0;
|
||||||
|
|
||||||
|
if (idx < 0 || idx >= g_GameInputList.count) {
|
||||||
|
return SDL_SetError("GAMEINPUT_InternalRemoveByIndex argument idx %d is out of range", idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_GameInputList.devices[idx]->device->Release();
|
||||||
|
|
||||||
|
if (g_GameInputList.devices[idx]) {
|
||||||
|
SDL_free(g_GameInputList.devices[idx]);
|
||||||
|
g_GameInputList.devices[idx] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_GameInputList.count == 1) {
|
||||||
|
/* last element in the list, free the entire list then */
|
||||||
|
SDL_free(g_GameInputList.devices);
|
||||||
|
g_GameInputList.devices = NULL;
|
||||||
|
} else {
|
||||||
|
if (idx != g_GameInputList.count - 1) {
|
||||||
|
bytes = sizeof(*devicelist) * (g_GameInputList.count - idx);
|
||||||
|
SDL_memmove(&g_GameInputList.devices[idx], &g_GameInputList.devices[idx + 1], bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
devicelist = (GAMEINPUT_InternalDevice **)SDL_realloc(g_GameInputList.devices, sizeof(*devicelist) * (g_GameInputList.count - 1LL));
|
||||||
|
if (!devicelist) {
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_GameInputList.devices = devicelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decrement the count and return */
|
||||||
|
return g_GameInputList.count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GAMEINPUT_InternalDevice *GAMEINPUT_InternalFindByIndex(int idx)
|
||||||
|
{
|
||||||
|
if (idx < 0 || idx >= g_GameInputList.count) {
|
||||||
|
SDL_SetError("GAMEINPUT_InternalFindByIndex argument idx %d out of range", idx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_GameInputList.devices[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CALLBACK GAMEINPUT_InternalJoystickDeviceCallback(
|
||||||
|
_In_ GameInputCallbackToken callbackToken,
|
||||||
|
_In_ void* context,
|
||||||
|
_In_ IGameInputDevice* device,
|
||||||
|
_In_ uint64_t timestamp,
|
||||||
|
_In_ GameInputDeviceStatus currentStatus,
|
||||||
|
_In_ GameInputDeviceStatus previousStatus)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
GAMEINPUT_InternalDevice *elem = NULL;
|
||||||
|
|
||||||
|
if (currentStatus & GameInputDeviceConnected) {
|
||||||
|
GAMEINPUT_InternalAddOrFind(device);
|
||||||
|
} else {
|
||||||
|
for (idx = 0; idx < g_GameInputList.count; ++idx) {
|
||||||
|
elem = g_GameInputList.devices[idx];
|
||||||
|
if (elem && elem->device == device) {
|
||||||
|
/* will be deleted on the next Detect call */
|
||||||
|
elem->isDeleteRequested = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAMEINPUT_JoystickDetect(void);
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickInit(void)
|
||||||
|
{
|
||||||
|
HRESULT hR;
|
||||||
|
|
||||||
|
if (!g_pGameInput) {
|
||||||
|
hR = GameInputCreate(&g_pGameInput);
|
||||||
|
if (FAILED(hR)) {
|
||||||
|
return SDL_SetError("GameInputCreate failure with HRESULT of %08X", hR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hR = g_pGameInput->RegisterDeviceCallback(
|
||||||
|
nullptr,
|
||||||
|
GameInputKindGamepad,
|
||||||
|
GameInputDeviceConnected,
|
||||||
|
GameInputBlockingEnumeration,
|
||||||
|
nullptr,
|
||||||
|
GAMEINPUT_InternalJoystickDeviceCallback,
|
||||||
|
&g_GameInputCallbackToken
|
||||||
|
);
|
||||||
|
if (FAILED(hR)) {
|
||||||
|
return SDL_SetError("IGameInput::RegisterDeviceCallback failure with HRESULT of %08X", hR);
|
||||||
|
}
|
||||||
|
|
||||||
|
GAMEINPUT_JoystickDetect();
|
||||||
|
|
||||||
|
/* no need to free IGameInput on failure. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickGetCount(void)
|
||||||
|
{
|
||||||
|
return g_GameInputList.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAMEINPUT_JoystickDetect(void)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
GAMEINPUT_InternalDevice *elem = NULL;
|
||||||
|
|
||||||
|
for (idx = 0; idx < g_GameInputList.count; ++idx) {
|
||||||
|
elem = g_GameInputList.devices[idx];
|
||||||
|
if (!elem) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elem->isAdded) {
|
||||||
|
SDL_PrivateJoystickAdded(elem->instanceId);
|
||||||
|
elem->isAdded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elem->isDeleteRequested || !(elem->device->GetDeviceStatus() & GameInputDeviceConnected)) {
|
||||||
|
SDL_PrivateJoystickRemoved(elem->instanceId);
|
||||||
|
GAMEINPUT_InternalRemoveByIndex(idx--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *GAMEINPUT_JoystickGetDeviceName(int device_index)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem->deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *GAMEINPUT_JoystickGetDevicePath(int device_index)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* APP_LOCAL_DEVICE_ID as a hex string, since it's required for some association callbacks */
|
||||||
|
return elem->devicePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
|
||||||
|
{
|
||||||
|
/* Steamworks API is not available in GDK */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickGetDevicePlayerIndex(int device_index)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Okay, so, while XInput technically has player indicies,
|
||||||
|
* GameInput does not. It just dispatches a callback whenever a device is found.
|
||||||
|
* So if you're using true native GameInput (which this backend IS)
|
||||||
|
* you're meant to assign some index to a player yourself.
|
||||||
|
*
|
||||||
|
* GameMaker, for example, seems to do this in the order of plugging in.
|
||||||
|
*
|
||||||
|
* Sorry for the trouble!
|
||||||
|
*/
|
||||||
|
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem->playerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAMEINPUT_JoystickSetDevicePlayerIndex(int device_index, int player_index)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem->playerIndex = player_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_JoystickGUID GAMEINPUT_JoystickGetDeviceGUID(int device_index)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
/* empty guid */
|
||||||
|
return { { 0 } };
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem->joystickGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_JoystickID GAMEINPUT_JoystickGetDeviceInstanceID(int device_index)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem->instanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||||
|
{
|
||||||
|
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
|
||||||
|
GAMEINPUT_InternalJoystickHwdata *hwdata = NULL;
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hwdata = (GAMEINPUT_InternalJoystickHwdata *)SDL_calloc(1, sizeof(*hwdata));
|
||||||
|
if (!hwdata) {
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
hwdata->devref = elem;
|
||||||
|
|
||||||
|
joystick->hwdata = hwdata;
|
||||||
|
joystick->naxes = 6;
|
||||||
|
joystick->nbuttons = 11;
|
||||||
|
joystick->nhats = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||||
|
{
|
||||||
|
/* don't check for caps here, since SetRumbleState doesn't return any result - we don't need to check it */
|
||||||
|
GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata;
|
||||||
|
GameInputRumbleParams *params = &hwdata->rumbleParams;
|
||||||
|
params->lowFrequency = (float)low_frequency_rumble / (float)SDL_MAX_UINT16;
|
||||||
|
params->highFrequency = (float)high_frequency_rumble / (float)SDL_MAX_UINT16;
|
||||||
|
hwdata->devref->device->SetRumbleState(params);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||||
|
{
|
||||||
|
/* don't check for caps here, since SetRumbleState doesn't return any result - we don't need to check it */
|
||||||
|
GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata;
|
||||||
|
GameInputRumbleParams *params = &hwdata->rumbleParams;
|
||||||
|
params->leftTrigger = (float)left_rumble / (float)SDL_MAX_UINT16;
|
||||||
|
params->rightTrigger = (float)right_rumble / (float)SDL_MAX_UINT16;
|
||||||
|
hwdata->devref->device->SetRumbleState(params);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Uint32 GAMEINPUT_JoystickGetCapabilities(SDL_Joystick *joystick)
|
||||||
|
{
|
||||||
|
return joystick->hwdata->devref->caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||||
|
{
|
||||||
|
return SDL_Unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
|
||||||
|
{
|
||||||
|
HRESULT hR = S_OK;
|
||||||
|
const GAMEINPUT_JoystickEffectData *effect = NULL;
|
||||||
|
GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata;
|
||||||
|
|
||||||
|
if (!data || size != sizeof(GAMEINPUT_JoystickEffectData)) {
|
||||||
|
return SDL_SetError("GAMEINPUT_JoystickSendEffect invalid data or size");
|
||||||
|
}
|
||||||
|
|
||||||
|
effect = (const GAMEINPUT_JoystickEffectData *)data;
|
||||||
|
if (effect->type == GAMEINPUT_JoystickEffectDataType_HapticFeedback) {
|
||||||
|
hR = hwdata->devref->device->SetHapticMotorState(
|
||||||
|
effect->hapticFeedbackMotorIndex,
|
||||||
|
&effect->hapticFeedbackParams
|
||||||
|
);
|
||||||
|
if (FAILED(hR)) {
|
||||||
|
return SDL_SetError("IGameInputDevice::SetHapticMotorState failure with HRESULT of %08X", hR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAMEINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
|
||||||
|
{
|
||||||
|
/* I am not sure what is this even supposed to do in case of GameInput... */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
|
||||||
|
{
|
||||||
|
static WORD s_XInputButtons[] = {
|
||||||
|
GameInputGamepadA, GameInputGamepadB, GameInputGamepadX, GameInputGamepadY,
|
||||||
|
GameInputGamepadLeftShoulder, GameInputGamepadRightShoulder, GameInputGamepadView, GameInputGamepadMenu,
|
||||||
|
GameInputGamepadLeftThumbstick, GameInputGamepadRightThumbstick,
|
||||||
|
0 /* Guide button is not supported on Xbox so ignore that... */
|
||||||
|
};
|
||||||
|
Uint8 btnidx = 0, btnstate = 0, hat = 0;
|
||||||
|
GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata;
|
||||||
|
IGameInputDevice *device = hwdata->devref->device;
|
||||||
|
IGameInputReading *reading = NULL;
|
||||||
|
uint64_t ts = 0;
|
||||||
|
GameInputGamepadState state;
|
||||||
|
HRESULT hR = g_pGameInput->GetCurrentReading(
|
||||||
|
GameInputKindGamepad,
|
||||||
|
device,
|
||||||
|
&reading
|
||||||
|
);
|
||||||
|
|
||||||
|
if (FAILED(hR)) {
|
||||||
|
/* don't SetError here since there can be a legitimate case when there's no reading avail */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GDKX private docs for GetTimestamp: "The microsecond timestamp describing when the input was made." */
|
||||||
|
/* SDL expects a nanosecond timestamp, so I guess US_TO_NS should be used here? */
|
||||||
|
ts = SDL_US_TO_NS(reading->GetTimestamp());
|
||||||
|
|
||||||
|
if (((!hwdata->lastTimestamp) || (ts != hwdata->lastTimestamp)) && reading->GetGamepadState(&state)) {
|
||||||
|
/* `state` is now valid */
|
||||||
|
|
||||||
|
#define tosint16(_TheValue) ((Sint16)(((_TheValue) < 0.0f) ? ((_TheValue) * 32768.0f) : ((_TheValue) * 32767.0f)))
|
||||||
|
SDL_SendJoystickAxis(ts, joystick, 0, tosint16(state.leftThumbstickX));
|
||||||
|
SDL_SendJoystickAxis(ts, joystick, 1, tosint16(state.leftThumbstickY));
|
||||||
|
SDL_SendJoystickAxis(ts, joystick, 2, tosint16(state.leftTrigger));
|
||||||
|
SDL_SendJoystickAxis(ts, joystick, 3, tosint16(state.rightThumbstickX));
|
||||||
|
SDL_SendJoystickAxis(ts, joystick, 4, tosint16(state.rightThumbstickY));
|
||||||
|
SDL_SendJoystickAxis(ts, joystick, 5, tosint16(state.rightTrigger));
|
||||||
|
#undef tosint16
|
||||||
|
|
||||||
|
for (btnidx = 0; btnidx < (Uint8)SDL_arraysize(s_XInputButtons); ++btnidx) {
|
||||||
|
if (s_XInputButtons[btnidx] == 0) {
|
||||||
|
btnstate = SDL_RELEASED;
|
||||||
|
} else {
|
||||||
|
btnstate = (state.buttons & s_XInputButtons[btnidx]) ? SDL_PRESSED : SDL_RELEASED;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SendJoystickButton(ts, joystick, btnidx, btnstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.buttons & GameInputGamepadDPadUp) {
|
||||||
|
hat |= SDL_HAT_UP;
|
||||||
|
}
|
||||||
|
if (state.buttons & GameInputGamepadDPadDown) {
|
||||||
|
hat |= SDL_HAT_DOWN;
|
||||||
|
}
|
||||||
|
if (state.buttons & GameInputGamepadDPadLeft) {
|
||||||
|
hat |= SDL_HAT_LEFT;
|
||||||
|
}
|
||||||
|
if (state.buttons & GameInputGamepadDPadRight) {
|
||||||
|
hat |= SDL_HAT_RIGHT;
|
||||||
|
}
|
||||||
|
SDL_SendJoystickHat(ts, joystick, 0, hat);
|
||||||
|
|
||||||
|
/* Xbox doesn't let you obtain the power level, pretend we're always full */
|
||||||
|
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
|
||||||
|
|
||||||
|
hwdata->lastTimestamp = ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
reading->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAMEINPUT_JoystickClose(SDL_Joystick* joystick)
|
||||||
|
{
|
||||||
|
SDL_free(joystick->hwdata);
|
||||||
|
joystick->hwdata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAMEINPUT_JoystickQuit(void)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
if (!g_pGameInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the callback */
|
||||||
|
g_pGameInput->UnregisterCallback(g_GameInputCallbackToken, /*timeoutInUs:*/ 10000);
|
||||||
|
g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE;
|
||||||
|
|
||||||
|
/* free the list */
|
||||||
|
for (idx = 0; idx < g_GameInputList.count; ++idx) {
|
||||||
|
g_GameInputList.devices[idx]->device->Release();
|
||||||
|
SDL_free(g_GameInputList.devices[idx]);
|
||||||
|
g_GameInputList.devices[idx] = NULL;
|
||||||
|
}
|
||||||
|
SDL_free(g_GameInputList.devices);
|
||||||
|
g_GameInputList.devices = NULL;
|
||||||
|
g_GameInputList.count = 0;
|
||||||
|
|
||||||
|
g_pGameInput->Release();
|
||||||
|
g_pGameInput = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
|
||||||
|
{
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SDL_JoystickDriver SDL_GAMEINPUT_JoystickDriver =
|
||||||
|
{
|
||||||
|
GAMEINPUT_JoystickInit,
|
||||||
|
GAMEINPUT_JoystickGetCount,
|
||||||
|
GAMEINPUT_JoystickDetect,
|
||||||
|
GAMEINPUT_JoystickGetDeviceName,
|
||||||
|
GAMEINPUT_JoystickGetDevicePath,
|
||||||
|
GAMEINPUT_JoystickGetDeviceSteamVirtualGamepadSlot,
|
||||||
|
GAMEINPUT_JoystickGetDevicePlayerIndex,
|
||||||
|
GAMEINPUT_JoystickSetDevicePlayerIndex,
|
||||||
|
GAMEINPUT_JoystickGetDeviceGUID,
|
||||||
|
GAMEINPUT_JoystickGetDeviceInstanceID,
|
||||||
|
GAMEINPUT_JoystickOpen,
|
||||||
|
GAMEINPUT_JoystickRumble,
|
||||||
|
GAMEINPUT_JoystickRumbleTriggers,
|
||||||
|
GAMEINPUT_JoystickGetCapabilities,
|
||||||
|
GAMEINPUT_JoystickSetLED,
|
||||||
|
GAMEINPUT_JoystickSendEffect,
|
||||||
|
GAMEINPUT_JoystickSetSensorsEnabled,
|
||||||
|
GAMEINPUT_JoystickUpdate,
|
||||||
|
GAMEINPUT_JoystickClose,
|
||||||
|
GAMEINPUT_JoystickQuit,
|
||||||
|
GAMEINPUT_JoystickGetGamepadMapping
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT */
|
58
src/joystick/gdk/SDL_gameinputjoystick_c.h
Normal file
58
src/joystick/gdk/SDL_gameinputjoystick_c.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2024 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 defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT
|
||||||
|
|
||||||
|
/* include this file in C++ */
|
||||||
|
#include <GameInput.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum GAMEINPUT_JoystickEffectDataType
|
||||||
|
{
|
||||||
|
GAMEINPUT_JoystickEffectDataType_HapticFeedback
|
||||||
|
} GAMEINPUT_JoystickEffectDataType;
|
||||||
|
|
||||||
|
typedef struct GAMEINPUT_JoystickEffectData
|
||||||
|
{
|
||||||
|
GAMEINPUT_JoystickEffectDataType type;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct /* type == GAMEINPUT_JoystickEffectDataType_HapticFeedback */
|
||||||
|
{
|
||||||
|
uint32_t hapticFeedbackMotorIndex;
|
||||||
|
GameInputHapticFeedbackParams hapticFeedbackParams;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} GAMEINPUT_JoystickEffectData;
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* defined(SDL_JOYSTICK_GAMEINPUT) && SDL_JOYSTICK_GAMEINPUT */
|
Loading…
Add table
Add a link
Reference in a new issue