src/joystick/android/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 16 Dec 2017 10:40:43 -0800
changeset 11778 db38a635e2c6
parent 11671 3dc400fafd76
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Added support for the ASUS TV500BG Android gamepad
     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 #include "../steam/SDL_steamcontroller.h"
    39 
    40 #include "android/keycodes.h"
    41 
    42 /* As of platform android-14, android/keycodes.h is missing these defines */
    43 #ifndef AKEYCODE_BUTTON_1
    44 #define AKEYCODE_BUTTON_1 188
    45 #define AKEYCODE_BUTTON_2 189
    46 #define AKEYCODE_BUTTON_3 190
    47 #define AKEYCODE_BUTTON_4 191
    48 #define AKEYCODE_BUTTON_5 192
    49 #define AKEYCODE_BUTTON_6 193
    50 #define AKEYCODE_BUTTON_7 194
    51 #define AKEYCODE_BUTTON_8 195
    52 #define AKEYCODE_BUTTON_9 196
    53 #define AKEYCODE_BUTTON_10 197
    54 #define AKEYCODE_BUTTON_11 198
    55 #define AKEYCODE_BUTTON_12 199
    56 #define AKEYCODE_BUTTON_13 200
    57 #define AKEYCODE_BUTTON_14 201
    58 #define AKEYCODE_BUTTON_15 202
    59 #define AKEYCODE_BUTTON_16 203
    60 #endif
    61 
    62 #define ANDROID_ACCELEROMETER_NAME "Android Accelerometer"
    63 #define ANDROID_ACCELEROMETER_DEVICE_ID INT_MIN
    64 #define ANDROID_MAX_NBUTTONS 36
    65 
    66 static SDL_joylist_item * JoystickByDeviceId(int device_id);
    67 
    68 static SDL_joylist_item *SDL_joylist = NULL;
    69 static SDL_joylist_item *SDL_joylist_tail = NULL;
    70 static int numjoysticks = 0;
    71 static int instance_counter = 0;
    72 
    73 
    74 /* Function to convert Android keyCodes into SDL ones.
    75  * This code manipulation is done to get a sequential list of codes.
    76  * FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
    77  */
    78 static int
    79 keycode_to_SDL(int keycode)
    80 {
    81     /* FIXME: If this function gets too unwieldy in the future, replace with a lookup table */
    82     int button = 0;
    83     switch(keycode) 
    84     {
    85         /* Some gamepad buttons (API 9) */
    86         case AKEYCODE_BUTTON_A:
    87             button = SDL_CONTROLLER_BUTTON_A;
    88             break;
    89         case AKEYCODE_BUTTON_B:
    90             button = SDL_CONTROLLER_BUTTON_B;
    91             break;
    92         case AKEYCODE_BUTTON_X:
    93             button = SDL_CONTROLLER_BUTTON_X;
    94             break;
    95         case AKEYCODE_BUTTON_Y:
    96             button = SDL_CONTROLLER_BUTTON_Y;
    97             break;
    98         case AKEYCODE_BUTTON_L1:
    99             button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
   100             break;
   101         case AKEYCODE_BUTTON_R1:
   102             button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
   103             break;
   104         case AKEYCODE_BUTTON_THUMBL:
   105             button = SDL_CONTROLLER_BUTTON_LEFTSTICK;
   106             break;
   107         case AKEYCODE_BUTTON_THUMBR:
   108             button = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
   109             break;
   110         case AKEYCODE_BUTTON_START:
   111             button = SDL_CONTROLLER_BUTTON_START;
   112             break;
   113         case AKEYCODE_BACK:
   114         case AKEYCODE_BUTTON_SELECT:
   115             button = SDL_CONTROLLER_BUTTON_BACK;
   116             break;
   117         case AKEYCODE_BUTTON_MODE:
   118             button = SDL_CONTROLLER_BUTTON_GUIDE;
   119             break;
   120         case AKEYCODE_BUTTON_L2:
   121             button = SDL_CONTROLLER_BUTTON_MAX; /* Not supported by GameController */
   122             break;
   123         case AKEYCODE_BUTTON_R2:
   124             button = SDL_CONTROLLER_BUTTON_MAX+1; /* Not supported by GameController */
   125             break;
   126         case AKEYCODE_BUTTON_C:
   127             button = SDL_CONTROLLER_BUTTON_MAX+2; /* Not supported by GameController */
   128             break;
   129         case AKEYCODE_BUTTON_Z:
   130             button = SDL_CONTROLLER_BUTTON_MAX+3; /* Not supported by GameController */
   131             break;
   132                         
   133         /* D-Pad key codes (API 1) */
   134         case AKEYCODE_DPAD_UP:
   135             button = SDL_CONTROLLER_BUTTON_DPAD_UP;
   136             break;
   137         case AKEYCODE_DPAD_DOWN:
   138             button = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
   139             break;
   140         case AKEYCODE_DPAD_LEFT:
   141             button = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
   142             break;
   143         case AKEYCODE_DPAD_RIGHT:
   144             button = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
   145             break;
   146         case AKEYCODE_DPAD_CENTER:
   147             /* This is handled better by applications as the A button */
   148             /*button = SDL_CONTROLLER_BUTTON_MAX+4; /* Not supported by GameController */
   149             button = SDL_CONTROLLER_BUTTON_A;
   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; -Wunreachable-code-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         }
   195         return 0;
   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         }
   211         return 0;
   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] = {
   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 
   250 int
   251 Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
   252 {
   253     SDL_JoystickGUID guid;
   254     SDL_joylist_item *item;
   255     
   256     if(JoystickByDeviceId(device_id) != NULL || name == NULL) {
   257         return -1;
   258     }
   259     
   260     /* the GUID is just the first 16 chars of the name for now */
   261     SDL_zero(guid);
   262     SDL_memcpy(&guid, desc, SDL_min(sizeof(guid), SDL_strlen(desc)));
   263 
   264     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
   265     if (item == NULL) {
   266         return -1;
   267     }
   268 
   269     SDL_zerop(item);
   270     item->guid = guid;
   271     item->device_id = device_id;
   272     item->name = SDL_strdup(name);
   273     if (item->name == NULL) {
   274          SDL_free(item);
   275          return -1;
   276     }
   277     
   278     item->is_accelerometer = is_accelerometer;
   279     if (nbuttons > -1) {
   280         item->nbuttons = nbuttons;
   281     }
   282     else {
   283         item->nbuttons = ANDROID_MAX_NBUTTONS;
   284     }
   285     item->naxes = naxes;
   286     item->nhats = nhats;
   287     item->nballs = nballs;
   288     item->device_instance = instance_counter++;
   289     if (SDL_joylist_tail == NULL) {
   290         SDL_joylist = SDL_joylist_tail = item;
   291     } else {
   292         SDL_joylist_tail->next = item;
   293         SDL_joylist_tail = item;
   294     }
   295 
   296     /* Need to increment the joystick count before we post the event */
   297     ++numjoysticks;
   298 
   299     SDL_PrivateJoystickAdded(numjoysticks - 1);
   300 
   301 #ifdef DEBUG_JOYSTICK
   302     SDL_Log("Added joystick %s with device_id %d", name, device_id);
   303 #endif
   304 
   305     return numjoysticks;
   306 }
   307 
   308 int 
   309 Android_RemoveJoystick(int device_id)
   310 {
   311     SDL_joylist_item *item = SDL_joylist;
   312     SDL_joylist_item *prev = NULL;
   313     
   314     /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
   315     while (item != NULL) {
   316         if (item->device_id == device_id) {
   317             break;
   318         }
   319         prev = item;
   320         item = item->next;
   321     }
   322     
   323     if (item == NULL) {
   324         return -1;
   325     }
   326 
   327     if (item->joystick) {
   328         item->joystick->hwdata = NULL;
   329     }
   330         
   331     if (prev != NULL) {
   332         prev->next = item->next;
   333     } else {
   334         SDL_assert(SDL_joylist == item);
   335         SDL_joylist = item->next;
   336     }
   337     if (item == SDL_joylist_tail) {
   338         SDL_joylist_tail = prev;
   339     }
   340 
   341     /* Need to decrement the joystick count before we post the event */
   342     --numjoysticks;
   343 
   344     SDL_PrivateJoystickRemoved(item->device_instance);
   345 
   346 #ifdef DEBUG_JOYSTICK
   347     SDL_Log("Removed joystick with device_id %d", device_id);
   348 #endif
   349     
   350     SDL_free(item->name);
   351     SDL_free(item);
   352     return numjoysticks;
   353 }
   354 
   355 
   356 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
   357 {
   358     SDL_joylist_item *item;
   359     
   360     item = (SDL_joylist_item *)SDL_calloc(1, sizeof (SDL_joylist_item));
   361     if (item == NULL) {
   362         return SDL_FALSE;
   363     }
   364 
   365     *device_instance = item->device_instance = instance_counter++;
   366     item->device_id = -1;
   367     item->name = SDL_strdup(name);
   368     item->guid = guid;
   369     SDL_GetSteamControllerInputs(&item->nbuttons,
   370                                  &item->naxes,
   371                                  &item->nhats);
   372     item->m_bSteamController = SDL_TRUE;
   373 
   374     if (SDL_joylist_tail == NULL) {
   375         SDL_joylist = SDL_joylist_tail = item;
   376     } else {
   377         SDL_joylist_tail->next = item;
   378         SDL_joylist_tail = item;
   379     }
   380 
   381     /* Need to increment the joystick count before we post the event */
   382     ++numjoysticks;
   383 
   384     SDL_PrivateJoystickAdded(numjoysticks - 1);
   385 
   386     return SDL_TRUE;
   387 }
   388 
   389 static void SteamControllerDisconnectedCallback(int device_instance)
   390 {
   391     SDL_joylist_item *item = SDL_joylist;
   392     SDL_joylist_item *prev = NULL;
   393     
   394     while (item != NULL) {
   395         if (item->device_instance == device_instance) {
   396             break;
   397         }
   398         prev = item;
   399         item = item->next;
   400     }
   401     
   402     if (item == NULL) {
   403         return;
   404     }
   405 
   406     if (item->joystick) {
   407         item->joystick->hwdata = NULL;
   408     }
   409         
   410     if (prev != NULL) {
   411         prev->next = item->next;
   412     } else {
   413         SDL_assert(SDL_joylist == item);
   414         SDL_joylist = item->next;
   415     }
   416     if (item == SDL_joylist_tail) {
   417         SDL_joylist_tail = prev;
   418     }
   419 
   420     /* Need to decrement the joystick count before we post the event */
   421     --numjoysticks;
   422 
   423     SDL_PrivateJoystickRemoved(item->device_instance);
   424 
   425     SDL_free(item->name);
   426     SDL_free(item);
   427 }
   428 
   429 int
   430 SDL_SYS_JoystickInit(void)
   431 {
   432     SDL_SYS_JoystickDetect();
   433     
   434     if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
   435         /* Default behavior, accelerometer as joystick */
   436         Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
   437     }
   438    
   439     SDL_InitSteamControllers(SteamControllerConnectedCallback,
   440                              SteamControllerDisconnectedCallback);
   441 
   442     return (numjoysticks);
   443 
   444 }
   445 
   446 int
   447 SDL_SYS_NumJoysticks(void)
   448 {
   449     return numjoysticks;
   450 }
   451 
   452 void
   453 SDL_SYS_JoystickDetect(void)
   454 {
   455     /* Support for device connect/disconnect is API >= 16 only,
   456      * so we poll every three seconds
   457      * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
   458      */
   459     static Uint32 timeout = 0;
   460     if (!timeout || SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
   461         timeout = SDL_GetTicks() + 3000;
   462         Android_JNI_PollInputDevices();
   463     }
   464 
   465     SDL_UpdateSteamControllers();
   466 }
   467 
   468 static SDL_joylist_item *
   469 JoystickByDevIndex(int device_index)
   470 {
   471     SDL_joylist_item *item = SDL_joylist;
   472 
   473     if ((device_index < 0) || (device_index >= numjoysticks)) {
   474         return NULL;
   475     }
   476 
   477     while (device_index > 0) {
   478         SDL_assert(item != NULL);
   479         device_index--;
   480         item = item->next;
   481     }
   482 
   483     return item;
   484 }
   485 
   486 static SDL_joylist_item *
   487 JoystickByDeviceId(int device_id)
   488 {
   489     SDL_joylist_item *item = SDL_joylist;
   490 
   491     while (item != NULL) {
   492         if (item->device_id == device_id) {
   493             return item;
   494         }
   495         item = item->next;
   496     }
   497     
   498     /* Joystick not found, try adding it */
   499     SDL_SYS_JoystickDetect();
   500     
   501     while (item != NULL) {
   502         if (item->device_id == device_id) {
   503             return item;
   504         }
   505         item = item->next;
   506     }
   507 
   508     return NULL;
   509 }
   510 
   511 /* Function to get the device-dependent name of a joystick */
   512 const char *
   513 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   514 {
   515     return JoystickByDevIndex(device_index)->name;
   516 }
   517 
   518 /* Function to perform the mapping from device index to the instance id for this index */
   519 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   520 {
   521     return JoystickByDevIndex(device_index)->device_instance;
   522 }
   523 
   524 /* Function to open a joystick for use.
   525    The joystick to open is specified by the device index.
   526    This should fill the nbuttons and naxes fields of the joystick structure.
   527    It returns 0, or -1 if there is an error.
   528  */
   529 int
   530 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   531 {
   532     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   533 
   534     if (item == NULL) {
   535         return SDL_SetError("No such device");
   536     }
   537     
   538     if (item->joystick != NULL) {
   539         return SDL_SetError("Joystick already opened");
   540     }
   541 
   542     joystick->instance_id = item->device_instance;
   543     joystick->hwdata = (struct joystick_hwdata *) item;
   544     item->joystick = joystick;
   545     joystick->nhats = item->nhats;
   546     joystick->nballs = item->nballs;
   547     joystick->nbuttons = item->nbuttons;
   548     joystick->naxes = item->naxes;
   549 
   550     return (0);
   551 }
   552 
   553 /* Function to determine if this joystick is attached to the system right now */
   554 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   555 {
   556     return joystick->hwdata != NULL;
   557 }
   558 
   559 void
   560 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   561 {
   562     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
   563 
   564     if (item == NULL) {
   565         return;
   566     }
   567  
   568     if (item->m_bSteamController) {
   569         SDL_UpdateSteamController(joystick);
   570         return;
   571     }
   572 
   573     if (item->is_accelerometer) {
   574         int i;
   575         Sint16 value;
   576         float values[3];
   577 
   578         if (Android_JNI_GetAccelerometerValues(values)) {
   579             for (i = 0; i < 3; i++) {
   580                 if (values[i] > 1.0f) {
   581                     values[i] = 1.0f;
   582                 } else if (values[i] < -1.0f) {
   583                     values[i] = -1.0f;
   584                 }
   585 
   586                 value = (Sint16)(values[i] * 32767.0f);
   587                 SDL_PrivateJoystickAxis(item->joystick, i, value);
   588             }
   589         }
   590     }
   591 }
   592 
   593 /* Function to close a joystick after use */
   594 void
   595 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   596 {
   597     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
   598     if (item) {
   599         item->joystick = NULL;
   600     }
   601 }
   602 
   603 /* Function to perform any system-specific joystick related cleanup */
   604 void
   605 SDL_SYS_JoystickQuit(void)
   606 {
   607 /* We don't have any way to scan for joysticks at init, so don't wipe the list
   608  * of joysticks here in case this is a reinit.
   609  */
   610 #if 0
   611     SDL_joylist_item *item = NULL;
   612     SDL_joylist_item *next = NULL;
   613 
   614     for (item = SDL_joylist; item; item = next) {
   615         next = item->next;
   616         SDL_free(item->name);
   617         SDL_free(item);
   618     }
   619 
   620     SDL_joylist = SDL_joylist_tail = NULL;
   621 
   622     numjoysticks = 0;
   623     instance_counter = 0;
   624 #endif /* 0 */
   625 
   626     SDL_QuitSteamControllers();
   627 }
   628 
   629 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
   630 {
   631     return JoystickByDevIndex(device_index)->guid;
   632 }
   633 
   634 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   635 {
   636     SDL_JoystickGUID guid;
   637     
   638     if (joystick->hwdata != NULL) {
   639         return ((SDL_joylist_item*)joystick->hwdata)->guid;
   640     }
   641     
   642     SDL_zero(guid);
   643     return guid;
   644 }
   645 
   646 SDL_bool SDL_SYS_IsDPAD_DeviceIndex(int device_index)
   647 {
   648     return JoystickByDevIndex(device_index)->naxes == 0;
   649 }
   650 
   651 #endif /* SDL_JOYSTICK_ANDROID */
   652 
   653 /* vi: set ts=4 sw=4 expandtab: */