diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj index e070c31ef7..cec3972f0f 100644 --- a/VisualC-GDK/SDL/SDL.vcxproj +++ b/VisualC-GDK/SDL/SDL.vcxproj @@ -438,6 +438,7 @@ + @@ -576,9 +577,7 @@ - - @@ -691,6 +690,10 @@ CompileAsCpp CompileAsCpp + + $(IntDir)$(TargetName)_cpp.pch + $(IntDir)$(TargetName)_cpp.pch + diff --git a/include/build_config/SDL_build_config_wingdk.h b/include/build_config/SDL_build_config_wingdk.h index 2f25b597e5..d856d2323e 100644 --- a/include/build_config/SDL_build_config_wingdk.h +++ b/include/build_config/SDL_build_config_wingdk.h @@ -176,6 +176,16 @@ #define SDL_JOYSTICK_XINPUT 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 */ #ifdef HAVE_SENSORSAPI_H #define SDL_SENSOR_WINDOWS 1 diff --git a/include/build_config/SDL_build_config_xbox.h b/include/build_config/SDL_build_config_xbox.h index 2f0f090fe7..c5198aeec7 100644 --- a/include/build_config/SDL_build_config_xbox.h +++ b/include/build_config/SDL_build_config_xbox.h @@ -173,7 +173,17 @@ #ifdef HAVE_WINDOWS_GAMING_INPUT_H #define SDL_JOYSTICK_WGI 1 #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*/ /* Enable the sensor driver */ diff --git a/src/core/windows/SDL_xinput.c b/src/core/windows/SDL_xinput.c index 13c06bde4d..fdeed70854 100644 --- a/src/core/windows/SDL_xinput.c +++ b/src/core/windows/SDL_xinput.c @@ -20,6 +20,8 @@ */ #include "SDL_internal.h" +#ifndef SDL_JOYSTICK_GAMEINPUT + #include "SDL_xinput.h" /* Set up for C function definitions, even when using C++ */ @@ -142,3 +144,5 @@ void WIN_UnloadXInputDLL(void) #ifdef __cplusplus } #endif + +#endif /* !SDL_JOYSTICK_GAMEINPUT */ diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index bbc553b58b..c1c1a3843c 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -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 */ &SDL_RAWINPUT_JoystickDriver, #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 */ &SDL_WINDOWS_JoystickDriver, #endif diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 95544118da..739d6973d1 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -245,6 +245,7 @@ extern SDL_JoystickDriver SDL_PS2_JoystickDriver; extern SDL_JoystickDriver SDL_PSP_JoystickDriver; extern SDL_JoystickDriver SDL_VITA_JoystickDriver; extern SDL_JoystickDriver SDL_N3DS_JoystickDriver; +extern SDL_JoystickDriver SDL_GAMEINPUT_JoystickDriver; /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/src/joystick/gdk/SDL_gameinputjoystick.cpp b/src/joystick/gdk/SDL_gameinputjoystick.cpp new file mode 100644 index 0000000000..1b4223d6ea --- /dev/null +++ b/src/joystick/gdk/SDL_gameinputjoystick.cpp @@ -0,0 +1,582 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + 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 */ diff --git a/src/joystick/gdk/SDL_gameinputjoystick_c.h b/src/joystick/gdk/SDL_gameinputjoystick_c.h new file mode 100644 index 0000000000..03bc1c0599 --- /dev/null +++ b/src/joystick/gdk/SDL_gameinputjoystick_c.h @@ -0,0 +1,58 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + 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 + +/* 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 */