Atlas - SDL_steam_virtual_gamepad.c

Home / ext / SDL / src / joystick Lines: 3 | Size: 8124 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#include "SDL_joystick_c.h" 24#include "SDL_steam_virtual_gamepad.h" 25 26#ifdef SDL_PLATFORM_LINUX 27#include "../core/unix/SDL_appid.h" 28#endif 29#ifdef SDL_PLATFORM_WIN32 30#include "../core/windows/SDL_windows.h" 31#else 32#include <sys/types.h> 33#include <sys/stat.h> 34#endif 35 36static char *SDL_steam_virtual_gamepad_info_file SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 37static Uint64 SDL_steam_virtual_gamepad_info_file_mtime SDL_GUARDED_BY(SDL_joystick_lock) = 0; 38static Uint64 SDL_steam_virtual_gamepad_info_check_time SDL_GUARDED_BY(SDL_joystick_lock) = 0; 39static SDL_SteamVirtualGamepadInfo **SDL_steam_virtual_gamepad_info SDL_GUARDED_BY(SDL_joystick_lock) = NULL; 40static int SDL_steam_virtual_gamepad_info_count SDL_GUARDED_BY(SDL_joystick_lock) = 0; 41 42 43static Uint64 GetFileModificationTime(const char *file) 44{ 45 Uint64 modification_time = 0; 46 47#ifdef SDL_PLATFORM_WIN32 48 WCHAR *wFile = WIN_UTF8ToStringW(file); 49 if (wFile) { 50 HANDLE hFile = CreateFileW(wFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 51 if (hFile != INVALID_HANDLE_VALUE) { 52 FILETIME last_write_time; 53 if (GetFileTime(hFile, NULL, NULL, &last_write_time)) { 54 modification_time = last_write_time.dwHighDateTime; 55 modification_time <<= 32; 56 modification_time |= last_write_time.dwLowDateTime; 57 } 58 CloseHandle(hFile); 59 } 60 SDL_free(wFile); 61 } 62#else 63 struct stat sb; 64 65 if (stat(file, &sb) == 0) { 66 modification_time = (Uint64)sb.st_mtime; 67 } 68#endif 69 return modification_time; 70} 71 72static void SDL_FreeSteamVirtualGamepadInfo(void) 73{ 74 int i; 75 76 SDL_AssertJoysticksLocked(); 77 78 for (i = 0; i < SDL_steam_virtual_gamepad_info_count; ++i) { 79 SDL_SteamVirtualGamepadInfo *entry = SDL_steam_virtual_gamepad_info[i]; 80 if (entry) { 81 SDL_free(entry->name); 82 SDL_free(entry); 83 } 84 } 85 SDL_free(SDL_steam_virtual_gamepad_info); 86 SDL_steam_virtual_gamepad_info = NULL; 87 SDL_steam_virtual_gamepad_info_count = 0; 88} 89 90static void AddVirtualGamepadInfo(int slot, SDL_SteamVirtualGamepadInfo *info) 91{ 92 SDL_SteamVirtualGamepadInfo *new_info; 93 94 SDL_AssertJoysticksLocked(); 95 96 if (slot < 0) { 97 return; 98 } 99 100 if (slot >= SDL_steam_virtual_gamepad_info_count) { 101 SDL_SteamVirtualGamepadInfo **slots = (SDL_SteamVirtualGamepadInfo **)SDL_realloc(SDL_steam_virtual_gamepad_info, (slot + 1)*sizeof(*SDL_steam_virtual_gamepad_info)); 102 if (!slots) { 103 return; 104 } 105 while (SDL_steam_virtual_gamepad_info_count <= slot) { 106 slots[SDL_steam_virtual_gamepad_info_count++] = NULL; 107 } 108 SDL_steam_virtual_gamepad_info = slots; 109 } 110 111 if (SDL_steam_virtual_gamepad_info[slot]) { 112 // We already have this slot info 113 return; 114 } 115 116 new_info = (SDL_SteamVirtualGamepadInfo *)SDL_malloc(sizeof(*new_info)); 117 if (!new_info) { 118 return; 119 } 120 SDL_copyp(new_info, info); 121 SDL_steam_virtual_gamepad_info[slot] = new_info; 122 SDL_zerop(info); 123} 124 125void SDL_InitSteamVirtualGamepadInfo(void) 126{ 127 const char *file; 128 129 SDL_AssertJoysticksLocked(); 130 131 // The file isn't available inside the macOS sandbox 132 if (SDL_GetSandbox() == SDL_SANDBOX_MACOS) { 133 return; 134 } 135 136 file = SDL_getenv_unsafe("SteamVirtualGamepadInfo"); 137 if (file && *file) { 138#ifdef SDL_PLATFORM_LINUX 139 // Older versions of Wine will blacklist the Steam Virtual Gamepad if 140 // it appears to have the real controller's VID/PID, so ignore this. 141 const char *exe = SDL_GetExeName(); 142 if (exe && SDL_strcmp(exe, "wine64-preloader") == 0) { 143 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Wine launched by Steam, ignoring SteamVirtualGamepadInfo"); 144 return; 145 } 146#endif 147 SDL_steam_virtual_gamepad_info_file = SDL_strdup(file); 148 } 149 SDL_UpdateSteamVirtualGamepadInfo(); 150} 151 152bool SDL_SteamVirtualGamepadEnabled(void) 153{ 154 SDL_AssertJoysticksLocked(); 155 156 return (SDL_steam_virtual_gamepad_info != NULL); 157} 158 159bool SDL_UpdateSteamVirtualGamepadInfo(void) 160{ 161 const int UPDATE_CHECK_INTERVAL_MS = 3000; 162 Uint64 now; 163 Uint64 mtime; 164 char *data, *end, *next, *line, *value; 165 size_t size; 166 int slot, new_slot; 167 SDL_SteamVirtualGamepadInfo info; 168 169 SDL_AssertJoysticksLocked(); 170 171 if (!SDL_steam_virtual_gamepad_info_file) { 172 return false; 173 } 174 175 now = SDL_GetTicks(); 176 if (SDL_steam_virtual_gamepad_info_check_time && 177 now < (SDL_steam_virtual_gamepad_info_check_time + UPDATE_CHECK_INTERVAL_MS)) { 178 return false; 179 } 180 SDL_steam_virtual_gamepad_info_check_time = now; 181 182 mtime = GetFileModificationTime(SDL_steam_virtual_gamepad_info_file); 183 if (mtime == 0 || mtime == SDL_steam_virtual_gamepad_info_file_mtime) { 184 return false; 185 } 186 187 data = (char *)SDL_LoadFile(SDL_steam_virtual_gamepad_info_file, &size); 188 if (!data) { 189 return false; 190 } 191 192 SDL_FreeSteamVirtualGamepadInfo(); 193 194 slot = -1; 195 SDL_zero(info); 196 197 for (next = data, end = data + size; next < end; ) { 198 while (next < end && (*next == '\0' || *next == '\r' || *next == '\n')) { 199 ++next; 200 } 201 202 line = next; 203 204 while (next < end && (*next != '\r' && *next != '\n')) { 205 ++next; 206 } 207 *next = '\0'; 208 209 if (SDL_sscanf(line, "[slot %d]", &new_slot) == 1) { 210 if (slot >= 0) { 211 AddVirtualGamepadInfo(slot, &info); 212 } 213 slot = new_slot; 214 } else { 215 value = SDL_strchr(line, '='); 216 if (value) { 217 *value++ = '\0'; 218 219 if (SDL_strcmp(line, "name") == 0) { 220 SDL_free(info.name); 221 info.name = SDL_strdup(value); 222 } else if (SDL_strcmp(line, "VID") == 0) { 223 info.vendor_id = (Uint16)SDL_strtoul(value, NULL, 0); 224 } else if (SDL_strcmp(line, "PID") == 0) { 225 info.product_id = (Uint16)SDL_strtoul(value, NULL, 0); 226 } else if (SDL_strcmp(line, "type") == 0) { 227 info.type = SDL_GetGamepadTypeFromString(value); 228 } else if (SDL_strcmp(line, "handle") == 0) { 229 info.handle = (Uint64)SDL_strtoull(value, NULL, 0); 230 } 231 } 232 } 233 } 234 if (slot >= 0) { 235 AddVirtualGamepadInfo(slot, &info); 236 } 237 SDL_free(info.name); 238 SDL_free(data); 239 240 SDL_steam_virtual_gamepad_info_file_mtime = mtime; 241 242 return true; 243} 244 245const SDL_SteamVirtualGamepadInfo *SDL_GetSteamVirtualGamepadInfo(int slot) 246{ 247 SDL_AssertJoysticksLocked(); 248 249 if (slot < 0 || slot >= SDL_steam_virtual_gamepad_info_count) { 250 return NULL; 251 } 252 return SDL_steam_virtual_gamepad_info[slot]; 253} 254 255void SDL_QuitSteamVirtualGamepadInfo(void) 256{ 257 SDL_AssertJoysticksLocked(); 258 259 if (SDL_steam_virtual_gamepad_info_file) { 260 SDL_FreeSteamVirtualGamepadInfo(); 261 SDL_free(SDL_steam_virtual_gamepad_info_file); 262 SDL_steam_virtual_gamepad_info_file = NULL; 263 } 264} 265
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.