summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/joystick/emscripten
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/joystick/emscripten')
-rw-r--r--contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick.c445
-rw-r--r--contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick_c.h49
2 files changed, 494 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick.c b/contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick.c
new file mode 100644
index 0000000..b481d5d
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick.c
@@ -0,0 +1,445 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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
22#include "SDL_internal.h"
23
24#ifdef SDL_JOYSTICK_EMSCRIPTEN
25
26#include <stdio.h> // For the definition of NULL
27
28#include "SDL_sysjoystick_c.h"
29#include "../SDL_joystick_c.h"
30
31static SDL_joylist_item *JoystickByIndex(int index);
32
33static SDL_joylist_item *SDL_joylist = NULL;
34static SDL_joylist_item *SDL_joylist_tail = NULL;
35static int numjoysticks = 0;
36
37static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
38{
39 SDL_joylist_item *item;
40 int i;
41
42 SDL_LockJoysticks();
43
44 if (JoystickByIndex(gamepadEvent->index) != NULL) {
45 goto done;
46 }
47
48 item = (SDL_joylist_item *)SDL_malloc(sizeof(SDL_joylist_item));
49 if (!item) {
50 goto done;
51 }
52
53 SDL_zerop(item);
54 item->index = gamepadEvent->index;
55
56 item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id);
57 if (!item->name) {
58 SDL_free(item);
59 goto done;
60 }
61
62 item->mapping = SDL_strdup(gamepadEvent->mapping);
63 if (!item->mapping) {
64 SDL_free(item->name);
65 SDL_free(item);
66 goto done;
67 }
68
69 item->naxes = gamepadEvent->numAxes;
70 item->nbuttons = gamepadEvent->numButtons;
71 item->device_instance = SDL_GetNextObjectID();
72
73 item->timestamp = gamepadEvent->timestamp;
74
75 for (i = 0; i < item->naxes; i++) {
76 item->axis[i] = gamepadEvent->axis[i];
77 }
78
79 for (i = 0; i < item->nbuttons; i++) {
80 item->analogButton[i] = gamepadEvent->analogButton[i];
81 item->digitalButton[i] = gamepadEvent->digitalButton[i];
82 }
83
84 if (!SDL_joylist_tail) {
85 SDL_joylist = SDL_joylist_tail = item;
86 } else {
87 SDL_joylist_tail->next = item;
88 SDL_joylist_tail = item;
89 }
90
91 ++numjoysticks;
92
93 SDL_PrivateJoystickAdded(item->device_instance);
94
95#ifdef DEBUG_JOYSTICK
96 SDL_Log("Number of joysticks is %d", numjoysticks);
97#endif
98#ifdef DEBUG_JOYSTICK
99 SDL_Log("Added joystick with index %d", item->index);
100#endif
101
102done:
103 SDL_UnlockJoysticks();
104
105 return 1;
106}
107
108static EM_BOOL Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
109{
110 SDL_joylist_item *item = SDL_joylist;
111 SDL_joylist_item *prev = NULL;
112
113 SDL_LockJoysticks();
114
115 while (item) {
116 if (item->index == gamepadEvent->index) {
117 break;
118 }
119 prev = item;
120 item = item->next;
121 }
122
123 if (!item) {
124 goto done;
125 }
126
127 if (item->joystick) {
128 item->joystick->hwdata = NULL;
129 }
130
131 if (prev) {
132 prev->next = item->next;
133 } else {
134 SDL_assert(SDL_joylist == item);
135 SDL_joylist = item->next;
136 }
137 if (item == SDL_joylist_tail) {
138 SDL_joylist_tail = prev;
139 }
140
141 // Need to decrement the joystick count before we post the event
142 --numjoysticks;
143
144 SDL_PrivateJoystickRemoved(item->device_instance);
145
146#ifdef DEBUG_JOYSTICK
147 SDL_Log("Removed joystick with id %d", item->device_instance);
148#endif
149 SDL_free(item->name);
150 SDL_free(item->mapping);
151 SDL_free(item);
152
153done:
154 SDL_UnlockJoysticks();
155
156 return 1;
157}
158
159// Function to perform any system-specific joystick related cleanup
160static void EMSCRIPTEN_JoystickQuit(void)
161{
162 SDL_joylist_item *item = NULL;
163 SDL_joylist_item *next = NULL;
164
165 for (item = SDL_joylist; item; item = next) {
166 next = item->next;
167 SDL_free(item->mapping);
168 SDL_free(item->name);
169 SDL_free(item);
170 }
171
172 SDL_joylist = SDL_joylist_tail = NULL;
173
174 numjoysticks = 0;
175
176 emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
177 emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
178}
179
180// Function to scan the system for joysticks.
181static bool EMSCRIPTEN_JoystickInit(void)
182{
183 int rc, i, numjs;
184 EmscriptenGamepadEvent gamepadState;
185
186 numjoysticks = 0;
187
188 rc = emscripten_sample_gamepad_data();
189
190 // Check if gamepad is supported by browser
191 if (rc == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
192 return SDL_SetError("Gamepads not supported");
193 }
194
195 numjs = emscripten_get_num_gamepads();
196
197 // handle already connected gamepads
198 if (numjs > 0) {
199 for (i = 0; i < numjs; i++) {
200 rc = emscripten_get_gamepad_status(i, &gamepadState);
201 if (rc == EMSCRIPTEN_RESULT_SUCCESS) {
202 Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
203 &gamepadState,
204 NULL);
205 }
206 }
207 }
208
209 rc = emscripten_set_gamepadconnected_callback(NULL,
210 0,
211 Emscripten_JoyStickConnected);
212
213 if (rc != EMSCRIPTEN_RESULT_SUCCESS) {
214 EMSCRIPTEN_JoystickQuit();
215 return SDL_SetError("Could not set gamepad connect callback");
216 }
217
218 rc = emscripten_set_gamepaddisconnected_callback(NULL,
219 0,
220 Emscripten_JoyStickDisconnected);
221 if (rc != EMSCRIPTEN_RESULT_SUCCESS) {
222 EMSCRIPTEN_JoystickQuit();
223 return SDL_SetError("Could not set gamepad disconnect callback");
224 }
225
226 return true;
227}
228
229// Returns item matching given SDL device index.
230static SDL_joylist_item *JoystickByDeviceIndex(int device_index)
231{
232 SDL_joylist_item *item = SDL_joylist;
233
234 while (0 < device_index) {
235 --device_index;
236 item = item->next;
237 }
238
239 return item;
240}
241
242// Returns item matching given HTML gamepad index.
243static SDL_joylist_item *JoystickByIndex(int index)
244{
245 SDL_joylist_item *item = SDL_joylist;
246
247 if (index < 0) {
248 return NULL;
249 }
250
251 while (item) {
252 if (item->index == index) {
253 break;
254 }
255 item = item->next;
256 }
257
258 return item;
259}
260
261static int EMSCRIPTEN_JoystickGetCount(void)
262{
263 return numjoysticks;
264}
265
266static void EMSCRIPTEN_JoystickDetect(void)
267{
268}
269
270static bool EMSCRIPTEN_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
271{
272 // We don't override any other drivers
273 return false;
274}
275
276static const char *EMSCRIPTEN_JoystickGetDeviceName(int device_index)
277{
278 return JoystickByDeviceIndex(device_index)->name;
279}
280
281static const char *EMSCRIPTEN_JoystickGetDevicePath(int device_index)
282{
283 return NULL;
284}
285
286static int EMSCRIPTEN_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
287{
288 return -1;
289}
290
291static int EMSCRIPTEN_JoystickGetDevicePlayerIndex(int device_index)
292{
293 return -1;
294}
295
296static void EMSCRIPTEN_JoystickSetDevicePlayerIndex(int device_index, int player_index)
297{
298}
299
300static SDL_JoystickID EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index)
301{
302 return JoystickByDeviceIndex(device_index)->device_instance;
303}
304
305static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
306{
307 SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
308
309 if (!item) {
310 return SDL_SetError("No such device");
311 }
312
313 if (item->joystick) {
314 return SDL_SetError("Joystick already opened");
315 }
316
317 joystick->hwdata = (struct joystick_hwdata *)item;
318 item->joystick = joystick;
319
320 // HTML5 Gamepad API doesn't say anything about these
321 joystick->nhats = 0;
322
323 joystick->nbuttons = item->nbuttons;
324 joystick->naxes = item->naxes;
325
326 return true;
327}
328
329/* Function to update the state of a joystick - called as a device poll.
330 * This function shouldn't update the joystick structure directly,
331 * but instead should call SDL_PrivateJoystick*() to deliver events
332 * and update joystick device state.
333 */
334static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
335{
336 EmscriptenGamepadEvent gamepadState;
337 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
338 int i, result;
339 Uint64 timestamp = SDL_GetTicksNS();
340
341 emscripten_sample_gamepad_data();
342
343 if (item) {
344 result = emscripten_get_gamepad_status(item->index, &gamepadState);
345 if (result == EMSCRIPTEN_RESULT_SUCCESS) {
346 if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
347 for (i = 0; i < item->nbuttons; i++) {
348 if (item->digitalButton[i] != gamepadState.digitalButton[i]) {
349 bool down = (gamepadState.digitalButton[i] != 0);
350 SDL_SendJoystickButton(timestamp, item->joystick, i, down);
351 }
352
353 // store values to compare them in the next update
354 item->analogButton[i] = gamepadState.analogButton[i];
355 item->digitalButton[i] = gamepadState.digitalButton[i];
356 }
357
358 for (i = 0; i < item->naxes; i++) {
359 if (item->axis[i] != gamepadState.axis[i]) {
360 // do we need to do conversion?
361 SDL_SendJoystickAxis(timestamp, item->joystick, i,
362 (Sint16)(32767. * gamepadState.axis[i]));
363 }
364
365 // store to compare in next update
366 item->axis[i] = gamepadState.axis[i];
367 }
368
369 item->timestamp = gamepadState.timestamp;
370 }
371 }
372 }
373}
374
375// Function to close a joystick after use
376static void EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick)
377{
378 SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
379 if (item) {
380 item->joystick = NULL;
381 }
382}
383
384static SDL_GUID EMSCRIPTEN_JoystickGetDeviceGUID(int device_index)
385{
386 // the GUID is just the name for now
387 const char *name = EMSCRIPTEN_JoystickGetDeviceName(device_index);
388 return SDL_CreateJoystickGUIDForName(name);
389}
390
391static bool EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
392{
393 return SDL_Unsupported();
394}
395
396static bool EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
397{
398 return SDL_Unsupported();
399}
400
401static bool EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
402{
403 return false;
404}
405
406static bool EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
407{
408 return SDL_Unsupported();
409}
410
411static bool EMSCRIPTEN_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
412{
413 return SDL_Unsupported();
414}
415
416static bool EMSCRIPTEN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled)
417{
418 return SDL_Unsupported();
419}
420
421SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver = {
422 EMSCRIPTEN_JoystickInit,
423 EMSCRIPTEN_JoystickGetCount,
424 EMSCRIPTEN_JoystickDetect,
425 EMSCRIPTEN_JoystickIsDevicePresent,
426 EMSCRIPTEN_JoystickGetDeviceName,
427 EMSCRIPTEN_JoystickGetDevicePath,
428 EMSCRIPTEN_JoystickGetDeviceSteamVirtualGamepadSlot,
429 EMSCRIPTEN_JoystickGetDevicePlayerIndex,
430 EMSCRIPTEN_JoystickSetDevicePlayerIndex,
431 EMSCRIPTEN_JoystickGetDeviceGUID,
432 EMSCRIPTEN_JoystickGetDeviceInstanceID,
433 EMSCRIPTEN_JoystickOpen,
434 EMSCRIPTEN_JoystickRumble,
435 EMSCRIPTEN_JoystickRumbleTriggers,
436 EMSCRIPTEN_JoystickSetLED,
437 EMSCRIPTEN_JoystickSendEffect,
438 EMSCRIPTEN_JoystickSetSensorsEnabled,
439 EMSCRIPTEN_JoystickUpdate,
440 EMSCRIPTEN_JoystickClose,
441 EMSCRIPTEN_JoystickQuit,
442 EMSCRIPTEN_JoystickGetGamepadMapping
443};
444
445#endif // SDL_JOYSTICK_EMSCRIPTEN
diff --git a/contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick_c.h b/contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick_c.h
new file mode 100644
index 0000000..e03a27c
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/joystick/emscripten/SDL_sysjoystick_c.h
@@ -0,0 +1,49 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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
22#include "SDL_internal.h"
23
24#ifdef SDL_JOYSTICK_EMSCRIPTEN
25#include "../SDL_sysjoystick.h"
26
27#include <emscripten/html5.h>
28
29// A linked list of available joysticks
30typedef struct SDL_joylist_item
31{
32 int index;
33 char *name;
34 char *mapping;
35 SDL_JoystickID device_instance;
36 SDL_Joystick *joystick;
37 int nbuttons;
38 int naxes;
39 double timestamp;
40 double axis[64];
41 double analogButton[64];
42 EM_BOOL digitalButton[64];
43
44 struct SDL_joylist_item *next;
45} SDL_joylist_item;
46
47typedef SDL_joylist_item joystick_hwdata;
48
49#endif // SDL_JOYSTICK_EMSCRIPTEN