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