SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 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_ANDROID
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 #include "../../core/android/SDL_android.h"
38 #include "../steam/SDL_steamcontroller.h"
39 
40 #include "android/keycodes.h"
41 
42 /* As of platform android-14, android/keycodes.h is missing these defines */
43 #ifndef AKEYCODE_BUTTON_1
44 #define AKEYCODE_BUTTON_1 188
45 #define AKEYCODE_BUTTON_2 189
46 #define AKEYCODE_BUTTON_3 190
47 #define AKEYCODE_BUTTON_4 191
48 #define AKEYCODE_BUTTON_5 192
49 #define AKEYCODE_BUTTON_6 193
50 #define AKEYCODE_BUTTON_7 194
51 #define AKEYCODE_BUTTON_8 195
52 #define AKEYCODE_BUTTON_9 196
53 #define AKEYCODE_BUTTON_10 197
54 #define AKEYCODE_BUTTON_11 198
55 #define AKEYCODE_BUTTON_12 199
56 #define AKEYCODE_BUTTON_13 200
57 #define AKEYCODE_BUTTON_14 201
58 #define AKEYCODE_BUTTON_15 202
59 #define AKEYCODE_BUTTON_16 203
60 #endif
61 
62 #define ANDROID_ACCELEROMETER_NAME "Android Accelerometer"
63 #define ANDROID_ACCELEROMETER_DEVICE_ID INT_MIN
64 #define ANDROID_MAX_NBUTTONS 36
65 
66 static SDL_joylist_item * JoystickByDeviceId(int device_id);
67 
68 static SDL_joylist_item *SDL_joylist = NULL;
69 static SDL_joylist_item *SDL_joylist_tail = NULL;
70 static int numjoysticks = 0;
71 static int instance_counter = 0;
72 
73 
74 /* Function to convert Android keyCodes into SDL ones.
75  * This code manipulation is done to get a sequential list of codes.
76  * FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
77  */
78 static int
79 keycode_to_SDL(int keycode)
80 {
81  /* FIXME: If this function gets too unwiedly in the future, replace with a lookup table */
82  int button = 0;
83  switch(keycode)
84  {
85  /* Some gamepad buttons (API 9) */
86  case AKEYCODE_BUTTON_A:
87  button = SDL_CONTROLLER_BUTTON_A;
88  break;
89  case AKEYCODE_BUTTON_B:
90  button = SDL_CONTROLLER_BUTTON_B;
91  break;
92  case AKEYCODE_BUTTON_X:
93  button = SDL_CONTROLLER_BUTTON_X;
94  break;
95  case AKEYCODE_BUTTON_Y:
96  button = SDL_CONTROLLER_BUTTON_Y;
97  break;
98  case AKEYCODE_BUTTON_L1:
100  break;
101  case AKEYCODE_BUTTON_R1:
103  break;
104  case AKEYCODE_BUTTON_THUMBL:
106  break;
107  case AKEYCODE_BUTTON_THUMBR:
109  break;
110  case AKEYCODE_BUTTON_START:
112  break;
113  case AKEYCODE_BUTTON_SELECT:
115  break;
116  case AKEYCODE_BUTTON_MODE:
118  break;
119  case AKEYCODE_BUTTON_L2:
120  button = SDL_CONTROLLER_BUTTON_MAX; /* Not supported by GameController */
121  break;
122  case AKEYCODE_BUTTON_R2:
123  button = SDL_CONTROLLER_BUTTON_MAX+1; /* Not supported by GameController */
124  break;
125  case AKEYCODE_BUTTON_C:
126  button = SDL_CONTROLLER_BUTTON_MAX+2; /* Not supported by GameController */
127  break;
128  case AKEYCODE_BUTTON_Z:
129  button = SDL_CONTROLLER_BUTTON_MAX+3; /* Not supported by GameController */
130  break;
131 
132  /* D-Pad key codes (API 1) */
133  case AKEYCODE_DPAD_UP:
135  break;
136  case AKEYCODE_DPAD_DOWN:
138  break;
139  case AKEYCODE_DPAD_LEFT:
141  break;
142  case AKEYCODE_DPAD_RIGHT:
144  break;
145  case AKEYCODE_DPAD_CENTER:
146  button = SDL_CONTROLLER_BUTTON_MAX+4; /* Not supported by GameController */
147  break;
148 
149  /* More gamepad buttons (API 12), these get mapped to 20...35*/
150  case AKEYCODE_BUTTON_1:
151  case AKEYCODE_BUTTON_2:
152  case AKEYCODE_BUTTON_3:
153  case AKEYCODE_BUTTON_4:
154  case AKEYCODE_BUTTON_5:
155  case AKEYCODE_BUTTON_6:
156  case AKEYCODE_BUTTON_7:
157  case AKEYCODE_BUTTON_8:
158  case AKEYCODE_BUTTON_9:
159  case AKEYCODE_BUTTON_10:
160  case AKEYCODE_BUTTON_11:
161  case AKEYCODE_BUTTON_12:
162  case AKEYCODE_BUTTON_13:
163  case AKEYCODE_BUTTON_14:
164  case AKEYCODE_BUTTON_15:
165  case AKEYCODE_BUTTON_16:
166  button = keycode - AKEYCODE_BUTTON_1 + SDL_CONTROLLER_BUTTON_MAX + 5;
167  break;
168 
169  default:
170  return -1;
171  /* break; -Wunreachable-code-break */
172  }
173 
174  /* This is here in case future generations, probably with six fingers per hand,
175  * happily add new cases up above and forget to update the max number of buttons.
176  */
177  SDL_assert(button < ANDROID_MAX_NBUTTONS);
178  return button;
179 
180 }
181 
182 int
183 Android_OnPadDown(int device_id, int keycode)
184 {
185  SDL_joylist_item *item;
186  int button = keycode_to_SDL(keycode);
187  if (button >= 0) {
188  item = JoystickByDeviceId(device_id);
189  if (item && item->joystick) {
190  SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
191  }
192  return 0;
193  }
194 
195  return -1;
196 }
197 
198 int
199 Android_OnPadUp(int device_id, int keycode)
200 {
201  SDL_joylist_item *item;
202  int button = keycode_to_SDL(keycode);
203  if (button >= 0) {
204  item = JoystickByDeviceId(device_id);
205  if (item && item->joystick) {
206  SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED);
207  }
208  return 0;
209  }
210 
211  return -1;
212 }
213 
214 int
215 Android_OnJoy(int device_id, int axis, float value)
216 {
217  /* Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] */
218  SDL_joylist_item *item = JoystickByDeviceId(device_id);
219  if (item && item->joystick) {
220  SDL_PrivateJoystickAxis(item->joystick, axis, (Sint16) (32767.*value));
221  }
222 
223  return 0;
224 }
225 
226 int
227 Android_OnHat(int device_id, int hat_id, int x, int y)
228 {
229  const Uint8 position_map[3][3] = {
233  };
234 
235  if (x >= -1 && x <=1 && y >= -1 && y <= 1) {
236  SDL_joylist_item *item = JoystickByDeviceId(device_id);
237  if (item && item->joystick) {
238  SDL_PrivateJoystickHat(item->joystick, hat_id, position_map[y+1][x+1]);
239  }
240  return 0;
241  }
242 
243  return -1;
244 }
245 
246 
247 int
248 Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
249 {
250  SDL_JoystickGUID guid;
251  SDL_joylist_item *item;
252 
253  if(JoystickByDeviceId(device_id) != NULL || name == NULL) {
254  return -1;
255  }
256 
257  /* the GUID is just the first 16 chars of the name for now */
258  SDL_zero(guid);
259  SDL_memcpy(&guid, desc, SDL_min(sizeof(guid), SDL_strlen(desc)));
260 
261  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
262  if (item == NULL) {
263  return -1;
264  }
265 
266  SDL_zerop(item);
267  item->guid = guid;
268  item->device_id = device_id;
269  item->name = SDL_strdup(name);
270  if (item->name == NULL) {
271  SDL_free(item);
272  return -1;
273  }
274 
275  item->is_accelerometer = is_accelerometer;
276  if (nbuttons > -1) {
277  item->nbuttons = nbuttons;
278  }
279  else {
280  item->nbuttons = ANDROID_MAX_NBUTTONS;
281  }
282  item->naxes = naxes;
283  item->nhats = nhats;
284  item->nballs = nballs;
285  item->device_instance = instance_counter++;
286  if (SDL_joylist_tail == NULL) {
287  SDL_joylist = SDL_joylist_tail = item;
288  } else {
289  SDL_joylist_tail->next = item;
290  SDL_joylist_tail = item;
291  }
292 
293  /* Need to increment the joystick count before we post the event */
294  ++numjoysticks;
295 
297 
298 #ifdef DEBUG_JOYSTICK
299  SDL_Log("Added joystick %s with device_id %d", name, device_id);
300 #endif
301 
302  return numjoysticks;
303 }
304 
305 int
306 Android_RemoveJoystick(int device_id)
307 {
308  SDL_joylist_item *item = SDL_joylist;
309  SDL_joylist_item *prev = NULL;
310 
311  /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
312  while (item != NULL) {
313  if (item->device_id == device_id) {
314  break;
315  }
316  prev = item;
317  item = item->next;
318  }
319 
320  if (item == NULL) {
321  return -1;
322  }
323 
324  if (item->joystick) {
325  item->joystick->hwdata = NULL;
326  }
327 
328  if (prev != NULL) {
329  prev->next = item->next;
330  } else {
331  SDL_assert(SDL_joylist == item);
332  SDL_joylist = item->next;
333  }
334  if (item == SDL_joylist_tail) {
335  SDL_joylist_tail = prev;
336  }
337 
338  /* Need to decrement the joystick count before we post the event */
339  --numjoysticks;
340 
341  SDL_PrivateJoystickRemoved(item->device_instance);
342 
343 #ifdef DEBUG_JOYSTICK
344  SDL_Log("Removed joystick with device_id %d", device_id);
345 #endif
346 
347  SDL_free(item->name);
348  SDL_free(item);
349  return numjoysticks;
350 }
351 
352 
353 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
354 {
355  SDL_joylist_item *item;
356 
357  item = (SDL_joylist_item *)SDL_calloc(1, sizeof (SDL_joylist_item));
358  if (item == NULL) {
359  return SDL_FALSE;
360  }
361 
362  *device_instance = item->device_instance = instance_counter++;
363  item->device_id = -1;
364  item->name = SDL_strdup(name);
365  item->guid = guid;
366  SDL_GetSteamControllerInputs(&item->nbuttons,
367  &item->naxes,
368  &item->nhats);
369  item->m_bSteamController = SDL_TRUE;
370 
371  if (SDL_joylist_tail == NULL) {
372  SDL_joylist = SDL_joylist_tail = item;
373  } else {
374  SDL_joylist_tail->next = item;
375  SDL_joylist_tail = item;
376  }
377 
378  /* Need to increment the joystick count before we post the event */
379  ++numjoysticks;
380 
382 
383  return SDL_TRUE;
384 }
385 
386 static void SteamControllerDisconnectedCallback(int device_instance)
387 {
388  SDL_joylist_item *item = SDL_joylist;
389  SDL_joylist_item *prev = NULL;
390 
391  while (item != NULL) {
392  if (item->device_instance == device_instance) {
393  break;
394  }
395  prev = item;
396  item = item->next;
397  }
398 
399  if (item == NULL) {
400  return;
401  }
402 
403  if (item->joystick) {
404  item->joystick->hwdata = NULL;
405  }
406 
407  if (prev != NULL) {
408  prev->next = item->next;
409  } else {
410  SDL_assert(SDL_joylist == item);
411  SDL_joylist = item->next;
412  }
413  if (item == SDL_joylist_tail) {
414  SDL_joylist_tail = prev;
415  }
416 
417  /* Need to decrement the joystick count before we post the event */
418  --numjoysticks;
419 
420  SDL_PrivateJoystickRemoved(item->device_instance);
421 
422  SDL_free(item->name);
423  SDL_free(item);
424 }
425 
426 int
428 {
430 
432  /* Default behavior, accelerometer as joystick */
433  Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
434  }
435 
438 
439  return (numjoysticks);
440 
441 }
442 
443 int
445 {
446  return numjoysticks;
447 }
448 
449 void
451 {
452  /* Support for device connect/disconnect is API >= 16 only,
453  * so we poll every three seconds
454  * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
455  */
456  static Uint32 timeout = 0;
457  if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
458  timeout = SDL_GetTicks() + 3000;
460  }
461 
463 }
464 
465 static SDL_joylist_item *
466 JoystickByDevIndex(int device_index)
467 {
468  SDL_joylist_item *item = SDL_joylist;
469 
470  if ((device_index < 0) || (device_index >= numjoysticks)) {
471  return NULL;
472  }
473 
474  while (device_index > 0) {
475  SDL_assert(item != NULL);
476  device_index--;
477  item = item->next;
478  }
479 
480  return item;
481 }
482 
483 static SDL_joylist_item *
484 JoystickByDeviceId(int device_id)
485 {
486  SDL_joylist_item *item = SDL_joylist;
487 
488  while (item != NULL) {
489  if (item->device_id == device_id) {
490  return item;
491  }
492  item = item->next;
493  }
494 
495  /* Joystick not found, try adding it */
497 
498  while (item != NULL) {
499  if (item->device_id == device_id) {
500  return item;
501  }
502  item = item->next;
503  }
504 
505  return NULL;
506 }
507 
508 /* Function to get the device-dependent name of a joystick */
509 const char *
510 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
511 {
512  return JoystickByDevIndex(device_index)->name;
513 }
514 
515 /* Function to perform the mapping from device index to the instance id for this index */
517 {
518  return JoystickByDevIndex(device_index)->device_instance;
519 }
520 
521 /* Function to open a joystick for use.
522  The joystick to open is specified by the device index.
523  This should fill the nbuttons and naxes fields of the joystick structure.
524  It returns 0, or -1 if there is an error.
525  */
526 int
527 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
528 {
529  SDL_joylist_item *item = JoystickByDevIndex(device_index);
530 
531  if (item == NULL) {
532  return SDL_SetError("No such device");
533  }
534 
535  if (item->joystick != NULL) {
536  return SDL_SetError("Joystick already opened");
537  }
538 
539  joystick->instance_id = item->device_instance;
540  joystick->hwdata = (struct joystick_hwdata *) item;
541  item->joystick = joystick;
542  joystick->nhats = item->nhats;
543  joystick->nballs = item->nballs;
544  joystick->nbuttons = item->nbuttons;
545  joystick->naxes = item->naxes;
546 
547  return (0);
548 }
549 
550 /* Function to determine if this joystick is attached to the system right now */
551 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
552 {
553  return joystick->hwdata != NULL;
554 }
555 
556 void
557 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
558 {
559  SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
560 
561  if (item == NULL) {
562  return;
563  }
564 
565  if (item->m_bSteamController) {
566  SDL_UpdateSteamController(joystick);
567  return;
568  }
569 
570  if (item->is_accelerometer) {
571  int i;
572  Sint16 value;
573  float values[3];
574 
576  for (i = 0; i < 3; i++) {
577  if (values[i] > 1.0f) {
578  values[i] = 1.0f;
579  } else if (values[i] < -1.0f) {
580  values[i] = -1.0f;
581  }
582 
583  value = (Sint16)(values[i] * 32767.0f);
584  SDL_PrivateJoystickAxis(item->joystick, i, value);
585  }
586  }
587  }
588 }
589 
590 /* Function to close a joystick after use */
591 void
592 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
593 {
594  SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
595  if (item) {
596  item->joystick = NULL;
597  }
598 }
599 
600 /* Function to perform any system-specific joystick related cleanup */
601 void
603 {
604 /* We don't have any way to scan for joysticks at init, so don't wipe the list
605  * of joysticks here in case this is a reinit.
606  */
607 #if 0
608  SDL_joylist_item *item = NULL;
609  SDL_joylist_item *next = NULL;
610 
611  for (item = SDL_joylist; item; item = next) {
612  next = item->next;
613  SDL_free(item->name);
614  SDL_free(item);
615  }
616 
617  SDL_joylist = SDL_joylist_tail = NULL;
618 
619  numjoysticks = 0;
620  instance_counter = 0;
621 #endif /* 0 */
622 
624 }
625 
627 {
628  return JoystickByDevIndex(device_index)->guid;
629 }
630 
631 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
632 {
634 
635  if (joystick->hwdata != NULL) {
636  return ((SDL_joylist_item*)joystick->hwdata)->guid;
637  }
638 
639  SDL_zero(guid);
640  return guid;
641 }
642 
643 #endif /* SDL_JOYSTICK_ANDROID */
644 
645 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_HAT_LEFTDOWN
Definition: SDL_joystick.h:324
void SDL_UpdateSteamControllers(void)
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
SDL_Texture * button
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:638
SDL_JoystickGUID guid
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:712
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback, SteamControllerDisconnectedCallback_t disconnectedCallback)
static void SteamControllerDisconnectedCallback(int device_instance)
void SDL_QuitSteamControllers(void)
SDL_bool Android_JNI_GetAccelerometerValues(float values[3])
SDL_Joystick * joystick
#define SDL_HAT_RIGHTUP
Definition: SDL_joystick.h:321
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:788
GLfloat f
struct joystick_hwdata * next
SDL_Texture * axis
void SDL_SYS_JoystickQuit(void)
uint32_t Uint32
Definition: SDL_stdinc.h:181
#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
#define SDL_GetHintBoolean
GLenum GLsizei GLsizei GLint * values
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:318
#define SDL_Log
#define SDL_memcpy
#define SDL_HINT_ACCELEROMETER_AS_JOYSTICK
A variable controlling whether the Android / iOS built-in accelerometer should be listed as a joystic...
Definition: SDL_hints.h:366
#define SDL_HAT_RIGHTDOWN
Definition: SDL_joystick.h:322
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:320
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
GLsizei const GLfloat * value
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)
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
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
static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_SYS_JoystickInit(void)
#define NULL
Definition: begin_code.h:164
void SDL_UpdateSteamController(SDL_Joystick *joystick)
SDL_bool
Definition: SDL_stdinc.h:139
int SDL_SYS_NumJoysticks(void)
#define SDL_SetError
#define SDL_calloc
#define SDL_strlen
#define SDL_strdup
#define SDL_HAT_LEFTUP
Definition: SDL_joystick.h:323
GLbitfield GLuint64 timeout
struct SDL_joylist_item * item
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
static int numjoysticks
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
#define SDL_malloc
void Android_JNI_PollInputDevices(void)
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:316
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_HAT_UP
Definition: SDL_joystick.h:317
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:319
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
int16_t Sint16
Definition: SDL_stdinc.h:163
void SDL_SYS_JoystickDetect(void)