SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 
37 static SDL_joylist_item * JoystickByIndex(int index);
38 
39 static SDL_joylist_item *SDL_joylist = NULL;
40 static SDL_joylist_item *SDL_joylist_tail = NULL;
41 static int numjoysticks = 0;
42 static int instance_counter = 0;
43 
44 static EM_BOOL
45 Emscripten_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 
98  ++numjoysticks;
99 
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 
113 static EM_BOOL
114 Emscripten_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 scan the system for joysticks.
160  * It should return 0, or -1 on an unrecoverable fatal error.
161  */
162 int
164 {
165  int retval, i, numjs;
166  EmscriptenGamepadEvent gamepadState;
167 
168  numjoysticks = 0;
169  numjs = emscripten_get_num_gamepads();
170 
171  /* Check if gamepad is supported by browser */
172  if (numjs == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
173  return SDL_SetError("Gamepads not supported");
174  }
175 
176  /* handle already connected gamepads */
177  if (numjs > 0) {
178  for(i = 0; i < numjs; i++) {
179  retval = emscripten_get_gamepad_status(i, &gamepadState);
180  if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
181  Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
182  &gamepadState,
183  NULL);
184  }
185  }
186  }
187 
188  retval = emscripten_set_gamepadconnected_callback(NULL,
189  0,
190  Emscripten_JoyStickConnected);
191 
192  if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
194  return SDL_SetError("Could not set gamepad connect callback");
195  }
196 
197  retval = emscripten_set_gamepaddisconnected_callback(NULL,
198  0,
199  Emscripten_JoyStickDisconnected);
200  if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
202  return SDL_SetError("Could not set gamepad disconnect callback");
203  }
204 
205  return 0;
206 }
207 
208 /* Returns item matching given SDL device index. */
209 static SDL_joylist_item *
210 JoystickByDeviceIndex(int device_index)
211 {
212  SDL_joylist_item *item = SDL_joylist;
213 
214  while (0 < device_index) {
215  --device_index;
216  item = item->next;
217  }
218 
219  return item;
220 }
221 
222 /* Returns item matching given HTML gamepad index. */
223 static SDL_joylist_item *
224 JoystickByIndex(int index)
225 {
226  SDL_joylist_item *item = SDL_joylist;
227 
228  if (index < 0) {
229  return NULL;
230  }
231 
232  while (item != NULL) {
233  if (item->index == index) {
234  break;
235  }
236  item = item->next;
237  }
238 
239  return item;
240 }
241 
242 int
244 {
245  return numjoysticks;
246 }
247 
248 void
250 {
251 }
252 
253 /* Function to get the device-dependent name of a joystick */
254 const char *
255 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
256 {
257  return JoystickByDeviceIndex(device_index)->name;
258 }
259 
260 /* Function to perform the mapping from device index to the instance id for this index */
262 {
263  return JoystickByDeviceIndex(device_index)->device_instance;
264 }
265 
266 /* Function to open a joystick for use.
267  The joystick to open is specified by the device index.
268  This should fill the nbuttons and naxes fields of the joystick structure.
269  It returns 0, or -1 if there is an error.
270  */
271 int
272 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
273 {
274  SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
275 
276  if (item == NULL ) {
277  return SDL_SetError("No such device");
278  }
279 
280  if (item->joystick != NULL) {
281  return SDL_SetError("Joystick already opened");
282  }
283 
284  joystick->instance_id = item->device_instance;
285  joystick->hwdata = (struct joystick_hwdata *) item;
286  item->joystick = joystick;
287 
288  /* HTML5 Gamepad API doesn't say anything about these */
289  joystick->nhats = 0;
290  joystick->nballs = 0;
291 
292  joystick->nbuttons = item->nbuttons;
293  joystick->naxes = item->naxes;
294 
295  return (0);
296 }
297 
298 /* Function to determine if this joystick is attached to the system right now */
299 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
300 {
301  return joystick->hwdata != NULL;
302 }
303 
304 /* Function to update the state of a joystick - called as a device poll.
305  * This function shouldn't update the joystick structure directly,
306  * but instead should call SDL_PrivateJoystick*() to deliver events
307  * and update joystick device state.
308  */
309 void
310 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
311 {
312  EmscriptenGamepadEvent gamepadState;
313  SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
314  int i, result, buttonState;
315 
316  if (item) {
317  result = emscripten_get_gamepad_status(item->index, &gamepadState);
318  if( result == EMSCRIPTEN_RESULT_SUCCESS) {
319  if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
320  for(i = 0; i < item->nbuttons; i++) {
321  if(item->digitalButton[i] != gamepadState.digitalButton[i]) {
322  buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
323  SDL_PrivateJoystickButton(item->joystick, i, buttonState);
324  }
325 
326  /* store values to compare them in the next update */
327  item->analogButton[i] = gamepadState.analogButton[i];
328  item->digitalButton[i] = gamepadState.digitalButton[i];
329  }
330 
331  for(i = 0; i < item->naxes; i++) {
332  if(item->axis[i] != gamepadState.axis[i]) {
333  /* do we need to do conversion? */
334  SDL_PrivateJoystickAxis(item->joystick, i,
335  (Sint16) (32767.*gamepadState.axis[i]));
336  }
337 
338  /* store to compare in next update */
339  item->axis[i] = gamepadState.axis[i];
340  }
341 
342  item->timestamp = gamepadState.timestamp;
343  }
344  }
345  }
346 }
347 
348 /* Function to close a joystick after use */
349 void
350 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
351 {
352  SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
353  if (item) {
354  item->joystick = NULL;
355  }
356 }
357 
358 /* Function to perform any system-specific joystick related cleanup */
359 void
361 {
362  SDL_joylist_item *item = NULL;
363  SDL_joylist_item *next = NULL;
364 
365  for (item = SDL_joylist; item; item = next) {
366  next = item->next;
367  SDL_free(item->mapping);
368  SDL_free(item->name);
369  SDL_free(item);
370  }
371 
372  SDL_joylist = SDL_joylist_tail = NULL;
373 
374  numjoysticks = 0;
375  instance_counter = 0;
376 
377  emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
378  emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
379 }
380 
382 SDL_SYS_JoystickGetDeviceGUID(int device_index)
383 {
385  /* the GUID is just the first 16 chars of the name for now */
386  const char *name = SDL_SYS_JoystickNameForDeviceIndex(device_index);
387  SDL_zero(guid);
388  SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
389  return guid;
390 }
391 
393 SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
394 {
396  /* the GUID is just the first 16 chars of the name for now */
397  const char *name = joystick->name;
398  SDL_zero(guid);
399  SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
400  return guid;
401 }
402 
403 #endif /* SDL_JOYSTICK_EMSCRIPTEN */
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:638
GLuint64EXT * result
SDL_JoystickGUID guid
SDL_Joystick * joystick
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:788
struct joystick_hwdata * next
void SDL_SYS_JoystickQuit(void)
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:655
GLuint const GLchar * name
SDL_bool retval
#define SDL_Log
#define SDL_memcpy
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define SDL_free
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
void SDL_PrivateJoystickAdded(int device_index)
Definition: SDL_joystick.c:595
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
GLuint index
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
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 SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_SYS_JoystickInit(void)
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
int SDL_SYS_NumJoysticks(void)
#define SDL_SetError
#define SDL_strlen
#define SDL_strdup
struct SDL_joylist_item * item
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
static int numjoysticks
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
#define SDL_malloc
#define SDL_PRESSED
Definition: SDL_events.h:50
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
#define SDL_RELEASED
Definition: SDL_events.h:49
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
int16_t Sint16
Definition: SDL_stdinc.h:163
void SDL_SYS_JoystickDetect(void)