src/joystick/android/SDL_sysjoystick.c
author Gabriel Jacobo <gabomdq@gmail.com>
Tue, 19 Nov 2013 10:00:05 -0300
changeset 8013 109299fe73ad
parent 8008 5e5819ca19db
child 8024 ffbdb99af7bd
permissions -rw-r--r--
[Android] Try to improve handling of DPAD|GAMEPAD + KEYBOARD devices

It seems some devices report themselves as DPAD or GAMEPAD and KEYBOARD as well,
and we need to route different keycodes to different parts of SDL.
     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 /* This is the system specific header for the SDL joystick API */
    27 #include <stdio.h>              /* For the definition of NULL */
    28 
    29 #include "SDL_error.h"
    30 #include "SDL_events.h"
    31 #include "SDL_joystick.h"
    32 #include "SDL_hints.h"
    33 #include "SDL_assert.h"
    34 #include "SDL_log.h"
    35 #include "../SDL_sysjoystick.h"
    36 #include "../SDL_joystick_c.h"
    37 #include "../../core/android/SDL_android.h"
    38 
    39 #include "android/keycodes.h"
    40 
    41 /* As of platform android-14, android/keycodes.h is missing these defines */
    42 #ifndef AKEYCODE_BUTTON_1
    43 #define AKEYCODE_BUTTON_1 188
    44 #define AKEYCODE_BUTTON_2 189
    45 #define AKEYCODE_BUTTON_3 190
    46 #define AKEYCODE_BUTTON_4 191
    47 #define AKEYCODE_BUTTON_5 192
    48 #define AKEYCODE_BUTTON_6 193
    49 #define AKEYCODE_BUTTON_7 194
    50 #define AKEYCODE_BUTTON_8 195
    51 #define AKEYCODE_BUTTON_9 196
    52 #define AKEYCODE_BUTTON_10 197
    53 #define AKEYCODE_BUTTON_11 198
    54 #define AKEYCODE_BUTTON_12 199
    55 #define AKEYCODE_BUTTON_13 200
    56 #define AKEYCODE_BUTTON_14 201
    57 #define AKEYCODE_BUTTON_15 202
    58 #define AKEYCODE_BUTTON_16 203
    59 #endif
    60 
    61 #define ANDROID_ACCELEROMETER_INDEX (SYS_numjoysticks - 1)
    62 #define ANDROID_ACCELEROMETER_NAME "Android Accelerometer"
    63 #define ANDROID_MAX_NBUTTONS 36
    64 
    65 static SDL_Joystick **SYS_Joysticks;
    66 static char **SYS_JoystickNames;
    67 static int SYS_numjoysticks;
    68 static SDL_bool SYS_accelAsJoy;
    69 
    70 /* Function to convert Android keyCodes into SDL ones.
    71  * This code manipulation is done to get a sequential list of codes.
    72  * FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
    73  */
    74 static int
    75 keycode_to_SDL(int keycode)
    76 {
    77     /* FIXME: If this function gets too unwiedly in the future, replace with a lookup table */
    78     int button = 0;
    79     switch(keycode) 
    80     {
    81         /* D-Pad key codes (API 1), these get mapped to 0...4 */
    82         case AKEYCODE_DPAD_UP:
    83         case AKEYCODE_DPAD_DOWN:
    84         case AKEYCODE_DPAD_LEFT:
    85         case AKEYCODE_DPAD_RIGHT:
    86         case AKEYCODE_DPAD_CENTER:
    87             button = keycode - AKEYCODE_DPAD_UP;
    88             break;
    89         
    90         /* Some gamepad buttons (API 9), these get mapped to 5...19*/
    91         case AKEYCODE_BUTTON_A:
    92         case AKEYCODE_BUTTON_B:
    93         case AKEYCODE_BUTTON_C:
    94         case AKEYCODE_BUTTON_X:
    95         case AKEYCODE_BUTTON_Y:
    96         case AKEYCODE_BUTTON_Z:
    97         case AKEYCODE_BUTTON_L1:
    98         case AKEYCODE_BUTTON_L2:
    99         case AKEYCODE_BUTTON_R1:
   100         case AKEYCODE_BUTTON_R2:
   101         case AKEYCODE_BUTTON_THUMBL:
   102         case AKEYCODE_BUTTON_THUMBR:
   103         case AKEYCODE_BUTTON_START:
   104         case AKEYCODE_BUTTON_SELECT:
   105         case AKEYCODE_BUTTON_MODE:
   106             button = keycode - AKEYCODE_BUTTON_A + 5;
   107             break;
   108             
   109         
   110         /* More gamepad buttons (API 12), these get mapped to 20...35*/
   111         case AKEYCODE_BUTTON_1:
   112         case AKEYCODE_BUTTON_2:
   113         case AKEYCODE_BUTTON_3:
   114         case AKEYCODE_BUTTON_4:
   115         case AKEYCODE_BUTTON_5:
   116         case AKEYCODE_BUTTON_6:
   117         case AKEYCODE_BUTTON_7:
   118         case AKEYCODE_BUTTON_8:
   119         case AKEYCODE_BUTTON_9:
   120         case AKEYCODE_BUTTON_10:
   121         case AKEYCODE_BUTTON_11:
   122         case AKEYCODE_BUTTON_12:
   123         case AKEYCODE_BUTTON_13:
   124         case AKEYCODE_BUTTON_14:
   125         case AKEYCODE_BUTTON_15:
   126         case AKEYCODE_BUTTON_16:
   127             button = keycode - AKEYCODE_BUTTON_1 + 20;
   128             break;
   129             
   130         default:
   131             return -1;
   132             break;
   133     }
   134     
   135     /* This is here in case future generations, probably with six fingers per hand, 
   136      * happily add new cases up above and forget to update the max number of buttons. 
   137      */
   138     SDL_assert(button < ANDROID_MAX_NBUTTONS);
   139     return button;
   140     
   141 }
   142 
   143 /* Function to scan the system for joysticks.
   144  * This function should set SDL_numjoysticks to the number of available
   145  * joysticks.  Joystick 0 should be the system default joystick.
   146  * It should return 0, or -1 on an unrecoverable fatal error.
   147  */
   148 int
   149 SDL_SYS_JoystickInit(void)
   150 {
   151     int i = 0;
   152     const char *env;
   153     
   154     env = SDL_GetHint(SDL_HINT_ACCEL_AS_JOY);
   155     if (env && !SDL_atoi(env))
   156         SYS_accelAsJoy = SDL_FALSE;
   157     else
   158         SYS_accelAsJoy = SDL_TRUE; /* Default behavior */
   159     
   160     SYS_numjoysticks = Android_JNI_GetNumJoysticks();
   161     if (SYS_accelAsJoy) {
   162         SYS_numjoysticks++;
   163     }
   164     SYS_Joysticks = (SDL_Joystick **)SDL_malloc(SYS_numjoysticks*sizeof(SDL_Joystick *));
   165     if (SYS_Joysticks == NULL)
   166     {
   167         return SDL_OutOfMemory();
   168     }
   169     SYS_JoystickNames = (char **)SDL_malloc(SYS_numjoysticks*sizeof(char *));
   170     if (SYS_JoystickNames == NULL)
   171     {
   172         SDL_free(SYS_Joysticks);
   173         SYS_Joysticks = NULL;
   174         return SDL_OutOfMemory();
   175     }
   176     SDL_memset(SYS_JoystickNames, 0, (SYS_numjoysticks*sizeof(char *)));
   177     SDL_memset(SYS_Joysticks, 0, (SYS_numjoysticks*sizeof(SDL_Joystick *)));
   178     
   179     for (i = 0; i < SYS_numjoysticks; i++)
   180     {
   181         if ( SYS_accelAsJoy && i == ANDROID_ACCELEROMETER_INDEX ) {
   182             SYS_JoystickNames[i] = ANDROID_ACCELEROMETER_NAME;
   183         } else {
   184             SYS_JoystickNames[i] = Android_JNI_GetJoystickName(i);
   185         }
   186     }
   187    
   188     return (SYS_numjoysticks);
   189 }
   190 
   191 int SDL_SYS_NumJoysticks()
   192 {
   193     return SYS_numjoysticks;
   194 }
   195 
   196 void SDL_SYS_JoystickDetect()
   197 {
   198 }
   199 
   200 /* TODO: Hotplugging support */
   201 SDL_bool SDL_SYS_JoystickNeedsPolling()
   202 {
   203     return SDL_FALSE;
   204 }
   205 
   206 /* Function to get the device-dependent name of a joystick */
   207 const char *
   208 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   209 {
   210     return SYS_JoystickNames[device_index];
   211 }
   212 
   213 /* Function to perform the mapping from device index to the instance id for this index */
   214 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   215 {
   216     return device_index;
   217 }
   218 
   219 /* Function to open a joystick for use.
   220    The joystick to open is specified by the index field of the joystick.
   221    This should fill the nbuttons and naxes fields of the joystick structure.
   222    It returns 0, or -1 if there is an error.
   223  */
   224 int
   225 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   226 {
   227     if (device_index < SYS_numjoysticks) {
   228         joystick->nhats = 0;
   229         joystick->nballs = 0;
   230         if (SYS_accelAsJoy && device_index == ANDROID_ACCELEROMETER_INDEX) {
   231             joystick->nbuttons = 0;
   232             joystick->naxes = 3;
   233         } else {
   234             /* FIXME: Get the real number of buttons in the device? */
   235             joystick->nbuttons = ANDROID_MAX_NBUTTONS;
   236             joystick->naxes = Android_JNI_GetJoystickAxes(device_index);
   237         }
   238         
   239         SYS_Joysticks[device_index] = joystick;
   240         return 0;
   241     } else {
   242         return SDL_SetError("No joystick available with that index");
   243     }
   244 }
   245 
   246 /* Function to determine is this joystick is attached to the system right now */
   247 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   248 {
   249     return SDL_TRUE;
   250 }
   251 
   252 /* Function to update the state of a joystick - called as a device poll.
   253  * This function shouldn't update the joystick structure directly,
   254  * but instead should call SDL_PrivateJoystick*() to deliver events
   255  * and update joystick device state.
   256  */
   257 void
   258 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   259 {
   260     int i;
   261     Sint16 value;
   262     float values[3];
   263 
   264     if (SYS_accelAsJoy && Android_JNI_GetAccelerometerValues(values) &&
   265         joystick->instance_id == ANDROID_ACCELEROMETER_INDEX) {
   266         for ( i = 0; i < 3; i++ ) {
   267             value = (Sint16)(values[i] * 32767.0f);
   268             SDL_PrivateJoystickAxis(joystick, i, value);
   269         }
   270     }
   271 }
   272 
   273 /* Function to close a joystick after use */
   274 void
   275 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   276 {
   277 }
   278 
   279 /* Function to perform any system-specific joystick related cleanup */
   280 void
   281 SDL_SYS_JoystickQuit(void)
   282 {
   283     SDL_free(SYS_JoystickNames);
   284     SDL_free(SYS_Joysticks);
   285     SYS_JoystickNames = NULL;
   286     SYS_Joysticks = NULL;
   287 }
   288 
   289 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   290 {
   291     SDL_JoystickGUID guid;
   292     /* the GUID is just the first 16 chars of the name for now */
   293     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   294     SDL_zero( guid );
   295     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   296     return guid;
   297 }
   298 
   299 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   300 {
   301     SDL_JoystickGUID guid;
   302     /* the GUID is just the first 16 chars of the name for now */
   303     const char *name = joystick->name;
   304     SDL_zero( guid );
   305     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   306     return guid;
   307 }
   308 
   309 int
   310 Android_OnPadDown(int padId, int keycode)
   311 {
   312     int button = keycode_to_SDL(keycode);
   313     if (button >= 0) {
   314         SDL_PrivateJoystickButton(SYS_Joysticks[padId], button , SDL_PRESSED);
   315         return 0;
   316     }
   317     
   318     return -1;
   319 }
   320 
   321 int
   322 Android_OnPadUp(int padId, int keycode)
   323 {
   324     int button = keycode_to_SDL(keycode);
   325     if (button >= 0) {
   326         SDL_PrivateJoystickButton(SYS_Joysticks[padId], button, SDL_RELEASED);
   327         return 0;
   328     }
   329     
   330     return -1;
   331 }
   332 
   333 int
   334 Android_OnJoy(int joyId, int axis, float value)
   335 {
   336     /* Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] */
   337     /* TODO: Are the reported values right? */
   338     SDL_PrivateJoystickAxis(SYS_Joysticks[joyId], axis, (Sint16) (32767.*value) );
   339     
   340     return 0;
   341 }
   342 
   343 #endif /* SDL_JOYSTICK_ANDROID */
   344 
   345 /* vi: set ts=4 sw=4 expandtab: */