src/joystick/android/SDL_sysjoystick.c
author Gabriel Jacobo <gabomdq@gmail.com>
Tue, 10 Dec 2013 16:24:11 -0300
changeset 8057 801d84e26f91
parent 8025 a867f1891d2a
child 8060 d1948d163145
permissions -rw-r--r--
[Android] Hotplugging support for joysticks
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.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_sysjoystick_c.h"
    38 #include "../SDL_joystick_c.h"
    39 #include "../../core/android/SDL_android.h"
    40 
    41 #include "android/keycodes.h"
    42 
    43 /* As of platform android-14, android/keycodes.h is missing these defines */
    44 #ifndef AKEYCODE_BUTTON_1
    45 #define AKEYCODE_BUTTON_1 188
    46 #define AKEYCODE_BUTTON_2 189
    47 #define AKEYCODE_BUTTON_3 190
    48 #define AKEYCODE_BUTTON_4 191
    49 #define AKEYCODE_BUTTON_5 192
    50 #define AKEYCODE_BUTTON_6 193
    51 #define AKEYCODE_BUTTON_7 194
    52 #define AKEYCODE_BUTTON_8 195
    53 #define AKEYCODE_BUTTON_9 196
    54 #define AKEYCODE_BUTTON_10 197
    55 #define AKEYCODE_BUTTON_11 198
    56 #define AKEYCODE_BUTTON_12 199
    57 #define AKEYCODE_BUTTON_13 200
    58 #define AKEYCODE_BUTTON_14 201
    59 #define AKEYCODE_BUTTON_15 202
    60 #define AKEYCODE_BUTTON_16 203
    61 #endif
    62 
    63 #define ANDROID_ACCELEROMETER_NAME "Android Accelerometer"
    64 #define ANDROID_ACCELEROMETER_DEVICE_ID INT_MIN
    65 #define ANDROID_MAX_NBUTTONS 36
    66 
    67 static SDL_joylist_item * JoystickByDeviceId(int device_id);
    68 
    69 static SDL_joylist_item *SDL_joylist = NULL;
    70 static SDL_joylist_item *SDL_joylist_tail = NULL;
    71 static int numjoysticks = 0;
    72 static int instance_counter = 0;
    73 
    74 
    75 /* Function to convert Android keyCodes into SDL ones.
    76  * This code manipulation is done to get a sequential list of codes.
    77  * FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
    78  */
    79 static int
    80 keycode_to_SDL(int keycode)
    81 {
    82     /* FIXME: If this function gets too unwiedly in the future, replace with a lookup table */
    83     int button = 0;
    84     switch(keycode) 
    85     {
    86         /* D-Pad key codes (API 1), these get mapped to 0...4 */
    87         case AKEYCODE_DPAD_UP:
    88         case AKEYCODE_DPAD_DOWN:
    89         case AKEYCODE_DPAD_LEFT:
    90         case AKEYCODE_DPAD_RIGHT:
    91         case AKEYCODE_DPAD_CENTER:
    92             button = keycode - AKEYCODE_DPAD_UP;
    93             break;
    94         
    95         /* Some gamepad buttons (API 9), these get mapped to 5...19*/
    96         case AKEYCODE_BUTTON_A:
    97         case AKEYCODE_BUTTON_B:
    98         case AKEYCODE_BUTTON_C:
    99         case AKEYCODE_BUTTON_X:
   100         case AKEYCODE_BUTTON_Y:
   101         case AKEYCODE_BUTTON_Z:
   102         case AKEYCODE_BUTTON_L1:
   103         case AKEYCODE_BUTTON_L2:
   104         case AKEYCODE_BUTTON_R1:
   105         case AKEYCODE_BUTTON_R2:
   106         case AKEYCODE_BUTTON_THUMBL:
   107         case AKEYCODE_BUTTON_THUMBR:
   108         case AKEYCODE_BUTTON_START:
   109         case AKEYCODE_BUTTON_SELECT:
   110         case AKEYCODE_BUTTON_MODE:
   111             button = keycode - AKEYCODE_BUTTON_A + 5;
   112             break;
   113             
   114         
   115         /* More gamepad buttons (API 12), these get mapped to 20...35*/
   116         case AKEYCODE_BUTTON_1:
   117         case AKEYCODE_BUTTON_2:
   118         case AKEYCODE_BUTTON_3:
   119         case AKEYCODE_BUTTON_4:
   120         case AKEYCODE_BUTTON_5:
   121         case AKEYCODE_BUTTON_6:
   122         case AKEYCODE_BUTTON_7:
   123         case AKEYCODE_BUTTON_8:
   124         case AKEYCODE_BUTTON_9:
   125         case AKEYCODE_BUTTON_10:
   126         case AKEYCODE_BUTTON_11:
   127         case AKEYCODE_BUTTON_12:
   128         case AKEYCODE_BUTTON_13:
   129         case AKEYCODE_BUTTON_14:
   130         case AKEYCODE_BUTTON_15:
   131         case AKEYCODE_BUTTON_16:
   132             button = keycode - AKEYCODE_BUTTON_1 + 20;
   133             break;
   134             
   135         default:
   136             return -1;
   137             break;
   138     }
   139     
   140     /* This is here in case future generations, probably with six fingers per hand, 
   141      * happily add new cases up above and forget to update the max number of buttons. 
   142      */
   143     SDL_assert(button < ANDROID_MAX_NBUTTONS);
   144     return button;
   145     
   146 }
   147 
   148 int
   149 Android_OnPadDown(int device_id, int keycode)
   150 {
   151     SDL_joylist_item *item;
   152     int button = keycode_to_SDL(keycode);
   153     if (button >= 0) {
   154         item = JoystickByDeviceId(device_id);
   155         if (item && item->joystick) {
   156             SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
   157         }
   158         return 0;
   159     }
   160     
   161     return -1;
   162 }
   163 
   164 int
   165 Android_OnPadUp(int device_id, int keycode)
   166 {
   167     SDL_joylist_item *item;
   168     int button = keycode_to_SDL(keycode);
   169     if (button >= 0) {
   170         item = JoystickByDeviceId(device_id);
   171         if (item && item->joystick) {
   172             SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED);
   173         }
   174         return 0;
   175     }
   176     
   177     return -1;
   178 }
   179 
   180 int
   181 Android_OnJoy(int device_id, int axis, float value)
   182 {
   183     /* Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] */
   184     SDL_joylist_item *item = JoystickByDeviceId(device_id);
   185     if (item && item->joystick) {
   186         SDL_PrivateJoystickAxis(item->joystick, axis, (Sint16) (32767.*value) );
   187     }
   188     
   189     return 0;
   190 }
   191 
   192 
   193 int
   194 Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
   195 {
   196     SDL_JoystickGUID guid;
   197     SDL_joylist_item *item;
   198 #if !SDL_EVENTS_DISABLED
   199     SDL_Event event;
   200 #endif
   201     
   202     if(JoystickByDeviceId(device_id) != NULL || name == NULL) {
   203         return -1;
   204     }
   205     
   206     /* the GUID is just the first 16 chars of the name for now */
   207     SDL_zero( guid );
   208     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   209 
   210     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
   211     if (item == NULL) {
   212         return -1;
   213     }
   214 
   215     SDL_zerop(item);
   216     item->guid = guid;
   217     item->device_id = device_id;
   218     item->name = SDL_strdup(name);
   219     if ( item->name == NULL ) {
   220          SDL_free(item);
   221          return -1;
   222     }
   223     
   224     item->is_accelerometer = is_accelerometer;
   225     if (nbuttons > -1) {
   226         item->nbuttons = nbuttons;
   227     }
   228     else {
   229         item->nbuttons = ANDROID_MAX_NBUTTONS;
   230     }
   231     item->naxes = naxes;
   232     item->nhats = nhats;
   233     item->nballs = nballs;
   234     item->device_instance = instance_counter++;
   235     if (SDL_joylist_tail == NULL) {
   236         SDL_joylist = SDL_joylist_tail = item;
   237     } else {
   238         SDL_joylist_tail->next = item;
   239         SDL_joylist_tail = item;
   240     }
   241 
   242     /* Need to increment the joystick count before we post the event */
   243     ++numjoysticks;
   244 
   245 #if !SDL_EVENTS_DISABLED
   246     event.type = SDL_JOYDEVICEADDED;
   247 
   248     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   249         event.jdevice.which = (numjoysticks - 1);
   250         if ( (SDL_EventOK == NULL) ||
   251              (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
   252             SDL_PushEvent(&event);
   253         }
   254     }
   255 #endif /* !SDL_EVENTS_DISABLED */
   256 
   257     SDL_Log("Added joystick %s with device_id %d", name, device_id);
   258 
   259     return numjoysticks;
   260 }
   261 
   262 int 
   263 Android_RemoveJoystick(int device_id)
   264 {
   265     SDL_joylist_item *item = SDL_joylist;
   266     SDL_joylist_item *prev = NULL;
   267 #if !SDL_EVENTS_DISABLED
   268     SDL_Event event;
   269 #endif
   270     
   271     /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
   272     while (item != NULL) {
   273         if (item->device_id == device_id) {
   274             break;
   275         }
   276         prev = item;
   277         item = item->next;
   278     }
   279     
   280     if (item == NULL) {
   281         return -1;
   282     }
   283 
   284     const int retval = item->device_instance;
   285     if (prev != NULL) {
   286         prev->next = item->next;
   287     } else {
   288         SDL_assert(SDL_joylist == item);
   289         SDL_joylist = item->next;
   290     }
   291     if (item == SDL_joylist_tail) {
   292         SDL_joylist_tail = prev;
   293     }
   294 
   295     /* Need to decrement the joystick count before we post the event */
   296     --numjoysticks;
   297 
   298 #if !SDL_EVENTS_DISABLED
   299     event.type = SDL_JOYDEVICEREMOVED;
   300 
   301     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   302         event.jdevice.which = item->device_instance;
   303         if ( (SDL_EventOK == NULL) ||
   304              (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
   305             SDL_PushEvent(&event);
   306         }
   307     }
   308 #endif /* !SDL_EVENTS_DISABLED */
   309 
   310     SDL_Log("Removed joystick with device_id %d", device_id);
   311     
   312     SDL_free(item->name);
   313     SDL_free(item);
   314     return retval;
   315 }
   316 
   317 
   318 int
   319 SDL_SYS_JoystickInit(void)
   320 {
   321     const char *env;
   322     SDL_SYS_JoystickDetect();
   323     
   324     env = SDL_GetHint(SDL_HINT_ACCEL_AS_JOY);
   325     if (!env || SDL_atoi(env)) {
   326         /* Default behavior, accelerometer as joystick */
   327         Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
   328     }
   329    
   330     return (numjoysticks);
   331 
   332 }
   333 
   334 int SDL_SYS_NumJoysticks()
   335 {
   336     return numjoysticks;
   337 }
   338 
   339 void SDL_SYS_JoystickDetect()
   340 {
   341     /* Support for device connect/disconnect is API >= 16 only,
   342      * so we have to poll ever few seconds.
   343      * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
   344      */
   345     Android_JNI_PollInputDevices();   
   346 }
   347 
   348 SDL_bool SDL_SYS_JoystickNeedsPolling()
   349 {
   350     return SDL_TRUE;
   351 }
   352 
   353 static SDL_joylist_item *
   354 JoystickByDevIndex(int device_index)
   355 {
   356     SDL_joylist_item *item = SDL_joylist;
   357 
   358     if ((device_index < 0) || (device_index >= numjoysticks)) {
   359         return NULL;
   360     }
   361 
   362     while (device_index > 0) {
   363         SDL_assert(item != NULL);
   364         device_index--;
   365         item = item->next;
   366     }
   367 
   368     return item;
   369 }
   370 
   371 static SDL_joylist_item *
   372 JoystickByDeviceId(int device_id)
   373 {
   374     SDL_joylist_item *item = SDL_joylist;
   375 
   376     while (item != NULL) {
   377         if (item->device_id == device_id) {
   378             return item;
   379         }
   380         item = item->next;
   381     }
   382     
   383     /* Joystick not found, try adding it */
   384     SDL_SYS_JoystickDetect();
   385     
   386     while (item != NULL) {
   387         if (item->device_id == device_id) {
   388             return item;
   389         }
   390         item = item->next;
   391     }
   392 
   393     return NULL;
   394 }
   395 
   396 /* Function to get the device-dependent name of a joystick */
   397 const char *
   398 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   399 {
   400     return JoystickByDevIndex(device_index)->name;
   401 }
   402 
   403 /* Function to perform the mapping from device index to the instance id for this index */
   404 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   405 {
   406     return JoystickByDevIndex(device_index)->device_instance;
   407 }
   408 
   409 /* Function to open a joystick for use.
   410    The joystick to open is specified by the index field of the joystick.
   411    This should fill the nbuttons and naxes fields of the joystick structure.
   412    It returns 0, or -1 if there is an error.
   413  */
   414 int
   415 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   416 {
   417     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   418     char *fname = NULL;
   419 
   420     if (item == NULL ) {
   421         return SDL_SetError("No such device");
   422     }
   423     
   424     if (item->joystick != NULL) {
   425         return SDL_SetError("Joystick already opened");
   426     }
   427 
   428     joystick->instance_id = item->device_instance;
   429     joystick->hwdata = (struct joystick_hwdata *) item;
   430     item->joystick = joystick;
   431     joystick->nhats = item->nhats;
   432     joystick->nballs = item->nballs;
   433     joystick->nbuttons = item->nbuttons;
   434     joystick->naxes = item->naxes;
   435 
   436     return (0);
   437 }
   438 
   439 /* Function to determine is this joystick is attached to the system right now */
   440 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   441 {
   442     return !joystick->closed && (joystick->hwdata != NULL);
   443 }
   444 
   445 void
   446 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   447 {
   448     int i;
   449     Sint16 value;
   450     float values[3];
   451     SDL_joylist_item *item = SDL_joylist;
   452 
   453     while (item) {
   454         if (item->is_accelerometer) {
   455             if (item->joystick) {
   456                 Android_JNI_GetAccelerometerValues(values);
   457                 for ( i = 0; i < 3; i++ ) {
   458                     value = (Sint16)(values[i] * 32767.0f);
   459                     SDL_PrivateJoystickAxis(item->joystick, i, value);
   460                 }
   461             }
   462             break;
   463         }
   464         item = item->next;
   465     }
   466 }
   467 
   468 /* Function to close a joystick after use */
   469 void
   470 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   471 {
   472     if (joystick->hwdata) {
   473         ((SDL_joylist_item*)joystick->hwdata)->joystick = NULL;
   474         joystick->hwdata = NULL;
   475     }
   476     joystick->closed = 1;
   477 }
   478 
   479 /* Function to perform any system-specific joystick related cleanup */
   480 void
   481 SDL_SYS_JoystickQuit(void)
   482 {
   483     SDL_joylist_item *item = NULL;
   484     SDL_joylist_item *next = NULL;
   485 
   486     for (item = SDL_joylist; item; item = next) {
   487         next = item->next;
   488         SDL_free(item->name);
   489         SDL_free(item);
   490     }
   491 
   492     SDL_joylist = SDL_joylist_tail = NULL;
   493 
   494     numjoysticks = 0;
   495     instance_counter = 0;
   496 }
   497 
   498 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   499 {
   500     return JoystickByDevIndex(device_index)->guid;
   501 }
   502 
   503 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   504 {
   505     return ((SDL_joylist_item*)joystick->hwdata)->guid;
   506 }
   507 
   508 #endif /* SDL_JOYSTICK_ANDROID */
   509 
   510 /* vi: set ts=4 sw=4 expandtab: */