SDL_sysjoystick.c (16009B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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 69static SDL_joylist_item * JoystickByDeviceId(int device_id); 70 71static SDL_joylist_item *SDL_joylist = NULL; 72static SDL_joylist_item *SDL_joylist_tail = NULL; 73static int numjoysticks = 0; 74static 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 */ 81static int 82keycode_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: 102 button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; 103 break; 104 case AKEYCODE_BUTTON_R1: 105 button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; 106 break; 107 case AKEYCODE_BUTTON_THUMBL: 108 button = SDL_CONTROLLER_BUTTON_LEFTSTICK; 109 break; 110 case AKEYCODE_BUTTON_THUMBR: 111 button = SDL_CONTROLLER_BUTTON_RIGHTSTICK; 112 break; 113 case AKEYCODE_BUTTON_START: 114 button = SDL_CONTROLLER_BUTTON_START; 115 break; 116 case AKEYCODE_BUTTON_SELECT: 117 button = SDL_CONTROLLER_BUTTON_BACK; 118 break; 119 case AKEYCODE_BUTTON_MODE: 120 button = SDL_CONTROLLER_BUTTON_GUIDE; 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: 137 button = SDL_CONTROLLER_BUTTON_DPAD_UP; 138 break; 139 case AKEYCODE_DPAD_DOWN: 140 button = SDL_CONTROLLER_BUTTON_DPAD_DOWN; 141 break; 142 case AKEYCODE_DPAD_LEFT: 143 button = SDL_CONTROLLER_BUTTON_DPAD_LEFT; 144 break; 145 case AKEYCODE_DPAD_RIGHT: 146 button = SDL_CONTROLLER_BUTTON_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 185int 186Android_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 } 195 return 0; 196 } 197 198 return -1; 199} 200 201int 202Android_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 } 211 return 0; 212 } 213 214 return -1; 215} 216 217int 218Android_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 229int 230Android_OnHat(int device_id, int hat_id, int x, int y) 231{ 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} 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 250int 251Android_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 256 SDL_Event event; 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 SDL_Log("Added joystick %s with device_id %d", name, device_id); 315 316 return numjoysticks; 317} 318 319int 320Android_RemoveJoystick(int device_id) 321{ 322 SDL_joylist_item *item = SDL_joylist; 323 SDL_joylist_item *prev = NULL; 324#if !SDL_EVENTS_DISABLED 325 SDL_Event event; 326#endif 327 328 /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */ 329 while (item != NULL) { 330 if (item->device_id == device_id) { 331 break; 332 } 333 prev = item; 334 item = item->next; 335 } 336 337 if (item == NULL) { 338 return -1; 339 } 340 341 const int retval = item->device_instance; 342 if (item->joystick) { 343 item->joystick->hwdata = NULL; 344 } 345 346 if (prev != NULL) { 347 prev->next = item->next; 348 } else { 349 SDL_assert(SDL_joylist == item); 350 SDL_joylist = item->next; 351 } 352 if (item == SDL_joylist_tail) { 353 SDL_joylist_tail = prev; 354 } 355 356 /* Need to decrement the joystick count before we post the event */ 357 --numjoysticks; 358 359#if !SDL_EVENTS_DISABLED 360 event.type = SDL_JOYDEVICEREMOVED; 361 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); 367 } 368 } 369#endif /* !SDL_EVENTS_DISABLED */ 370 371 SDL_Log("Removed joystick with device_id %d", device_id); 372 373 SDL_free(item->name); 374 SDL_free(item); 375 return retval; 376} 377 378 379int 380SDL_SYS_JoystickInit(void) 381{ 382 const char *hint; 383 SDL_SYS_JoystickDetect(); 384 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); 389 } 390 391 return (numjoysticks); 392 393} 394 395int SDL_SYS_NumJoysticks() 396{ 397 return numjoysticks; 398} 399 400void SDL_SYS_JoystickDetect() 401{ 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 405 */ 406 static Uint32 timeout = 0; 407 if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) { 408 timeout = SDL_GetTicks() + 3000; 409 Android_JNI_PollInputDevices(); 410 } 411} 412 413static SDL_joylist_item * 414JoystickByDevIndex(int device_index) 415{ 416 SDL_joylist_item *item = SDL_joylist; 417 418 if ((device_index < 0) || (device_index >= numjoysticks)) { 419 return NULL; 420 } 421 422 while (device_index > 0) { 423 SDL_assert(item != NULL); 424 device_index--; 425 item = item->next; 426 } 427 428 return item; 429} 430 431static SDL_joylist_item * 432JoystickByDeviceId(int device_id) 433{ 434 SDL_joylist_item *item = SDL_joylist; 435 436 while (item != NULL) { 437 if (item->device_id == device_id) { 438 return item; 439 } 440 item = item->next; 441 } 442 443 /* Joystick not found, try adding it */ 444 SDL_SYS_JoystickDetect(); 445 446 while (item != NULL) { 447 if (item->device_id == device_id) { 448 return item; 449 } 450 item = item->next; 451 } 452 453 return NULL; 454} 455 456/* Function to get the device-dependent name of a joystick */ 457const char * 458SDL_SYS_JoystickNameForDeviceIndex(int device_index) 459{ 460 return JoystickByDevIndex(device_index)->name; 461} 462 463/* Function to perform the mapping from device index to the instance id for this index */ 464SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) 465{ 466 return JoystickByDevIndex(device_index)->device_instance; 467} 468 469/* Function to open a joystick for use. 470 The joystick to open is specified by the index field of the joystick. 471 This should fill the nbuttons and naxes fields of the joystick structure. 472 It returns 0, or -1 if there is an error. 473 */ 474int 475SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) 476{ 477 SDL_joylist_item *item = JoystickByDevIndex(device_index); 478 479 if (item == NULL ) { 480 return SDL_SetError("No such device"); 481 } 482 483 if (item->joystick != NULL) { 484 return SDL_SetError("Joystick already opened"); 485 } 486 487 joystick->instance_id = item->device_instance; 488 joystick->hwdata = (struct joystick_hwdata *) item; 489 item->joystick = joystick; 490 joystick->nhats = item->nhats; 491 joystick->nballs = item->nballs; 492 joystick->nbuttons = item->nbuttons; 493 joystick->naxes = item->naxes; 494 495 return (0); 496} 497 498/* Function to determine is this joystick is attached to the system right now */ 499SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) 500{ 501 return !joystick->closed && (joystick->hwdata != NULL); 502} 503 504void 505SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) 506{ 507 int i; 508 Sint16 value; 509 float values[3]; 510 SDL_joylist_item *item = SDL_joylist; 511 512 while (item) { 513 if (item->is_accelerometer) { 514 if (item->joystick) { 515 if (Android_JNI_GetAccelerometerValues(values)) { 516 for ( i = 0; i < 3; i++ ) { 517 value = (Sint16)(values[i] * 32767.0f); 518 SDL_PrivateJoystickAxis(item->joystick, i, value); 519 } 520 } 521 } 522 break; 523 } 524 item = item->next; 525 } 526} 527 528/* Function to close a joystick after use */ 529void 530SDL_SYS_JoystickClose(SDL_Joystick * joystick) 531{ 532 if (joystick->hwdata) { 533 ((SDL_joylist_item*)joystick->hwdata)->joystick = NULL; 534 joystick->hwdata = NULL; 535 } 536 joystick->closed = 1; 537} 538 539/* Function to perform any system-specific joystick related cleanup */ 540void 541SDL_SYS_JoystickQuit(void) 542{ 543 SDL_joylist_item *item = NULL; 544 SDL_joylist_item *next = NULL; 545 546 for (item = SDL_joylist; item; item = next) { 547 next = item->next; 548 SDL_free(item->name); 549 SDL_free(item); 550 } 551 552 SDL_joylist = SDL_joylist_tail = NULL; 553 554 numjoysticks = 0; 555 instance_counter = 0; 556} 557 558SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) 559{ 560 return JoystickByDevIndex(device_index)->guid; 561} 562 563SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) 564{ 565 SDL_JoystickGUID guid; 566 567 if (joystick->hwdata != NULL) { 568 return ((SDL_joylist_item*)joystick->hwdata)->guid; 569 } 570 571 SDL_zero(guid); 572 return guid; 573} 574 575#endif /* SDL_JOYSTICK_ANDROID */ 576 577/* vi: set ts=4 sw=4 expandtab: */