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 #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
keycode_to_SDL(int keycode)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:
98 button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
99 break;
100 case AKEYCODE_BUTTON_R1:
101 button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
102 break;
103 case AKEYCODE_BUTTON_THUMBL:
104 button = SDL_CONTROLLER_BUTTON_LEFTSTICK;
105 break;
106 case AKEYCODE_BUTTON_THUMBR:
107 button = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
108 break;
109 case AKEYCODE_BUTTON_START:
110 button = SDL_CONTROLLER_BUTTON_START;
111 break;
112 case AKEYCODE_BUTTON_SELECT:
113 button = SDL_CONTROLLER_BUTTON_BACK;
114 break;
115 case AKEYCODE_BUTTON_MODE:
116 button = SDL_CONTROLLER_BUTTON_GUIDE;
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:
133 button = SDL_CONTROLLER_BUTTON_DPAD_UP;
134 break;
135 case AKEYCODE_DPAD_DOWN:
136 button = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
137 break;
138 case AKEYCODE_DPAD_LEFT:
139 button = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
140 break;
141 case AKEYCODE_DPAD_RIGHT:
142 button = SDL_CONTROLLER_BUTTON_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;
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
Android_OnPadDown(int device_id,int keycode)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
Android_OnPadUp(int device_id,int keycode)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
Android_OnJoy(int device_id,int axis,float value)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
Android_OnHat(int device_id,int hat_id,int x,int y)226 Android_OnHat(int device_id, int hat_id, int x, int y)
227 {
228 const Uint8 position_map[3][3] = {
229 {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
230 {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
231 {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
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
Android_AddJoystick(int device_id,const char * name,SDL_bool is_accelerometer,int nbuttons,int naxes,int nhats,int nballs)247 Android_AddJoystick(int device_id, const char *name, 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, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
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
295 SDL_PrivateJoystickAdded(numjoysticks - 1);
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
Android_RemoveJoystick(int device_id)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
SDL_SYS_JoystickInit(void)353 SDL_SYS_JoystickInit(void)
354 {
355 SDL_SYS_JoystickDetect();
356
357 if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
358 /* Default behavior, accelerometer as joystick */
359 Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
360 }
361
362 return (numjoysticks);
363
364 }
365
SDL_SYS_NumJoysticks()366 int SDL_SYS_NumJoysticks()
367 {
368 return numjoysticks;
369 }
370
SDL_SYS_JoystickDetect()371 void SDL_SYS_JoystickDetect()
372 {
373 /* Support for device connect/disconnect is API >= 16 only,
374 * so we poll every three seconds
375 * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
376 */
377 static Uint32 timeout = 0;
378 if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
379 timeout = SDL_GetTicks() + 3000;
380 Android_JNI_PollInputDevices();
381 }
382 }
383
384 static SDL_joylist_item *
JoystickByDevIndex(int device_index)385 JoystickByDevIndex(int device_index)
386 {
387 SDL_joylist_item *item = SDL_joylist;
388
389 if ((device_index < 0) || (device_index >= numjoysticks)) {
390 return NULL;
391 }
392
393 while (device_index > 0) {
394 SDL_assert(item != NULL);
395 device_index--;
396 item = item->next;
397 }
398
399 return item;
400 }
401
402 static SDL_joylist_item *
JoystickByDeviceId(int device_id)403 JoystickByDeviceId(int device_id)
404 {
405 SDL_joylist_item *item = SDL_joylist;
406
407 while (item != NULL) {
408 if (item->device_id == device_id) {
409 return item;
410 }
411 item = item->next;
412 }
413
414 /* Joystick not found, try adding it */
415 SDL_SYS_JoystickDetect();
416
417 while (item != NULL) {
418 if (item->device_id == device_id) {
419 return item;
420 }
421 item = item->next;
422 }
423
424 return NULL;
425 }
426
427 /* Function to get the device-dependent name of a joystick */
428 const char *
SDL_SYS_JoystickNameForDeviceIndex(int device_index)429 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
430 {
431 return JoystickByDevIndex(device_index)->name;
432 }
433
434 /* Function to perform the mapping from device index to the instance id for this index */
SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)435 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
436 {
437 return JoystickByDevIndex(device_index)->device_instance;
438 }
439
440 /* Function to open a joystick for use.
441 The joystick to open is specified by the device index.
442 This should fill the nbuttons and naxes fields of the joystick structure.
443 It returns 0, or -1 if there is an error.
444 */
445 int
SDL_SYS_JoystickOpen(SDL_Joystick * joystick,int device_index)446 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
447 {
448 SDL_joylist_item *item = JoystickByDevIndex(device_index);
449
450 if (item == NULL ) {
451 return SDL_SetError("No such device");
452 }
453
454 if (item->joystick != NULL) {
455 return SDL_SetError("Joystick already opened");
456 }
457
458 joystick->instance_id = item->device_instance;
459 joystick->hwdata = (struct joystick_hwdata *) item;
460 item->joystick = joystick;
461 joystick->nhats = item->nhats;
462 joystick->nballs = item->nballs;
463 joystick->nbuttons = item->nbuttons;
464 joystick->naxes = item->naxes;
465
466 return (0);
467 }
468
469 /* Function to determine if this joystick is attached to the system right now */
SDL_SYS_JoystickAttached(SDL_Joystick * joystick)470 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
471 {
472 return joystick->hwdata != NULL;
473 }
474
475 void
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)476 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
477 {
478 int i;
479 Sint16 value;
480 float values[3];
481 SDL_joylist_item *item = SDL_joylist;
482
483 while (item) {
484 if (item->is_accelerometer) {
485 if (item->joystick) {
486 if (Android_JNI_GetAccelerometerValues(values)) {
487 for ( i = 0; i < 3; i++ ) {
488 if (values[i] > 1.0f) {
489 values[i] = 1.0f;
490 } else if (values[i] < -1.0f) {
491 values[i] = -1.0f;
492 }
493
494 value = (Sint16)(values[i] * 32767.0f);
495 SDL_PrivateJoystickAxis(item->joystick, i, value);
496 }
497 }
498 }
499 break;
500 }
501 item = item->next;
502 }
503 }
504
505 /* Function to close a joystick after use */
506 void
SDL_SYS_JoystickClose(SDL_Joystick * joystick)507 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
508 {
509 SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
510 if (item) {
511 item->joystick = NULL;
512 }
513 }
514
515 /* Function to perform any system-specific joystick related cleanup */
516 void
SDL_SYS_JoystickQuit(void)517 SDL_SYS_JoystickQuit(void)
518 {
519 SDL_joylist_item *item = NULL;
520 SDL_joylist_item *next = NULL;
521
522 for (item = SDL_joylist; item; item = next) {
523 next = item->next;
524 SDL_free(item->name);
525 SDL_free(item);
526 }
527
528 SDL_joylist = SDL_joylist_tail = NULL;
529
530 numjoysticks = 0;
531 instance_counter = 0;
532 }
533
SDL_SYS_JoystickGetDeviceGUID(int device_index)534 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
535 {
536 return JoystickByDevIndex(device_index)->guid;
537 }
538
SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)539 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
540 {
541 SDL_JoystickGUID guid;
542
543 if (joystick->hwdata != NULL) {
544 return ((SDL_joylist_item*)joystick->hwdata)->guid;
545 }
546
547 SDL_zero(guid);
548 return guid;
549 }
550
551 #endif /* SDL_JOYSTICK_ANDROID */
552
553 /* vi: set ts=4 sw=4 expandtab: */
554