Changed SDL_HINT_ACCEL_AS_JOY to SDL_HINT_ACCELEROMETER_AS_JOYSTICK to be more clear.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
22 #include "../../SDL_internal.h"
24 #ifdef SDL_JOYSTICK_ANDROID
26 #include <stdio.h> /* For the definition of NULL */
27 #include "SDL_error.h"
28 #include "SDL_events.h"
30 #if !SDL_EVENTS_DISABLED
31 #include "../../events/SDL_events_c.h"
34 #include "SDL_joystick.h"
35 #include "SDL_hints.h"
36 #include "SDL_assert.h"
37 #include "SDL_timer.h"
39 #include "SDL_sysjoystick_c.h"
40 #include "../SDL_joystick_c.h"
41 #include "../../core/android/SDL_android.h"
43 #include "android/keycodes.h"
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
65 #define ANDROID_ACCELEROMETER_NAME "Android Accelerometer"
66 #define ANDROID_ACCELEROMETER_DEVICE_ID INT_MIN
67 #define ANDROID_MAX_NBUTTONS 36
69 static SDL_joylist_item * JoystickByDeviceId(int device_id);
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;
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
82 keycode_to_SDL(int keycode)
84 /* FIXME: If this function gets too unwiedly in the future, replace with a lookup table */
88 /* Some gamepad buttons (API 9) */
89 case AKEYCODE_BUTTON_A:
90 button = SDL_CONTROLLER_BUTTON_A;
92 case AKEYCODE_BUTTON_B:
93 button = SDL_CONTROLLER_BUTTON_B;
95 case AKEYCODE_BUTTON_X:
96 button = SDL_CONTROLLER_BUTTON_X;
98 case AKEYCODE_BUTTON_Y:
99 button = SDL_CONTROLLER_BUTTON_Y;
101 case AKEYCODE_BUTTON_L1:
102 button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
104 case AKEYCODE_BUTTON_R1:
105 button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
107 case AKEYCODE_BUTTON_THUMBL:
108 button = SDL_CONTROLLER_BUTTON_LEFTSTICK;
110 case AKEYCODE_BUTTON_THUMBR:
111 button = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
113 case AKEYCODE_BUTTON_START:
114 button = SDL_CONTROLLER_BUTTON_START;
116 case AKEYCODE_BUTTON_SELECT:
117 button = SDL_CONTROLLER_BUTTON_BACK;
119 case AKEYCODE_BUTTON_MODE:
120 button = SDL_CONTROLLER_BUTTON_GUIDE;
122 case AKEYCODE_BUTTON_L2:
123 button = SDL_CONTROLLER_BUTTON_MAX; /* Not supported by GameController */
125 case AKEYCODE_BUTTON_R2:
126 button = SDL_CONTROLLER_BUTTON_MAX+1; /* Not supported by GameController */
128 case AKEYCODE_BUTTON_C:
129 button = SDL_CONTROLLER_BUTTON_MAX+2; /* Not supported by GameController */
131 case AKEYCODE_BUTTON_Z:
132 button = SDL_CONTROLLER_BUTTON_MAX+3; /* Not supported by GameController */
135 /* D-Pad key codes (API 1) */
136 case AKEYCODE_DPAD_UP:
137 button = SDL_CONTROLLER_BUTTON_DPAD_UP;
139 case AKEYCODE_DPAD_DOWN:
140 button = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
142 case AKEYCODE_DPAD_LEFT:
143 button = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
145 case AKEYCODE_DPAD_RIGHT:
146 button = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
148 case AKEYCODE_DPAD_CENTER:
149 button = SDL_CONTROLLER_BUTTON_MAX+4; /* Not supported by GameController */
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;
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.
180 SDL_assert(button < ANDROID_MAX_NBUTTONS);
186 Android_OnPadDown(int device_id, int keycode)
188 SDL_joylist_item *item;
189 int button = keycode_to_SDL(keycode);
191 item = JoystickByDeviceId(device_id);
192 if (item && item->joystick) {
193 SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
202 Android_OnPadUp(int device_id, int keycode)
204 SDL_joylist_item *item;
205 int button = keycode_to_SDL(keycode);
207 item = JoystickByDeviceId(device_id);
208 if (item && item->joystick) {
209 SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED);
218 Android_OnJoy(int device_id, int axis, float value)
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) );
230 Android_OnHat(int device_id, int hat_id, int x, int y)
232 const Uint8 position_map[3][3] = {
233 {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
234 {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
235 {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
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] );
251 Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
253 SDL_JoystickGUID guid;
254 SDL_joylist_item *item;
255 #if !SDL_EVENTS_DISABLED
259 if(JoystickByDeviceId(device_id) != NULL || name == NULL) {
263 /* the GUID is just the first 16 chars of the name for now */
265 SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
267 item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
274 item->device_id = device_id;
275 item->name = SDL_strdup(name);
276 if ( item->name == NULL ) {
281 item->is_accelerometer = is_accelerometer;
283 item->nbuttons = nbuttons;
286 item->nbuttons = ANDROID_MAX_NBUTTONS;
290 item->nballs = nballs;
291 item->device_instance = instance_counter++;
292 if (SDL_joylist_tail == NULL) {
293 SDL_joylist = SDL_joylist_tail = item;
295 SDL_joylist_tail->next = item;
296 SDL_joylist_tail = item;
299 /* Need to increment the joystick count before we post the event */
302 #if !SDL_EVENTS_DISABLED
303 event.type = SDL_JOYDEVICEADDED;
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);
312 #endif /* !SDL_EVENTS_DISABLED */
314 SDL_Log("Added joystick %s with device_id %d", name, device_id);
320 Android_RemoveJoystick(int device_id)
322 SDL_joylist_item *item = SDL_joylist;
323 SDL_joylist_item *prev = NULL;
324 #if !SDL_EVENTS_DISABLED
328 /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
329 while (item != NULL) {
330 if (item->device_id == device_id) {
341 const int retval = item->device_instance;
342 if (item->joystick) {
343 item->joystick->hwdata = NULL;
347 prev->next = item->next;
349 SDL_assert(SDL_joylist == item);
350 SDL_joylist = item->next;
352 if (item == SDL_joylist_tail) {
353 SDL_joylist_tail = prev;
356 /* Need to decrement the joystick count before we post the event */
359 #if !SDL_EVENTS_DISABLED
360 event.type = SDL_JOYDEVICEREMOVED;
362 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
363 event.jdevice.which = item->device_instance;
364 if ( (SDL_EventOK == NULL) ||
365 (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
366 SDL_PushEvent(&event);
369 #endif /* !SDL_EVENTS_DISABLED */
371 SDL_Log("Removed joystick with device_id %d", device_id);
373 SDL_free(item->name);
380 SDL_SYS_JoystickInit(void)
383 SDL_SYS_JoystickDetect();
385 hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
386 if (!hint || SDL_atoi(hint)) {
387 /* Default behavior, accelerometer as joystick */
388 Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
391 return (numjoysticks);
395 int SDL_SYS_NumJoysticks()
400 void SDL_SYS_JoystickDetect()
402 /* Support for device connect/disconnect is API >= 16 only,
403 * so we poll every three seconds
404 * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
406 static Uint32 timeout = 0;
407 if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
408 timeout = SDL_GetTicks() + 3000;
409 Android_JNI_PollInputDevices();
413 SDL_bool SDL_SYS_JoystickNeedsPolling()
418 static SDL_joylist_item *
419 JoystickByDevIndex(int device_index)
421 SDL_joylist_item *item = SDL_joylist;
423 if ((device_index < 0) || (device_index >= numjoysticks)) {
427 while (device_index > 0) {
428 SDL_assert(item != NULL);
436 static SDL_joylist_item *
437 JoystickByDeviceId(int device_id)
439 SDL_joylist_item *item = SDL_joylist;
441 while (item != NULL) {
442 if (item->device_id == device_id) {
448 /* Joystick not found, try adding it */
449 SDL_SYS_JoystickDetect();
451 while (item != NULL) {
452 if (item->device_id == device_id) {
461 /* Function to get the device-dependent name of a joystick */
463 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
465 return JoystickByDevIndex(device_index)->name;
468 /* Function to perform the mapping from device index to the instance id for this index */
469 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
471 return JoystickByDevIndex(device_index)->device_instance;
474 /* Function to open a joystick for use.
475 The joystick to open is specified by the index field of the joystick.
476 This should fill the nbuttons and naxes fields of the joystick structure.
477 It returns 0, or -1 if there is an error.
480 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
482 SDL_joylist_item *item = JoystickByDevIndex(device_index);
485 return SDL_SetError("No such device");
488 if (item->joystick != NULL) {
489 return SDL_SetError("Joystick already opened");
492 joystick->instance_id = item->device_instance;
493 joystick->hwdata = (struct joystick_hwdata *) item;
494 item->joystick = joystick;
495 joystick->nhats = item->nhats;
496 joystick->nballs = item->nballs;
497 joystick->nbuttons = item->nbuttons;
498 joystick->naxes = item->naxes;
503 /* Function to determine is this joystick is attached to the system right now */
504 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
506 return !joystick->closed && (joystick->hwdata != NULL);
510 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
515 SDL_joylist_item *item = SDL_joylist;
518 if (item->is_accelerometer) {
519 if (item->joystick) {
520 if (Android_JNI_GetAccelerometerValues(values)) {
521 for ( i = 0; i < 3; i++ ) {
522 value = (Sint16)(values[i] * 32767.0f);
523 SDL_PrivateJoystickAxis(item->joystick, i, value);
533 /* Function to close a joystick after use */
535 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
537 if (joystick->hwdata) {
538 ((SDL_joylist_item*)joystick->hwdata)->joystick = NULL;
539 joystick->hwdata = NULL;
541 joystick->closed = 1;
544 /* Function to perform any system-specific joystick related cleanup */
546 SDL_SYS_JoystickQuit(void)
548 SDL_joylist_item *item = NULL;
549 SDL_joylist_item *next = NULL;
551 for (item = SDL_joylist; item; item = next) {
553 SDL_free(item->name);
557 SDL_joylist = SDL_joylist_tail = NULL;
560 instance_counter = 0;
563 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
565 return JoystickByDevIndex(device_index)->guid;
568 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
570 SDL_JoystickGUID guid;
572 if (joystick->hwdata != NULL) {
573 return ((SDL_joylist_item*)joystick->hwdata)->guid;
580 #endif /* SDL_JOYSTICK_ANDROID */
582 /* vi: set ts=4 sw=4 expandtab: */