src/joystick/android/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 02 Nov 2017 08:48:14 -0700
changeset 11671 3dc400fafd76
parent 11663 0d96acbd34f0
child 11778 db38a635e2c6
permissions -rw-r--r--
Fixed bug 3935 - Not find joysticks if android run 24-48 days.

Alexander Orefkov

In src\joystick\android\SDL_sysjoystick.c in SDL_SYS_JoystickDetect when SDL_GetTicks return number grater 2147483648 (after 24.85 days uptime) SDL_TICKS_PASSED(SDL_GetTicks(), timeout) return FALSE and Android_JNI_PollInputDevices is never calling.
And in JoystickByDeviceId - when search for newly added joystic - after SDL_SYS_JoystickDetect item not reinitilized, and always stay NULL, cause return NULL instead of added joystick.
     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 unwiedly 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_BUTTON_SELECT:
   114             button = SDL_CONTROLLER_BUTTON_BACK;
   115             break;
   116         case AKEYCODE_BUTTON_MODE:
   117             button = SDL_CONTROLLER_BUTTON_GUIDE;
   118             break;
   119         case AKEYCODE_BUTTON_L2:
   120             button = SDL_CONTROLLER_BUTTON_MAX; /* Not supported by GameController */
   121             break;
   122         case AKEYCODE_BUTTON_R2:
   123             button = SDL_CONTROLLER_BUTTON_MAX+1; /* Not supported by GameController */
   124             break;
   125         case AKEYCODE_BUTTON_C:
   126             button = SDL_CONTROLLER_BUTTON_MAX+2; /* Not supported by GameController */
   127             break;
   128         case AKEYCODE_BUTTON_Z:
   129             button = SDL_CONTROLLER_BUTTON_MAX+3; /* Not supported by GameController */
   130             break;
   131                         
   132         /* D-Pad key codes (API 1) */
   133         case AKEYCODE_DPAD_UP:
   134             button = SDL_CONTROLLER_BUTTON_DPAD_UP;
   135             break;
   136         case AKEYCODE_DPAD_DOWN:
   137             button = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
   138             break;
   139         case AKEYCODE_DPAD_LEFT:
   140             button = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
   141             break;
   142         case AKEYCODE_DPAD_RIGHT:
   143             button = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
   144             break;
   145         case AKEYCODE_DPAD_CENTER:
   146             /* This is handled better by applications as the A button */
   147             /*button = SDL_CONTROLLER_BUTTON_MAX+4; /* Not supported by GameController */
   148             button = SDL_CONTROLLER_BUTTON_A;
   149             break;
   150 
   151         case AKEYCODE_BACK:
   152             button = SDL_CONTROLLER_BUTTON_B;
   153             break;
   154 
   155         /* More gamepad buttons (API 12), these get mapped to 20...35*/
   156         case AKEYCODE_BUTTON_1:
   157         case AKEYCODE_BUTTON_2:
   158         case AKEYCODE_BUTTON_3:
   159         case AKEYCODE_BUTTON_4:
   160         case AKEYCODE_BUTTON_5:
   161         case AKEYCODE_BUTTON_6:
   162         case AKEYCODE_BUTTON_7:
   163         case AKEYCODE_BUTTON_8:
   164         case AKEYCODE_BUTTON_9:
   165         case AKEYCODE_BUTTON_10:
   166         case AKEYCODE_BUTTON_11:
   167         case AKEYCODE_BUTTON_12:
   168         case AKEYCODE_BUTTON_13:
   169         case AKEYCODE_BUTTON_14:
   170         case AKEYCODE_BUTTON_15:
   171         case AKEYCODE_BUTTON_16:
   172             button = keycode - AKEYCODE_BUTTON_1 + SDL_CONTROLLER_BUTTON_MAX + 5;
   173             break;
   174             
   175         default:
   176             return -1;
   177             /* break; -Wunreachable-code-break */
   178     }
   179     
   180     /* This is here in case future generations, probably with six fingers per hand, 
   181      * happily add new cases up above and forget to update the max number of buttons. 
   182      */
   183     SDL_assert(button < ANDROID_MAX_NBUTTONS);
   184     return button;
   185     
   186 }
   187 
   188 int
   189 Android_OnPadDown(int device_id, int keycode)
   190 {
   191     SDL_joylist_item *item;
   192     int button = keycode_to_SDL(keycode);
   193     if (button >= 0) {
   194         item = JoystickByDeviceId(device_id);
   195         if (item && item->joystick) {
   196             SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
   197         }
   198         return 0;
   199     }
   200     
   201     return -1;
   202 }
   203 
   204 int
   205 Android_OnPadUp(int device_id, int keycode)
   206 {
   207     SDL_joylist_item *item;
   208     int button = keycode_to_SDL(keycode);
   209     if (button >= 0) {
   210         item = JoystickByDeviceId(device_id);
   211         if (item && item->joystick) {
   212             SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED);
   213         }
   214         return 0;
   215     }
   216     
   217     return -1;
   218 }
   219 
   220 int
   221 Android_OnJoy(int device_id, int axis, float value)
   222 {
   223     /* Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] */
   224     SDL_joylist_item *item = JoystickByDeviceId(device_id);
   225     if (item && item->joystick) {
   226         SDL_PrivateJoystickAxis(item->joystick, axis, (Sint16) (32767.*value));
   227     }
   228     
   229     return 0;
   230 }
   231 
   232 int
   233 Android_OnHat(int device_id, int hat_id, int x, int y)
   234 {
   235     const Uint8 position_map[3][3] = {
   236         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   237         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   238         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   239     };
   240 
   241     if (x >= -1 && x <=1 && y >= -1 && y <= 1) {
   242         SDL_joylist_item *item = JoystickByDeviceId(device_id);
   243         if (item && item->joystick) {
   244             SDL_PrivateJoystickHat(item->joystick, hat_id, position_map[y+1][x+1]);
   245         }
   246         return 0;
   247     }
   248 
   249     return -1;
   250 }
   251 
   252 
   253 int
   254 Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
   255 {
   256     SDL_JoystickGUID guid;
   257     SDL_joylist_item *item;
   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, desc, SDL_min(sizeof(guid), SDL_strlen(desc)));
   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     SDL_PrivateJoystickAdded(numjoysticks - 1);
   303 
   304 #ifdef DEBUG_JOYSTICK
   305     SDL_Log("Added joystick %s with device_id %d", name, device_id);
   306 #endif
   307 
   308     return numjoysticks;
   309 }
   310 
   311 int 
   312 Android_RemoveJoystick(int device_id)
   313 {
   314     SDL_joylist_item *item = SDL_joylist;
   315     SDL_joylist_item *prev = NULL;
   316     
   317     /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
   318     while (item != NULL) {
   319         if (item->device_id == device_id) {
   320             break;
   321         }
   322         prev = item;
   323         item = item->next;
   324     }
   325     
   326     if (item == NULL) {
   327         return -1;
   328     }
   329 
   330     if (item->joystick) {
   331         item->joystick->hwdata = NULL;
   332     }
   333         
   334     if (prev != NULL) {
   335         prev->next = item->next;
   336     } else {
   337         SDL_assert(SDL_joylist == item);
   338         SDL_joylist = item->next;
   339     }
   340     if (item == SDL_joylist_tail) {
   341         SDL_joylist_tail = prev;
   342     }
   343 
   344     /* Need to decrement the joystick count before we post the event */
   345     --numjoysticks;
   346 
   347     SDL_PrivateJoystickRemoved(item->device_instance);
   348 
   349 #ifdef DEBUG_JOYSTICK
   350     SDL_Log("Removed joystick with device_id %d", device_id);
   351 #endif
   352     
   353     SDL_free(item->name);
   354     SDL_free(item);
   355     return numjoysticks;
   356 }
   357 
   358 
   359 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
   360 {
   361     SDL_joylist_item *item;
   362     
   363     item = (SDL_joylist_item *)SDL_calloc(1, sizeof (SDL_joylist_item));
   364     if (item == NULL) {
   365         return SDL_FALSE;
   366     }
   367 
   368     *device_instance = item->device_instance = instance_counter++;
   369     item->device_id = -1;
   370     item->name = SDL_strdup(name);
   371     item->guid = guid;
   372     SDL_GetSteamControllerInputs(&item->nbuttons,
   373                                  &item->naxes,
   374                                  &item->nhats);
   375     item->m_bSteamController = SDL_TRUE;
   376 
   377     if (SDL_joylist_tail == NULL) {
   378         SDL_joylist = SDL_joylist_tail = item;
   379     } else {
   380         SDL_joylist_tail->next = item;
   381         SDL_joylist_tail = item;
   382     }
   383 
   384     /* Need to increment the joystick count before we post the event */
   385     ++numjoysticks;
   386 
   387     SDL_PrivateJoystickAdded(numjoysticks - 1);
   388 
   389     return SDL_TRUE;
   390 }
   391 
   392 static void SteamControllerDisconnectedCallback(int device_instance)
   393 {
   394     SDL_joylist_item *item = SDL_joylist;
   395     SDL_joylist_item *prev = NULL;
   396     
   397     while (item != NULL) {
   398         if (item->device_instance == device_instance) {
   399             break;
   400         }
   401         prev = item;
   402         item = item->next;
   403     }
   404     
   405     if (item == NULL) {
   406         return;
   407     }
   408 
   409     if (item->joystick) {
   410         item->joystick->hwdata = NULL;
   411     }
   412         
   413     if (prev != NULL) {
   414         prev->next = item->next;
   415     } else {
   416         SDL_assert(SDL_joylist == item);
   417         SDL_joylist = item->next;
   418     }
   419     if (item == SDL_joylist_tail) {
   420         SDL_joylist_tail = prev;
   421     }
   422 
   423     /* Need to decrement the joystick count before we post the event */
   424     --numjoysticks;
   425 
   426     SDL_PrivateJoystickRemoved(item->device_instance);
   427 
   428     SDL_free(item->name);
   429     SDL_free(item);
   430 }
   431 
   432 int
   433 SDL_SYS_JoystickInit(void)
   434 {
   435     SDL_SYS_JoystickDetect();
   436     
   437     if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
   438         /* Default behavior, accelerometer as joystick */
   439         Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
   440     }
   441    
   442     SDL_InitSteamControllers(SteamControllerConnectedCallback,
   443                              SteamControllerDisconnectedCallback);
   444 
   445     return (numjoysticks);
   446 
   447 }
   448 
   449 int
   450 SDL_SYS_NumJoysticks(void)
   451 {
   452     return numjoysticks;
   453 }
   454 
   455 void
   456 SDL_SYS_JoystickDetect(void)
   457 {
   458     /* Support for device connect/disconnect is API >= 16 only,
   459      * so we poll every three seconds
   460      * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
   461      */
   462     static Uint32 timeout = 0;
   463     if (!timeout || SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
   464         timeout = SDL_GetTicks() + 3000;
   465         Android_JNI_PollInputDevices();
   466     }
   467 
   468     SDL_UpdateSteamControllers();
   469 }
   470 
   471 static SDL_joylist_item *
   472 JoystickByDevIndex(int device_index)
   473 {
   474     SDL_joylist_item *item = SDL_joylist;
   475 
   476     if ((device_index < 0) || (device_index >= numjoysticks)) {
   477         return NULL;
   478     }
   479 
   480     while (device_index > 0) {
   481         SDL_assert(item != NULL);
   482         device_index--;
   483         item = item->next;
   484     }
   485 
   486     return item;
   487 }
   488 
   489 static SDL_joylist_item *
   490 JoystickByDeviceId(int device_id)
   491 {
   492     SDL_joylist_item *item = SDL_joylist;
   493 
   494     while (item != NULL) {
   495         if (item->device_id == device_id) {
   496             return item;
   497         }
   498         item = item->next;
   499     }
   500     
   501     /* Joystick not found, try adding it */
   502     SDL_SYS_JoystickDetect();
   503     
   504     while (item != NULL) {
   505         if (item->device_id == device_id) {
   506             return item;
   507         }
   508         item = item->next;
   509     }
   510 
   511     return NULL;
   512 }
   513 
   514 /* Function to get the device-dependent name of a joystick */
   515 const char *
   516 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   517 {
   518     return JoystickByDevIndex(device_index)->name;
   519 }
   520 
   521 /* Function to perform the mapping from device index to the instance id for this index */
   522 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   523 {
   524     return JoystickByDevIndex(device_index)->device_instance;
   525 }
   526 
   527 /* Function to open a joystick for use.
   528    The joystick to open is specified by the device index.
   529    This should fill the nbuttons and naxes fields of the joystick structure.
   530    It returns 0, or -1 if there is an error.
   531  */
   532 int
   533 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   534 {
   535     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   536 
   537     if (item == NULL) {
   538         return SDL_SetError("No such device");
   539     }
   540     
   541     if (item->joystick != NULL) {
   542         return SDL_SetError("Joystick already opened");
   543     }
   544 
   545     joystick->instance_id = item->device_instance;
   546     joystick->hwdata = (struct joystick_hwdata *) item;
   547     item->joystick = joystick;
   548     joystick->nhats = item->nhats;
   549     joystick->nballs = item->nballs;
   550     joystick->nbuttons = item->nbuttons;
   551     joystick->naxes = item->naxes;
   552 
   553     return (0);
   554 }
   555 
   556 /* Function to determine if this joystick is attached to the system right now */
   557 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   558 {
   559     return joystick->hwdata != NULL;
   560 }
   561 
   562 void
   563 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   564 {
   565     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
   566 
   567     if (item == NULL) {
   568         return;
   569     }
   570  
   571     if (item->m_bSteamController) {
   572         SDL_UpdateSteamController(joystick);
   573         return;
   574     }
   575 
   576     if (item->is_accelerometer) {
   577         int i;
   578         Sint16 value;
   579         float values[3];
   580 
   581         if (Android_JNI_GetAccelerometerValues(values)) {
   582             for (i = 0; i < 3; i++) {
   583                 if (values[i] > 1.0f) {
   584                     values[i] = 1.0f;
   585                 } else if (values[i] < -1.0f) {
   586                     values[i] = -1.0f;
   587                 }
   588 
   589                 value = (Sint16)(values[i] * 32767.0f);
   590                 SDL_PrivateJoystickAxis(item->joystick, i, value);
   591             }
   592         }
   593     }
   594 }
   595 
   596 /* Function to close a joystick after use */
   597 void
   598 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   599 {
   600     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
   601     if (item) {
   602         item->joystick = NULL;
   603     }
   604 }
   605 
   606 /* Function to perform any system-specific joystick related cleanup */
   607 void
   608 SDL_SYS_JoystickQuit(void)
   609 {
   610 /* We don't have any way to scan for joysticks at init, so don't wipe the list
   611  * of joysticks here in case this is a reinit.
   612  */
   613 #if 0
   614     SDL_joylist_item *item = NULL;
   615     SDL_joylist_item *next = NULL;
   616 
   617     for (item = SDL_joylist; item; item = next) {
   618         next = item->next;
   619         SDL_free(item->name);
   620         SDL_free(item);
   621     }
   622 
   623     SDL_joylist = SDL_joylist_tail = NULL;
   624 
   625     numjoysticks = 0;
   626     instance_counter = 0;
   627 #endif /* 0 */
   628 
   629     SDL_QuitSteamControllers();
   630 }
   631 
   632 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
   633 {
   634     return JoystickByDevIndex(device_index)->guid;
   635 }
   636 
   637 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   638 {
   639     SDL_JoystickGUID guid;
   640     
   641     if (joystick->hwdata != NULL) {
   642         return ((SDL_joylist_item*)joystick->hwdata)->guid;
   643     }
   644     
   645     SDL_zero(guid);
   646     return guid;
   647 }
   648 
   649 SDL_bool SDL_SYS_IsDPAD_DeviceIndex(int device_index)
   650 {
   651     return JoystickByDevIndex(device_index)->naxes == 0;
   652 }
   653 
   654 #endif /* SDL_JOYSTICK_ANDROID */
   655 
   656 /* vi: set ts=4 sw=4 expandtab: */