SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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_timer.h"
32 #include "SDL_sysjoystick_c.h"
33 #include "../SDL_joystick_c.h"
34 
35 static SDL_joylist_item * JoystickByIndex(int index);
36 
37 static SDL_joylist_item *SDL_joylist = NULL;
38 static SDL_joylist_item *SDL_joylist_tail = NULL;
39 static int numjoysticks = 0;
40 static int instance_counter = 0;
41 
42 static EM_BOOL
43 Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
44 {
45  int i;
46 
47  SDL_joylist_item *item;
48 
49  if (JoystickByIndex(gamepadEvent->index) != NULL) {
50  return 1;
51  }
52 
53  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
54  if (item == NULL) {
55  return 1;
56  }
57 
58  SDL_zerop(item);
59  item->index = gamepadEvent->index;
60 
61  item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id);
62  if ( item->name == NULL ) {
63  SDL_free(item);
64  return 1;
65  }
66 
67  item->mapping = SDL_strdup(gamepadEvent->mapping);
68  if ( item->mapping == NULL ) {
69  SDL_free(item->name);
70  SDL_free(item);
71  return 1;
72  }
73 
74  item->naxes = gamepadEvent->numAxes;
75  item->nbuttons = gamepadEvent->numButtons;
76  item->device_instance = instance_counter++;
77 
78  item->timestamp = gamepadEvent->timestamp;
79 
80  for( i = 0; i < item->naxes; i++) {
81  item->axis[i] = gamepadEvent->axis[i];
82  }
83 
84  for( i = 0; i < item->nbuttons; i++) {
85  item->analogButton[i] = gamepadEvent->analogButton[i];
86  item->digitalButton[i] = gamepadEvent->digitalButton[i];
87  }
88 
89  if (SDL_joylist_tail == NULL) {
90  SDL_joylist = SDL_joylist_tail = item;
91  } else {
92  SDL_joylist_tail->next = item;
93  SDL_joylist_tail = item;
94  }
95 
96  ++numjoysticks;
97 
98  SDL_PrivateJoystickAdded(item->device_instance);
99 
100 #ifdef DEBUG_JOYSTICK
101  SDL_Log("Number of joysticks is %d", numjoysticks);
102 #endif
103 
104 #ifdef DEBUG_JOYSTICK
105  SDL_Log("Added joystick with index %d", item->index);
106 #endif
107 
108  return 1;
109 }
110 
111 static EM_BOOL
112 Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
113 {
114  SDL_joylist_item *item = SDL_joylist;
115  SDL_joylist_item *prev = NULL;
116 
117  while (item != NULL) {
118  if (item->index == gamepadEvent->index) {
119  break;
120  }
121  prev = item;
122  item = item->next;
123  }
124 
125  if (item == NULL) {
126  return 1;
127  }
128 
129  if (item->joystick) {
130  item->joystick->hwdata = NULL;
131  }
132 
133  if (prev != NULL) {
134  prev->next = item->next;
135  } else {
136  SDL_assert(SDL_joylist == item);
137  SDL_joylist = item->next;
138  }
139  if (item == SDL_joylist_tail) {
140  SDL_joylist_tail = prev;
141  }
142 
143  /* Need to decrement the joystick count before we post the event */
144  --numjoysticks;
145 
146  SDL_PrivateJoystickRemoved(item->device_instance);
147 
148 #ifdef DEBUG_JOYSTICK
149  SDL_Log("Removed joystick with id %d", item->device_instance);
150 #endif
151  SDL_free(item->name);
152  SDL_free(item->mapping);
153  SDL_free(item);
154  return 1;
155 }
156 
157 /* Function to perform any system-specific joystick related cleanup */
158 static void
159 EMSCRIPTEN_JoystickQuit(void)
160 {
161  SDL_joylist_item *item = NULL;
162  SDL_joylist_item *next = NULL;
163 
164  for (item = SDL_joylist; item; item = next) {
165  next = item->next;
166  SDL_free(item->mapping);
167  SDL_free(item->name);
168  SDL_free(item);
169  }
170 
171  SDL_joylist = SDL_joylist_tail = NULL;
172 
173  numjoysticks = 0;
174  instance_counter = 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.
181  * It should return 0, or -1 on an unrecoverable fatal error.
182  */
183 static int
184 EMSCRIPTEN_JoystickInit(void)
185 {
186  int retval, i, numjs;
187  EmscriptenGamepadEvent gamepadState;
188 
189  numjoysticks = 0;
190 
191  retval = emscripten_sample_gamepad_data();
192 
193  /* Check if gamepad is supported by browser */
194  if (retval == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
195  return SDL_SetError("Gamepads not supported");
196  }
197 
198  numjs = emscripten_get_num_gamepads();
199 
200  /* handle already connected gamepads */
201  if (numjs > 0) {
202  for(i = 0; i < numjs; i++) {
203  retval = emscripten_get_gamepad_status(i, &gamepadState);
204  if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
205  Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
206  &gamepadState,
207  NULL);
208  }
209  }
210  }
211 
212  retval = emscripten_set_gamepadconnected_callback(NULL,
213  0,
214  Emscripten_JoyStickConnected);
215 
216  if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
217  EMSCRIPTEN_JoystickQuit();
218  return SDL_SetError("Could not set gamepad connect callback");
219  }
220 
221  retval = emscripten_set_gamepaddisconnected_callback(NULL,
222  0,
223  Emscripten_JoyStickDisconnected);
224  if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
225  EMSCRIPTEN_JoystickQuit();
226  return SDL_SetError("Could not set gamepad disconnect callback");
227  }
228 
229  return 0;
230 }
231 
232 /* Returns item matching given SDL device index. */
233 static SDL_joylist_item *
234 JoystickByDeviceIndex(int device_index)
235 {
236  SDL_joylist_item *item = SDL_joylist;
237 
238  while (0 < device_index) {
239  --device_index;
240  item = item->next;
241  }
242 
243  return item;
244 }
245 
246 /* Returns item matching given HTML gamepad index. */
247 static SDL_joylist_item *
248 JoystickByIndex(int index)
249 {
250  SDL_joylist_item *item = SDL_joylist;
251 
252  if (index < 0) {
253  return NULL;
254  }
255 
256  while (item != NULL) {
257  if (item->index == index) {
258  break;
259  }
260  item = item->next;
261  }
262 
263  return item;
264 }
265 
266 static int
267 EMSCRIPTEN_JoystickGetCount(void)
268 {
269  return numjoysticks;
270 }
271 
272 static void
273 EMSCRIPTEN_JoystickDetect(void)
274 {
275 }
276 
277 static const char *
278 EMSCRIPTEN_JoystickGetDeviceName(int device_index)
279 {
280  return JoystickByDeviceIndex(device_index)->name;
281 }
282 
283 static int
284 EMSCRIPTEN_JoystickGetDevicePlayerIndex(int device_index)
285 {
286  return -1;
287 }
288 
289 static void
290 EMSCRIPTEN_JoystickSetDevicePlayerIndex(int device_index, int player_index)
291 {
292 }
293 
294 static SDL_JoystickID
295 EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index)
296 {
297  return JoystickByDeviceIndex(device_index)->device_instance;
298 }
299 
300 /* Function to open a joystick for use.
301  The joystick to open is specified by the device index.
302  This should fill the nbuttons and naxes fields of the joystick structure.
303  It returns 0, or -1 if there is an error.
304  */
305 static int
306 EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
307 {
308  SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
309 
310  if (item == NULL ) {
311  return SDL_SetError("No such device");
312  }
313 
314  if (item->joystick != NULL) {
315  return SDL_SetError("Joystick already opened");
316  }
317 
318  joystick->instance_id = item->device_instance;
319  joystick->hwdata = (struct joystick_hwdata *) item;
320  item->joystick = joystick;
321 
322  /* HTML5 Gamepad API doesn't say anything about these */
323  joystick->nhats = 0;
324  joystick->nballs = 0;
325 
326  joystick->nbuttons = item->nbuttons;
327  joystick->naxes = item->naxes;
328 
329  return (0);
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 static void
338 EMSCRIPTEN_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  emscripten_sample_gamepad_data();
345 
346  if (item) {
347  result = emscripten_get_gamepad_status(item->index, &gamepadState);
348  if( result == EMSCRIPTEN_RESULT_SUCCESS) {
349  if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
350  for(i = 0; i < item->nbuttons; i++) {
351  if(item->digitalButton[i] != gamepadState.digitalButton[i]) {
352  buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
353  SDL_PrivateJoystickButton(item->joystick, i, buttonState);
354  }
355 
356  /* store values to compare them in the next update */
357  item->analogButton[i] = gamepadState.analogButton[i];
358  item->digitalButton[i] = gamepadState.digitalButton[i];
359  }
360 
361  for(i = 0; i < item->naxes; i++) {
362  if(item->axis[i] != gamepadState.axis[i]) {
363  /* do we need to do conversion? */
364  SDL_PrivateJoystickAxis(item->joystick, i,
365  (Sint16) (32767.*gamepadState.axis[i]));
366  }
367 
368  /* store to compare in next update */
369  item->axis[i] = gamepadState.axis[i];
370  }
371 
372  item->timestamp = gamepadState.timestamp;
373  }
374  }
375  }
376 }
377 
378 /* Function to close a joystick after use */
379 static void
380 EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick)
381 {
382  SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
383  if (item) {
384  item->joystick = NULL;
385  }
386 }
387 
388 static SDL_JoystickGUID
389 EMSCRIPTEN_JoystickGetDeviceGUID(int device_index)
390 {
392  /* the GUID is just the first 16 chars of the name for now */
393  const char *name = EMSCRIPTEN_JoystickGetDeviceName(device_index);
394  SDL_zero(guid);
395  SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
396  return guid;
397 }
398 
399 static int
400 EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
401 {
402  return SDL_Unsupported();
403 }
404 
405 static int
406 EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
407 {
408  return SDL_Unsupported();
409 }
410 
411 static SDL_bool
412 EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
413 {
414  return SDL_FALSE;
415 }
416 
417 static SDL_bool
418 EMSCRIPTEN_JoystickHasLED(SDL_Joystick *joystick)
419 {
420  return SDL_FALSE;
421 }
422 
423 static int
424 EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
425 {
426  return SDL_Unsupported();
427 }
428 
429 static int
430 EMSCRIPTEN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
431 {
432  return SDL_Unsupported();
433 }
434 
436 {
437  EMSCRIPTEN_JoystickInit,
438  EMSCRIPTEN_JoystickGetCount,
439  EMSCRIPTEN_JoystickDetect,
440  EMSCRIPTEN_JoystickGetDeviceName,
441  EMSCRIPTEN_JoystickGetDevicePlayerIndex,
442  EMSCRIPTEN_JoystickSetDevicePlayerIndex,
443  EMSCRIPTEN_JoystickGetDeviceGUID,
444  EMSCRIPTEN_JoystickGetDeviceInstanceID,
445  EMSCRIPTEN_JoystickOpen,
446  EMSCRIPTEN_JoystickRumble,
447  EMSCRIPTEN_JoystickRumbleTriggers,
448  EMSCRIPTEN_JoystickHasLED,
449  EMSCRIPTEN_JoystickSetLED,
450  EMSCRIPTEN_JoystickSetSensorsEnabled,
451  EMSCRIPTEN_JoystickUpdate,
452  EMSCRIPTEN_JoystickClose,
453  EMSCRIPTEN_JoystickQuit,
454  EMSCRIPTEN_JoystickGetGamepadMapping
455 };
456 
457 #endif /* SDL_JOYSTICK_EMSCRIPTEN */
458 
459 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#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:89
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
const GLubyte GLuint red
Definition: SDL_glfuncs.h:80
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
char * SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
static int numjoysticks
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbyte GLbyte blue
GLuint64EXT * result
GLuint index
GLuint const GLchar * name
GLbyte green
uint16_t Uint16
Definition: SDL_stdinc.h:197
int16_t Sint16
Definition: SDL_stdinc.h:191
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_FALSE
Definition: SDL_stdinc.h:169
uint8_t Uint8
Definition: SDL_stdinc.h:185
#define SDL_zerop(x)
Definition: SDL_stdinc.h:427
#define SDL_min(x, y)
Definition: SDL_stdinc.h:412
SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver
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:163
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
SDL_JoystickGUID guid
struct SDL_joylist_item * item
SDL_bool retval
static SDL_Joystick * joystick
Definition: testjoystick.c:37