SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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_hints.h"
32 #include "SDL_assert.h"
33 #include "SDL_timer.h"
34 #include "SDL_log.h"
35 #include "SDL_sysjoystick_c.h"
36 #include "../SDL_joystick_c.h"
37 
38 static SDL_joylist_item * JoystickByIndex(int index);
39 
40 static SDL_joylist_item *SDL_joylist = NULL;
41 static SDL_joylist_item *SDL_joylist_tail = NULL;
42 static int numjoysticks = 0;
43 static int instance_counter = 0;
44 
45 EM_BOOL
46 Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
47 {
48  int i;
49 
50  SDL_joylist_item *item;
51 
52  if (JoystickByIndex(gamepadEvent->index) != NULL) {
53  return 1;
54  }
55 
56  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
57  if (item == NULL) {
58  return 1;
59  }
60 
61  SDL_zerop(item);
62  item->index = gamepadEvent->index;
63 
64  item->name = SDL_strdup(gamepadEvent->id);
65  if ( item->name == NULL ) {
66  SDL_free(item);
67  return 1;
68  }
69 
70  item->mapping = SDL_strdup(gamepadEvent->mapping);
71  if ( item->mapping == NULL ) {
72  SDL_free(item->name);
73  SDL_free(item);
74  return 1;
75  }
76 
77  item->naxes = gamepadEvent->numAxes;
78  item->nbuttons = gamepadEvent->numButtons;
79  item->device_instance = instance_counter++;
80 
81  item->timestamp = gamepadEvent->timestamp;
82 
83  for( i = 0; i < item->naxes; i++) {
84  item->axis[i] = gamepadEvent->axis[i];
85  }
86 
87  for( i = 0; i < item->nbuttons; i++) {
88  item->analogButton[i] = gamepadEvent->analogButton[i];
89  item->digitalButton[i] = gamepadEvent->digitalButton[i];
90  }
91 
92  if (SDL_joylist_tail == NULL) {
93  SDL_joylist = SDL_joylist_tail = item;
94  } else {
95  SDL_joylist_tail->next = item;
96  SDL_joylist_tail = item;
97  }
98 
99  ++numjoysticks;
100 
102 
103 #ifdef DEBUG_JOYSTICK
104  SDL_Log("Number of joysticks is %d", numjoysticks);
105 #endif
106 
107 #ifdef DEBUG_JOYSTICK
108  SDL_Log("Added joystick with index %d", item->index);
109 #endif
110 
111  return 1;
112 }
113 
114 EM_BOOL
115 Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
116 {
117  SDL_joylist_item *item = SDL_joylist;
118  SDL_joylist_item *prev = NULL;
119 
120  while (item != NULL) {
121  if (item->index == gamepadEvent->index) {
122  break;
123  }
124  prev = item;
125  item = item->next;
126  }
127 
128  if (item == NULL) {
129  return 1;
130  }
131 
132  if (item->joystick) {
133  item->joystick->hwdata = NULL;
134  }
135 
136  if (prev != NULL) {
137  prev->next = item->next;
138  } else {
139  SDL_assert(SDL_joylist == item);
140  SDL_joylist = item->next;
141  }
142  if (item == SDL_joylist_tail) {
143  SDL_joylist_tail = prev;
144  }
145 
146  /* Need to decrement the joystick count before we post the event */
147  --numjoysticks;
148 
149  SDL_PrivateJoystickRemoved(item->device_instance);
150 
151 #ifdef DEBUG_JOYSTICK
152  SDL_Log("Removed joystick with id %d", item->device_instance);
153 #endif
154  SDL_free(item->name);
155  SDL_free(item->mapping);
156  SDL_free(item);
157  return 1;
158 }
159 
160 /* Function to scan the system for joysticks.
161  * It should return 0, or -1 on an unrecoverable fatal error.
162  */
163 int
165 {
166  int retval, i, numjs;
167  EmscriptenGamepadEvent gamepadState;
168 
169  numjoysticks = 0;
170  numjs = emscripten_get_num_gamepads();
171 
172  /* Check if gamepad is supported by browser */
173  if (numjs == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
174  return SDL_SetError("Gamepads not supported");
175  }
176 
177  /* handle already connected gamepads */
178  if (numjs > 0) {
179  for(i = 0; i < numjs; i++) {
180  retval = emscripten_get_gamepad_status(i, &gamepadState);
181  if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
182  Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
183  &gamepadState,
184  NULL);
185  }
186  }
187  }
188 
189  retval = emscripten_set_gamepadconnected_callback(NULL,
190  0,
191  Emscripten_JoyStickConnected);
192 
193  if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
195  return SDL_SetError("Could not set gamepad connect callback");
196  }
197 
198  retval = emscripten_set_gamepaddisconnected_callback(NULL,
199  0,
200  Emscripten_JoyStickDisconnected);
201  if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
203  return SDL_SetError("Could not set gamepad disconnect callback");
204  }
205 
206  return 0;
207 }
208 
209 /* Returns item matching given SDL device index. */
210 static SDL_joylist_item *
211 JoystickByDeviceIndex(int device_index)
212 {
213  SDL_joylist_item *item = SDL_joylist;
214 
215  while (0 < device_index) {
216  --device_index;
217  item = item->next;
218  }
219 
220  return item;
221 }
222 
223 /* Returns item matching given HTML gamepad index. */
224 static SDL_joylist_item *
225 JoystickByIndex(int index)
226 {
227  SDL_joylist_item *item = SDL_joylist;
228 
229  if (index < 0) {
230  return NULL;
231  }
232 
233  while (item != NULL) {
234  if (item->index == index) {
235  break;
236  }
237  item = item->next;
238  }
239 
240  return item;
241 }
242 
244 {
245  return numjoysticks;
246 }
247 
249 {
250 }
251 
252 /* Function to get the device-dependent name of a joystick */
253 const char *
254 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
255 {
256  return JoystickByDeviceIndex(device_index)->name;
257 }
258 
259 /* Function to perform the mapping from device index to the instance id for this index */
261 {
262  return JoystickByDeviceIndex(device_index)->device_instance;
263 }
264 
265 /* Function to open a joystick for use.
266  The joystick to open is specified by the device index.
267  This should fill the nbuttons and naxes fields of the joystick structure.
268  It returns 0, or -1 if there is an error.
269  */
270 int
271 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
272 {
273  SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
274 
275  if (item == NULL ) {
276  return SDL_SetError("No such device");
277  }
278 
279  if (item->joystick != NULL) {
280  return SDL_SetError("Joystick already opened");
281  }
282 
283  joystick->instance_id = item->device_instance;
284  joystick->hwdata = (struct joystick_hwdata *) item;
285  item->joystick = joystick;
286 
287  /* HTML5 Gamepad API doesn't say anything about these */
288  joystick->nhats = 0;
289  joystick->nballs = 0;
290 
291  joystick->nbuttons = item->nbuttons;
292  joystick->naxes = item->naxes;
293 
294  return (0);
295 }
296 
297 /* Function to determine if this joystick is attached to the system right now */
298 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
299 {
300  return joystick->hwdata != NULL;
301 }
302 
303 /* Function to update the state of a joystick - called as a device poll.
304  * This function shouldn't update the joystick structure directly,
305  * but instead should call SDL_PrivateJoystick*() to deliver events
306  * and update joystick device state.
307  */
308 void
309 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
310 {
311  EmscriptenGamepadEvent gamepadState;
312  SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
313  int i, result, buttonState;
314 
315  if (item) {
316  result = emscripten_get_gamepad_status(item->index, &gamepadState);
317  if( result == EMSCRIPTEN_RESULT_SUCCESS) {
318  if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
319  for(i = 0; i < item->nbuttons; i++) {
320  if(item->digitalButton[i] != gamepadState.digitalButton[i]) {
321  buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
322  SDL_PrivateJoystickButton(item->joystick, i, buttonState);
323  }
324 
325  /* store values to compare them in the next update */
326  item->analogButton[i] = gamepadState.analogButton[i];
327  item->digitalButton[i] = gamepadState.digitalButton[i];
328  }
329 
330  for(i = 0; i < item->naxes; i++) {
331  if(item->axis[i] != gamepadState.axis[i]) {
332  // do we need to do conversion?
333  SDL_PrivateJoystickAxis(item->joystick, i,
334  (Sint16) (32767.*gamepadState.axis[i]));
335  }
336 
337  /* store to compare in next update */
338  item->axis[i] = gamepadState.axis[i];
339  }
340 
341  item->timestamp = gamepadState.timestamp;
342  }
343  }
344  }
345 }
346 
347 /* Function to close a joystick after use */
348 void
349 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
350 {
351  SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
352  if (item) {
353  item->joystick = NULL;
354  }
355 }
356 
357 /* Function to perform any system-specific joystick related cleanup */
358 void
360 {
361  SDL_joylist_item *item = NULL;
362  SDL_joylist_item *next = NULL;
363 
364  for (item = SDL_joylist; item; item = next) {
365  next = item->next;
366  SDL_free(item->mapping);
367  SDL_free(item->name);
368  SDL_free(item);
369  }
370 
371  SDL_joylist = SDL_joylist_tail = NULL;
372 
373  numjoysticks = 0;
374  instance_counter = 0;
375 
376  emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
377  emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
378 }
379 
381 SDL_SYS_JoystickGetDeviceGUID(int device_index)
382 {
384  /* the GUID is just the first 16 chars of the name for now */
385  const char *name = SDL_SYS_JoystickNameForDeviceIndex(device_index);
386  SDL_zero(guid);
387  SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
388  return guid;
389 }
390 
392 SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
393 {
395  /* the GUID is just the first 16 chars of the name for now */
396  const char *name = joystick->name;
397  SDL_zero(guid);
398  SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
399  return guid;
400 }
401 
402 #endif /* SDL_JOYSTICK_EMSCRIPTEN */
#define SDL_min(x, y)
Definition: SDL_stdinc.h:349
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:547
GLuint64EXT * result
SDL_JoystickGUID guid
int SDL_SYS_NumJoysticks()
SDL_Joystick * joystick
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:684
struct joystick_hwdata * next
GLuint const GLchar * name
void SDL_SYS_JoystickQuit(void)
#define SDL_zerop(x)
Definition: SDL_stdinc.h:360
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:567
SDL_bool retval
#define SDL_Log
#define SDL_memcpy
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:72
void SDL_free(void *mem)
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
void SDL_SYS_JoystickDetect()
void SDL_PrivateJoystickAdded(int device_index)
Definition: SDL_joystick.c:501
#define SDL_zero(x)
Definition: SDL_stdinc.h:359
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:167
int SDL_SYS_JoystickInit(void)
#define NULL
Definition: begin_code.h:143
SDL_bool
Definition: SDL_stdinc.h:130
#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
A signed 16-bit integer type.
Definition: SDL_stdinc.h:147