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