SDL 2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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#include "SDL_error.h"
28#include "SDL_events.h"
29
30#include "SDL_joystick.h"
31#include "SDL_assert.h"
32#include "SDL_timer.h"
33#include "SDL_log.h"
34#include "SDL_sysjoystick_c.h"
35#include "../SDL_joystick_c.h"
36
37static SDL_joylist_item * JoystickByIndex(int index);
38
39static SDL_joylist_item *SDL_joylist = NULL;
40static SDL_joylist_item *SDL_joylist_tail = NULL;
41static int numjoysticks = 0;
42static int instance_counter = 0;
43
44static EM_BOOL
45Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
46{
47 int i;
48
49 SDL_joylist_item *item;
50
51 if (JoystickByIndex(gamepadEvent->index) != NULL) {
52 return 1;
53 }
54
55 item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
56 if (item == NULL) {
57 return 1;
58 }
59
60 SDL_zerop(item);
61 item->index = gamepadEvent->index;
62
63 item->name = SDL_strdup(gamepadEvent->id);
64 if ( item->name == NULL ) {
65 SDL_free(item);
66 return 1;
67 }
68
69 item->mapping = SDL_strdup(gamepadEvent->mapping);
70 if ( item->mapping == NULL ) {
71 SDL_free(item->name);
72 SDL_free(item);
73 return 1;
74 }
75
76 item->naxes = gamepadEvent->numAxes;
77 item->nbuttons = gamepadEvent->numButtons;
78 item->device_instance = instance_counter++;
79
80 item->timestamp = gamepadEvent->timestamp;
81
82 for( i = 0; i < item->naxes; i++) {
83 item->axis[i] = gamepadEvent->axis[i];
84 }
85
86 for( i = 0; i < item->nbuttons; i++) {
87 item->analogButton[i] = gamepadEvent->analogButton[i];
88 item->digitalButton[i] = gamepadEvent->digitalButton[i];
89 }
90
91 if (SDL_joylist_tail == NULL) {
92 SDL_joylist = SDL_joylist_tail = item;
93 } else {
94 SDL_joylist_tail->next = item;
95 SDL_joylist_tail = item;
96 }
97
99
100 SDL_PrivateJoystickAdded(item->device_instance);
101
102#ifdef DEBUG_JOYSTICK
103 SDL_Log("Number of joysticks is %d", numjoysticks);
104#endif
105
106#ifdef DEBUG_JOYSTICK
107 SDL_Log("Added joystick with index %d", item->index);
108#endif
109
110 return 1;
111}
112
113static EM_BOOL
114Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
115{
116 SDL_joylist_item *item = SDL_joylist;
117 SDL_joylist_item *prev = NULL;
118
119 while (item != NULL) {
120 if (item->index == gamepadEvent->index) {
121 break;
122 }
123 prev = item;
124 item = item->next;
125 }
126
127 if (item == NULL) {
128 return 1;
129 }
130
131 if (item->joystick) {
132 item->joystick->hwdata = NULL;
133 }
134
135 if (prev != NULL) {
136 prev->next = item->next;
137 } else {
138 SDL_assert(SDL_joylist == item);
139 SDL_joylist = item->next;
140 }
141 if (item == SDL_joylist_tail) {
142 SDL_joylist_tail = prev;
143 }
144
145 /* Need to decrement the joystick count before we post the event */
146 --numjoysticks;
147
148 SDL_PrivateJoystickRemoved(item->device_instance);
149
150#ifdef DEBUG_JOYSTICK
151 SDL_Log("Removed joystick with id %d", item->device_instance);
152#endif
153 SDL_free(item->name);
154 SDL_free(item->mapping);
155 SDL_free(item);
156 return 1;
157}
158
159/* Function to perform any system-specific joystick related cleanup */
160static void
161EMSCRIPTEN_JoystickQuit(void)
162{
163 SDL_joylist_item *item = NULL;
164 SDL_joylist_item *next = NULL;
165
166 for (item = SDL_joylist; item; item = next) {
167 next = item->next;
168 SDL_free(item->mapping);
169 SDL_free(item->name);
170 SDL_free(item);
171 }
172
173 SDL_joylist = SDL_joylist_tail = NULL;
174
175 numjoysticks = 0;
176 instance_counter = 0;
177
178 emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
179 emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
180}
181
182/* Function to scan the system for joysticks.
183 * It should return 0, or -1 on an unrecoverable fatal error.
184 */
185static int
186EMSCRIPTEN_JoystickInit(void)
187{
188 int retval, i, numjs;
189 EmscriptenGamepadEvent gamepadState;
190
191 numjoysticks = 0;
192
193 retval = emscripten_sample_gamepad_data();
194
195 /* Check if gamepad is supported by browser */
196 if (retval == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
197 return SDL_SetError("Gamepads not supported");
198 }
199
200 numjs = emscripten_get_num_gamepads();
201
202 /* handle already connected gamepads */
203 if (numjs > 0) {
204 for(i = 0; i < numjs; i++) {
205 retval = emscripten_get_gamepad_status(i, &gamepadState);
206 if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
207 Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
208 &gamepadState,
209 NULL);
210 }
211 }
212 }
213
214 retval = emscripten_set_gamepadconnected_callback(NULL,
215 0,
216 Emscripten_JoyStickConnected);
217
218 if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
219 EMSCRIPTEN_JoystickQuit();
220 return SDL_SetError("Could not set gamepad connect callback");
221 }
222
223 retval = emscripten_set_gamepaddisconnected_callback(NULL,
224 0,
225 Emscripten_JoyStickDisconnected);
226 if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
227 EMSCRIPTEN_JoystickQuit();
228 return SDL_SetError("Could not set gamepad disconnect callback");
229 }
230
231 return 0;
232}
233
234/* Returns item matching given SDL device index. */
235static SDL_joylist_item *
236JoystickByDeviceIndex(int device_index)
237{
238 SDL_joylist_item *item = SDL_joylist;
239
240 while (0 < device_index) {
241 --device_index;
242 item = item->next;
243 }
244
245 return item;
246}
247
248/* Returns item matching given HTML gamepad index. */
249static SDL_joylist_item *
250JoystickByIndex(int index)
251{
252 SDL_joylist_item *item = SDL_joylist;
253
254 if (index < 0) {
255 return NULL;
256 }
257
258 while (item != NULL) {
259 if (item->index == index) {
260 break;
261 }
262 item = item->next;
263 }
264
265 return item;
266}
267
268static int
269EMSCRIPTEN_JoystickGetCount(void)
270{
271 return numjoysticks;
272}
273
274static void
275EMSCRIPTEN_JoystickDetect(void)
276{
277}
278
279static const char *
280EMSCRIPTEN_JoystickGetDeviceName(int device_index)
281{
282 return JoystickByDeviceIndex(device_index)->name;
283}
284
285static int
286EMSCRIPTEN_JoystickGetDevicePlayerIndex(int device_index)
287{
288 return -1;
289}
290
291static SDL_JoystickID
292EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index)
293{
294 return JoystickByDeviceIndex(device_index)->device_instance;
295}
296
297/* Function to open a joystick for use.
298 The joystick to open is specified by the device index.
299 This should fill the nbuttons and naxes fields of the joystick structure.
300 It returns 0, or -1 if there is an error.
301 */
302static int
303EMSCRIPTEN_JoystickOpen(SDL_Joystick * joystick, int device_index)
304{
305 SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
306
307 if (item == NULL ) {
308 return SDL_SetError("No such device");
309 }
310
311 if (item->joystick != NULL) {
312 return SDL_SetError("Joystick already opened");
313 }
314
315 joystick->instance_id = item->device_instance;
316 joystick->hwdata = (struct joystick_hwdata *) item;
317 item->joystick = joystick;
318
319 /* HTML5 Gamepad API doesn't say anything about these */
320 joystick->nhats = 0;
321 joystick->nballs = 0;
322
323 joystick->nbuttons = item->nbuttons;
324 joystick->naxes = item->naxes;
325
326 return (0);
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
335EMSCRIPTEN_JoystickUpdate(SDL_Joystick * joystick)
336{
337 EmscriptenGamepadEvent gamepadState;
338 SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
339 int i, result, buttonState;
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 buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
350 SDL_PrivateJoystickButton(item->joystick, i, buttonState);
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_PrivateJoystickAxis(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
377EMSCRIPTEN_JoystickClose(SDL_Joystick * joystick)
378{
379 SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
380 if (item) {
381 item->joystick = NULL;
382 }
383}
384
385static SDL_JoystickGUID
386EMSCRIPTEN_JoystickGetDeviceGUID(int device_index)
387{
389 /* the GUID is just the first 16 chars of the name for now */
390 const char *name = EMSCRIPTEN_JoystickGetDeviceName(device_index);
391 SDL_zero(guid);
393 return guid;
394}
395
396static int
397EMSCRIPTEN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
398{
399 return SDL_Unsupported();
400}
401
403{
404 EMSCRIPTEN_JoystickInit,
405 EMSCRIPTEN_JoystickGetCount,
406 EMSCRIPTEN_JoystickDetect,
407 EMSCRIPTEN_JoystickGetDeviceName,
408 EMSCRIPTEN_JoystickGetDevicePlayerIndex,
409 EMSCRIPTEN_JoystickGetDeviceGUID,
410 EMSCRIPTEN_JoystickGetDeviceInstanceID,
411 EMSCRIPTEN_JoystickOpen,
412 EMSCRIPTEN_JoystickRumble,
413 EMSCRIPTEN_JoystickUpdate,
414 EMSCRIPTEN_JoystickClose,
415 EMSCRIPTEN_JoystickQuit,
416};
417
418#endif /* SDL_JOYSTICK_EMSCRIPTEN */
419
420/* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define SDL_SetError
#define SDL_malloc
#define SDL_strlen
#define SDL_free
#define SDL_strdup
#define SDL_memcpy
#define SDL_Log
#define SDL_Unsupported()
Definition: SDL_error.h:53
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:805
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:833
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:755
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:966
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
GLuint64EXT * result
GLuint index
GLuint const GLchar * name
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
int16_t Sint16
Definition: SDL_stdinc.h:185
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
uint16_t Uint16
Definition: SDL_stdinc.h:191
SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver
static int numjoysticks
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
SDL_JoystickGUID guid
SDL_Joystick * joystick
struct SDL_joylist_item * item
SDL_bool retval