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