Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/joystick/SDL_steam_virtual_gamepad.c
9902 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 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_WIN32
27
#include "../core/windows/SDL_windows.h"
28
#else
29
#include <sys/types.h>
30
#include <sys/stat.h>
31
#endif
32
33
#define SDL_HINT_STEAM_VIRTUAL_GAMEPAD_INFO_FILE "SteamVirtualGamepadInfo"
34
35
static char *SDL_steam_virtual_gamepad_info_file SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
36
static Uint64 SDL_steam_virtual_gamepad_info_file_mtime SDL_GUARDED_BY(SDL_joystick_lock) = 0;
37
static Uint64 SDL_steam_virtual_gamepad_info_check_time SDL_GUARDED_BY(SDL_joystick_lock) = 0;
38
static SDL_SteamVirtualGamepadInfo **SDL_steam_virtual_gamepad_info SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
39
static int SDL_steam_virtual_gamepad_info_count SDL_GUARDED_BY(SDL_joystick_lock) = 0;
40
41
42
static Uint64 GetFileModificationTime(const char *file)
43
{
44
Uint64 modification_time = 0;
45
46
#ifdef SDL_PLATFORM_WIN32
47
WCHAR *wFile = WIN_UTF8ToStringW(file);
48
if (wFile) {
49
HANDLE hFile = CreateFileW(wFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
50
if (hFile != INVALID_HANDLE_VALUE) {
51
FILETIME last_write_time;
52
if (GetFileTime(hFile, NULL, NULL, &last_write_time)) {
53
modification_time = last_write_time.dwHighDateTime;
54
modification_time <<= 32;
55
modification_time |= last_write_time.dwLowDateTime;
56
}
57
CloseHandle(hFile);
58
}
59
SDL_free(wFile);
60
}
61
#else
62
struct stat sb;
63
64
if (stat(file, &sb) == 0) {
65
modification_time = (Uint64)sb.st_mtime;
66
}
67
#endif
68
return modification_time;
69
}
70
71
static void SDL_FreeSteamVirtualGamepadInfo(void)
72
{
73
int i;
74
75
SDL_AssertJoysticksLocked();
76
77
for (i = 0; i < SDL_steam_virtual_gamepad_info_count; ++i) {
78
SDL_SteamVirtualGamepadInfo *entry = SDL_steam_virtual_gamepad_info[i];
79
if (entry) {
80
SDL_free(entry->name);
81
SDL_free(entry);
82
}
83
}
84
SDL_free(SDL_steam_virtual_gamepad_info);
85
SDL_steam_virtual_gamepad_info = NULL;
86
SDL_steam_virtual_gamepad_info_count = 0;
87
}
88
89
static void AddVirtualGamepadInfo(int slot, SDL_SteamVirtualGamepadInfo *info)
90
{
91
SDL_SteamVirtualGamepadInfo *new_info;
92
93
SDL_AssertJoysticksLocked();
94
95
if (slot < 0) {
96
return;
97
}
98
99
if (slot >= SDL_steam_virtual_gamepad_info_count) {
100
SDL_SteamVirtualGamepadInfo **slots = (SDL_SteamVirtualGamepadInfo **)SDL_realloc(SDL_steam_virtual_gamepad_info, (slot + 1)*sizeof(*SDL_steam_virtual_gamepad_info));
101
if (!slots) {
102
return;
103
}
104
while (SDL_steam_virtual_gamepad_info_count <= slot) {
105
slots[SDL_steam_virtual_gamepad_info_count++] = NULL;
106
}
107
SDL_steam_virtual_gamepad_info = slots;
108
}
109
110
if (SDL_steam_virtual_gamepad_info[slot]) {
111
// We already have this slot info
112
return;
113
}
114
115
new_info = (SDL_SteamVirtualGamepadInfo *)SDL_malloc(sizeof(*new_info));
116
if (!new_info) {
117
return;
118
}
119
SDL_copyp(new_info, info);
120
SDL_steam_virtual_gamepad_info[slot] = new_info;
121
SDL_zerop(info);
122
}
123
124
void SDL_InitSteamVirtualGamepadInfo(void)
125
{
126
const char *file;
127
128
SDL_AssertJoysticksLocked();
129
130
// The file isn't available inside the macOS sandbox
131
if (SDL_GetSandbox() == SDL_SANDBOX_MACOS) {
132
return;
133
}
134
135
file = SDL_GetHint(SDL_HINT_STEAM_VIRTUAL_GAMEPAD_INFO_FILE);
136
if (file && *file) {
137
SDL_steam_virtual_gamepad_info_file = SDL_strdup(file);
138
}
139
SDL_UpdateSteamVirtualGamepadInfo();
140
}
141
142
bool SDL_SteamVirtualGamepadEnabled(void)
143
{
144
SDL_AssertJoysticksLocked();
145
146
return (SDL_steam_virtual_gamepad_info != NULL);
147
}
148
149
bool SDL_UpdateSteamVirtualGamepadInfo(void)
150
{
151
const int UPDATE_CHECK_INTERVAL_MS = 3000;
152
Uint64 now;
153
Uint64 mtime;
154
char *data, *end, *next, *line, *value;
155
size_t size;
156
int slot, new_slot;
157
SDL_SteamVirtualGamepadInfo info;
158
159
SDL_AssertJoysticksLocked();
160
161
if (!SDL_steam_virtual_gamepad_info_file) {
162
return false;
163
}
164
165
now = SDL_GetTicks();
166
if (SDL_steam_virtual_gamepad_info_check_time &&
167
now < (SDL_steam_virtual_gamepad_info_check_time + UPDATE_CHECK_INTERVAL_MS)) {
168
return false;
169
}
170
SDL_steam_virtual_gamepad_info_check_time = now;
171
172
mtime = GetFileModificationTime(SDL_steam_virtual_gamepad_info_file);
173
if (mtime == 0 || mtime == SDL_steam_virtual_gamepad_info_file_mtime) {
174
return false;
175
}
176
177
data = (char *)SDL_LoadFile(SDL_steam_virtual_gamepad_info_file, &size);
178
if (!data) {
179
return false;
180
}
181
182
SDL_FreeSteamVirtualGamepadInfo();
183
184
slot = -1;
185
SDL_zero(info);
186
187
for (next = data, end = data + size; next < end; ) {
188
while (next < end && (*next == '\0' || *next == '\r' || *next == '\n')) {
189
++next;
190
}
191
192
line = next;
193
194
while (next < end && (*next != '\r' && *next != '\n')) {
195
++next;
196
}
197
*next = '\0';
198
199
if (SDL_sscanf(line, "[slot %d]", &new_slot) == 1) {
200
if (slot >= 0) {
201
AddVirtualGamepadInfo(slot, &info);
202
}
203
slot = new_slot;
204
} else {
205
value = SDL_strchr(line, '=');
206
if (value) {
207
*value++ = '\0';
208
209
if (SDL_strcmp(line, "name") == 0) {
210
SDL_free(info.name);
211
info.name = SDL_strdup(value);
212
} else if (SDL_strcmp(line, "VID") == 0) {
213
info.vendor_id = (Uint16)SDL_strtoul(value, NULL, 0);
214
} else if (SDL_strcmp(line, "PID") == 0) {
215
info.product_id = (Uint16)SDL_strtoul(value, NULL, 0);
216
} else if (SDL_strcmp(line, "type") == 0) {
217
info.type = SDL_GetGamepadTypeFromString(value);
218
} else if (SDL_strcmp(line, "handle") == 0) {
219
info.handle = (Uint64)SDL_strtoull(value, NULL, 0);
220
}
221
}
222
}
223
}
224
if (slot >= 0) {
225
AddVirtualGamepadInfo(slot, &info);
226
}
227
SDL_free(info.name);
228
SDL_free(data);
229
230
SDL_steam_virtual_gamepad_info_file_mtime = mtime;
231
232
return true;
233
}
234
235
const SDL_SteamVirtualGamepadInfo *SDL_GetSteamVirtualGamepadInfo(int slot)
236
{
237
SDL_AssertJoysticksLocked();
238
239
if (slot < 0 || slot >= SDL_steam_virtual_gamepad_info_count) {
240
return NULL;
241
}
242
return SDL_steam_virtual_gamepad_info[slot];
243
}
244
245
void SDL_QuitSteamVirtualGamepadInfo(void)
246
{
247
SDL_AssertJoysticksLocked();
248
249
if (SDL_steam_virtual_gamepad_info_file) {
250
SDL_FreeSteamVirtualGamepadInfo();
251
SDL_free(SDL_steam_virtual_gamepad_info_file);
252
SDL_steam_virtual_gamepad_info_file = NULL;
253
}
254
}
255
256