Added Steam Input API support for game controllers

Added support for getting the real controller info, as well as the function SDL_GetGamepadSteamHandle() to get the Steam Input API handle, from the virtual gamepads provided by Steam.

Also added an event SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED which is triggered when a controller's API handle changes, e.g. the controllers were reassigned slots in the Steam UI.
This commit is contained in:
Sam Lantinga
2023-12-09 23:05:34 -08:00
parent a8f4f40d08
commit c981a597dc
42 changed files with 779 additions and 40 deletions

View File

@@ -26,6 +26,7 @@
#include "../SDL_hints_c.h"
#include "SDL_gamepad_c.h"
#include "SDL_joystick_c.h"
#include "SDL_steam_virtual_gamepad.h"
#ifndef SDL_EVENTS_DISABLED
#include "../events/SDL_events_c.h"
@@ -624,6 +625,8 @@ int SDL_InitJoysticks(void)
SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
SDL_JoystickAllowBackgroundEventsChanged, NULL);
SDL_InitSteamVirtualGamepadInfo();
status = -1;
for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
if (SDL_joystick_drivers[i]->Init() >= 0) {
@@ -696,6 +699,19 @@ SDL_JoystickID *SDL_GetJoysticks(int *count)
return joysticks;
}
const SDL_SteamVirtualGamepadInfo *SDL_GetJoystickInstanceVirtualGamepadInfo(SDL_JoystickID instance_id)
{
SDL_JoystickDriver *driver;
int device_index;
const SDL_SteamVirtualGamepadInfo *info = NULL;
if (SDL_SteamVirtualGamepadEnabled() &&
SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
info = SDL_GetSteamVirtualGamepadInfo(driver->GetDeviceSteamVirtualGamepadSlot(device_index));
}
return info;
}
/*
* Get the implementation dependent name of a joystick
*/
@@ -704,9 +720,13 @@ const char *SDL_GetJoystickInstanceName(SDL_JoystickID instance_id)
SDL_JoystickDriver *driver;
int device_index;
const char *name = NULL;
const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
if (info) {
name = info->name;
} else if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
name = driver->GetDeviceName(device_index);
}
SDL_UnlockJoysticks();
@@ -993,6 +1013,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
const char *joystickpath = NULL;
SDL_JoystickPowerLevel initial_power_level;
SDL_bool invert_sensors = SDL_FALSE;
const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
@@ -1076,6 +1097,12 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
joystick->is_gamepad = SDL_IsGamepad(instance_id);
/* Get the Steam Input API handle */
info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
if (info) {
joystick->steam_handle = info->handle;
}
/* Use system gyro and accelerometer if the gamepad doesn't have built-in sensors */
if (ShouldAttemptSensorFusion(joystick, &invert_sensors)) {
AttemptSensorFusion(joystick, invert_sensors);
@@ -1491,15 +1518,20 @@ SDL_PropertiesID SDL_GetJoystickProperties(SDL_Joystick *joystick)
const char *SDL_GetJoystickName(SDL_Joystick *joystick)
{
const char *retval;
const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
{
info = SDL_GetJoystickInstanceVirtualGamepadInfo(joystick->instance_id);
if (info) {
retval = info->name;
} else {
CHECK_JOYSTICK_MAGIC(joystick, NULL);
retval = joystick->name;
}
SDL_UnlockJoysticks();
/* FIXME: Really we should reference count this name so it doesn't go away after unlock */
return retval;
}
@@ -1823,6 +1855,8 @@ void SDL_QuitJoysticks(void)
SDL_QuitSubSystem(SDL_INIT_EVENTS);
#endif
SDL_QuitSteamVirtualGamepadInfo();
SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
SDL_JoystickAllowBackgroundEventsChanged, NULL);
@@ -1921,7 +1955,10 @@ void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id)
SDL_joystick_being_added = SDL_TRUE;
if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
player_index = driver->GetDevicePlayerIndex(device_index);
player_index = driver->GetDeviceSteamVirtualGamepadSlot(device_index);
if (player_index < 0) {
player_index = driver->GetDevicePlayerIndex(device_index);
}
}
if (player_index < 0 && SDL_IsGamepad(instance_id)) {
player_index = SDL_FindFreePlayerIndex();
@@ -2200,6 +2237,43 @@ int SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 butto
return posted;
}
static void SendSteamHandleUpdateEvents(void)
{
SDL_Joystick *joystick;
const SDL_SteamVirtualGamepadInfo *info;
/* Check to see if any Steam handles changed */
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
SDL_bool changed = SDL_FALSE;
if (!joystick->is_gamepad) {
continue;
}
info = SDL_GetJoystickInstanceVirtualGamepadInfo(joystick->instance_id);
if (info) {
if (joystick->steam_handle != info->handle) {
joystick->steam_handle = info->handle;
changed = SDL_TRUE;
}
} else {
if (joystick->steam_handle != 0) {
joystick->steam_handle = 0;
changed = SDL_TRUE;
}
}
if (changed) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED;
event.common.timestamp = 0;
event.gdevice.which = joystick->instance_id;
SDL_PushEvent(&event);
}
}
}
void SDL_UpdateJoysticks(void)
{
int i;
@@ -2212,6 +2286,10 @@ void SDL_UpdateJoysticks(void)
SDL_LockJoysticks();
if (SDL_UpdateSteamVirtualGamepadInfo()) {
SendSteamHandleUpdateEvents();
}
#ifdef SDL_JOYSTICK_HIDAPI
/* Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks */
HIDAPI_UpdateDevices();
@@ -3083,18 +3161,38 @@ SDL_JoystickGUID SDL_GetJoystickInstanceGUID(SDL_JoystickID instance_id)
Uint16 SDL_GetJoystickInstanceVendor(SDL_JoystickID instance_id)
{
Uint16 vendor;
SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
if (info) {
vendor = info->vendor_id;
} else {
SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL);
}
SDL_UnlockJoysticks();
SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL);
return vendor;
}
Uint16 SDL_GetJoystickInstanceProduct(SDL_JoystickID instance_id)
{
Uint16 product;
SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
if (info) {
product = info->product_id;
} else {
SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL);
}
SDL_UnlockJoysticks();
SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL);
return product;
}
@@ -3141,18 +3239,38 @@ SDL_JoystickGUID SDL_GetJoystickGUID(SDL_Joystick *joystick)
Uint16 SDL_GetJoystickVendor(SDL_Joystick *joystick)
{
Uint16 vendor;
SDL_JoystickGUID guid = SDL_GetJoystickGUID(joystick);
const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
info = SDL_GetJoystickInstanceVirtualGamepadInfo(joystick->instance_id);
if (info) {
vendor = info->vendor_id;
} else {
SDL_JoystickGUID guid = SDL_GetJoystickGUID(joystick);
SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL);
}
SDL_UnlockJoysticks();
SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL);
return vendor;
}
Uint16 SDL_GetJoystickProduct(SDL_Joystick *joystick)
{
Uint16 product;
SDL_JoystickGUID guid = SDL_GetJoystickGUID(joystick);
const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
info = SDL_GetJoystickInstanceVirtualGamepadInfo(joystick->instance_id);
if (info) {
product = info->product_id;
} else {
SDL_JoystickGUID guid = SDL_GetJoystickGUID(joystick);
SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL);
}
SDL_UnlockJoysticks();
SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL);
return product;
}