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