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