src/joystick/android/SDL_sysjoystick.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Thu, 30 Apr 2015 21:45:29 +0200
changeset 9579 9a5b4bf6f4d1
parent 9561 d8ad01792399
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Android: Deactivated debug log messages on joystick device events.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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 #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         /* Some gamepad buttons (API 9) */
    89         case AKEYCODE_BUTTON_A:
    90             button = SDL_CONTROLLER_BUTTON_A;
    91             break;
    92         case AKEYCODE_BUTTON_B:
    93             button = SDL_CONTROLLER_BUTTON_B;
    94             break;
    95         case AKEYCODE_BUTTON_X:
    96             button = SDL_CONTROLLER_BUTTON_X;
    97             break;
    98         case AKEYCODE_BUTTON_Y:
    99             button = SDL_CONTROLLER_BUTTON_Y;
   100             break;
   101         case AKEYCODE_BUTTON_L1:
   102             button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
   103             break;
   104         case AKEYCODE_BUTTON_R1:
   105             button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
   106             break;
   107         case AKEYCODE_BUTTON_THUMBL:
   108             button = SDL_CONTROLLER_BUTTON_LEFTSTICK;
   109             break;
   110         case AKEYCODE_BUTTON_THUMBR:
   111             button = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
   112             break;
   113         case AKEYCODE_BUTTON_START:
   114             button = SDL_CONTROLLER_BUTTON_START;
   115             break;
   116         case AKEYCODE_BUTTON_SELECT:
   117             button = SDL_CONTROLLER_BUTTON_BACK;
   118             break;
   119         case AKEYCODE_BUTTON_MODE:
   120             button = SDL_CONTROLLER_BUTTON_GUIDE;
   121             break;
   122         case AKEYCODE_BUTTON_L2:
   123             button = SDL_CONTROLLER_BUTTON_MAX; /* Not supported by GameController */
   124             break;
   125         case AKEYCODE_BUTTON_R2:
   126             button = SDL_CONTROLLER_BUTTON_MAX+1; /* Not supported by GameController */
   127             break;
   128         case AKEYCODE_BUTTON_C:
   129             button = SDL_CONTROLLER_BUTTON_MAX+2; /* Not supported by GameController */
   130             break;
   131         case AKEYCODE_BUTTON_Z:
   132             button = SDL_CONTROLLER_BUTTON_MAX+3; /* Not supported by GameController */
   133             break;
   134                         
   135         /* D-Pad key codes (API 1) */
   136         case AKEYCODE_DPAD_UP:
   137             button = SDL_CONTROLLER_BUTTON_DPAD_UP;
   138             break;
   139         case AKEYCODE_DPAD_DOWN:
   140             button = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
   141             break;
   142         case AKEYCODE_DPAD_LEFT:
   143             button = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
   144             break;
   145         case AKEYCODE_DPAD_RIGHT:
   146             button = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
   147             break;
   148         case AKEYCODE_DPAD_CENTER:
   149             button = SDL_CONTROLLER_BUTTON_MAX+4; /* Not supported by GameController */
   150             break;
   151 
   152         /* More gamepad buttons (API 12), these get mapped to 20...35*/
   153         case AKEYCODE_BUTTON_1:
   154         case AKEYCODE_BUTTON_2:
   155         case AKEYCODE_BUTTON_3:
   156         case AKEYCODE_BUTTON_4:
   157         case AKEYCODE_BUTTON_5:
   158         case AKEYCODE_BUTTON_6:
   159         case AKEYCODE_BUTTON_7:
   160         case AKEYCODE_BUTTON_8:
   161         case AKEYCODE_BUTTON_9:
   162         case AKEYCODE_BUTTON_10:
   163         case AKEYCODE_BUTTON_11:
   164         case AKEYCODE_BUTTON_12:
   165         case AKEYCODE_BUTTON_13:
   166         case AKEYCODE_BUTTON_14:
   167         case AKEYCODE_BUTTON_15:
   168         case AKEYCODE_BUTTON_16:
   169             button = keycode - AKEYCODE_BUTTON_1 + SDL_CONTROLLER_BUTTON_MAX + 5;
   170             break;
   171             
   172         default:
   173             return -1;
   174             break;
   175     }
   176     
   177     /* This is here in case future generations, probably with six fingers per hand, 
   178      * happily add new cases up above and forget to update the max number of buttons. 
   179      */
   180     SDL_assert(button < ANDROID_MAX_NBUTTONS);
   181     return button;
   182     
   183 }
   184 
   185 int
   186 Android_OnPadDown(int device_id, int keycode)
   187 {
   188     SDL_joylist_item *item;
   189     int button = keycode_to_SDL(keycode);
   190     if (button >= 0) {
   191         item = JoystickByDeviceId(device_id);
   192         if (item && item->joystick) {
   193             SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
   194         }
   195         return 0;
   196     }
   197     
   198     return -1;
   199 }
   200 
   201 int
   202 Android_OnPadUp(int device_id, int keycode)
   203 {
   204     SDL_joylist_item *item;
   205     int button = keycode_to_SDL(keycode);
   206     if (button >= 0) {
   207         item = JoystickByDeviceId(device_id);
   208         if (item && item->joystick) {
   209             SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED);
   210         }
   211         return 0;
   212     }
   213     
   214     return -1;
   215 }
   216 
   217 int
   218 Android_OnJoy(int device_id, int axis, float value)
   219 {
   220     /* Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] */
   221     SDL_joylist_item *item = JoystickByDeviceId(device_id);
   222     if (item && item->joystick) {
   223         SDL_PrivateJoystickAxis(item->joystick, axis, (Sint16) (32767.*value) );
   224     }
   225     
   226     return 0;
   227 }
   228 
   229 int
   230 Android_OnHat(int device_id, int hat_id, int x, int y)
   231 {
   232     const Uint8 position_map[3][3] = {
   233         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   234         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   235         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   236     };
   237 
   238     if (x >= -1 && x <=1 && y >= -1 && y <= 1) {
   239         SDL_joylist_item *item = JoystickByDeviceId(device_id);
   240         if (item && item->joystick) {
   241             SDL_PrivateJoystickHat(item->joystick, hat_id, position_map[y+1][x+1] );
   242         }
   243         return 0;
   244     }
   245 
   246     return -1;
   247 }
   248 
   249 
   250 int
   251 Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer, int nbuttons, int naxes, int nhats, int nballs)
   252 {
   253     SDL_JoystickGUID guid;
   254     SDL_joylist_item *item;
   255 #if !SDL_EVENTS_DISABLED
   256     SDL_Event event;
   257 #endif
   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, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   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 #if !SDL_EVENTS_DISABLED
   303     event.type = SDL_JOYDEVICEADDED;
   304 
   305     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   306         event.jdevice.which = (numjoysticks - 1);
   307         if ( (SDL_EventOK == NULL) ||
   308              (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
   309             SDL_PushEvent(&event);
   310         }
   311     }
   312 #endif /* !SDL_EVENTS_DISABLED */
   313 
   314 #ifdef DEBUG_JOYSTICK
   315     SDL_Log("Added joystick %s with device_id %d", name, device_id);
   316 #endif
   317 
   318     return numjoysticks;
   319 }
   320 
   321 int 
   322 Android_RemoveJoystick(int device_id)
   323 {
   324     SDL_joylist_item *item = SDL_joylist;
   325     SDL_joylist_item *prev = NULL;
   326 #if !SDL_EVENTS_DISABLED
   327     SDL_Event event;
   328 #endif
   329     
   330     /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
   331     while (item != NULL) {
   332         if (item->device_id == device_id) {
   333             break;
   334         }
   335         prev = item;
   336         item = item->next;
   337     }
   338     
   339     if (item == NULL) {
   340         return -1;
   341     }
   342 
   343     const int retval = item->device_instance;
   344     if (item->joystick) {
   345         item->joystick->hwdata = NULL;
   346     }
   347         
   348     if (prev != NULL) {
   349         prev->next = item->next;
   350     } else {
   351         SDL_assert(SDL_joylist == item);
   352         SDL_joylist = item->next;
   353     }
   354     if (item == SDL_joylist_tail) {
   355         SDL_joylist_tail = prev;
   356     }
   357 
   358     /* Need to decrement the joystick count before we post the event */
   359     --numjoysticks;
   360 
   361 #if !SDL_EVENTS_DISABLED
   362     event.type = SDL_JOYDEVICEREMOVED;
   363 
   364     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   365         event.jdevice.which = item->device_instance;
   366         if ( (SDL_EventOK == NULL) ||
   367              (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
   368             SDL_PushEvent(&event);
   369         }
   370     }
   371 #endif /* !SDL_EVENTS_DISABLED */
   372 
   373 #ifdef DEBUG_JOYSTICK
   374     SDL_Log("Removed joystick with device_id %d", device_id);
   375 #endif
   376     
   377     SDL_free(item->name);
   378     SDL_free(item);
   379     return retval;
   380 }
   381 
   382 
   383 int
   384 SDL_SYS_JoystickInit(void)
   385 {
   386     const char *hint;
   387     SDL_SYS_JoystickDetect();
   388     
   389     hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
   390     if (!hint || SDL_atoi(hint)) {
   391         /* Default behavior, accelerometer as joystick */
   392         Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
   393     }
   394    
   395     return (numjoysticks);
   396 
   397 }
   398 
   399 int SDL_SYS_NumJoysticks()
   400 {
   401     return numjoysticks;
   402 }
   403 
   404 void SDL_SYS_JoystickDetect()
   405 {
   406     /* Support for device connect/disconnect is API >= 16 only,
   407      * so we poll every three seconds
   408      * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
   409      */
   410     static Uint32 timeout = 0;
   411     if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
   412         timeout = SDL_GetTicks() + 3000;
   413         Android_JNI_PollInputDevices();
   414     }
   415 }
   416 
   417 static SDL_joylist_item *
   418 JoystickByDevIndex(int device_index)
   419 {
   420     SDL_joylist_item *item = SDL_joylist;
   421 
   422     if ((device_index < 0) || (device_index >= numjoysticks)) {
   423         return NULL;
   424     }
   425 
   426     while (device_index > 0) {
   427         SDL_assert(item != NULL);
   428         device_index--;
   429         item = item->next;
   430     }
   431 
   432     return item;
   433 }
   434 
   435 static SDL_joylist_item *
   436 JoystickByDeviceId(int device_id)
   437 {
   438     SDL_joylist_item *item = SDL_joylist;
   439 
   440     while (item != NULL) {
   441         if (item->device_id == device_id) {
   442             return item;
   443         }
   444         item = item->next;
   445     }
   446     
   447     /* Joystick not found, try adding it */
   448     SDL_SYS_JoystickDetect();
   449     
   450     while (item != NULL) {
   451         if (item->device_id == device_id) {
   452             return item;
   453         }
   454         item = item->next;
   455     }
   456 
   457     return NULL;
   458 }
   459 
   460 /* Function to get the device-dependent name of a joystick */
   461 const char *
   462 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   463 {
   464     return JoystickByDevIndex(device_index)->name;
   465 }
   466 
   467 /* Function to perform the mapping from device index to the instance id for this index */
   468 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   469 {
   470     return JoystickByDevIndex(device_index)->device_instance;
   471 }
   472 
   473 /* Function to open a joystick for use.
   474    The joystick to open is specified by the device index.
   475    This should fill the nbuttons and naxes fields of the joystick structure.
   476    It returns 0, or -1 if there is an error.
   477  */
   478 int
   479 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   480 {
   481     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   482 
   483     if (item == NULL ) {
   484         return SDL_SetError("No such device");
   485     }
   486     
   487     if (item->joystick != NULL) {
   488         return SDL_SetError("Joystick already opened");
   489     }
   490 
   491     joystick->instance_id = item->device_instance;
   492     joystick->hwdata = (struct joystick_hwdata *) item;
   493     item->joystick = joystick;
   494     joystick->nhats = item->nhats;
   495     joystick->nballs = item->nballs;
   496     joystick->nbuttons = item->nbuttons;
   497     joystick->naxes = item->naxes;
   498 
   499     return (0);
   500 }
   501 
   502 /* Function to determine if this joystick is attached to the system right now */
   503 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   504 {
   505     return joystick->hwdata != NULL;
   506 }
   507 
   508 void
   509 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   510 {
   511     int i;
   512     Sint16 value;
   513     float values[3];
   514     SDL_joylist_item *item = SDL_joylist;
   515 
   516     while (item) {
   517         if (item->is_accelerometer) {
   518             if (item->joystick) {
   519                 if (Android_JNI_GetAccelerometerValues(values)) {
   520                     for ( i = 0; i < 3; i++ ) {
   521                         value = (Sint16)(values[i] * 32767.0f);
   522                         SDL_PrivateJoystickAxis(item->joystick, i, value);
   523                     }
   524                 }
   525             }
   526             break;
   527         }
   528         item = item->next;
   529     }
   530 }
   531 
   532 /* Function to close a joystick after use */
   533 void
   534 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   535 {
   536 }
   537 
   538 /* Function to perform any system-specific joystick related cleanup */
   539 void
   540 SDL_SYS_JoystickQuit(void)
   541 {
   542     SDL_joylist_item *item = NULL;
   543     SDL_joylist_item *next = NULL;
   544 
   545     for (item = SDL_joylist; item; item = next) {
   546         next = item->next;
   547         SDL_free(item->name);
   548         SDL_free(item);
   549     }
   550 
   551     SDL_joylist = SDL_joylist_tail = NULL;
   552 
   553     numjoysticks = 0;
   554     instance_counter = 0;
   555 }
   556 
   557 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   558 {
   559     return JoystickByDevIndex(device_index)->guid;
   560 }
   561 
   562 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   563 {
   564     SDL_JoystickGUID guid;
   565     
   566     if (joystick->hwdata != NULL) {
   567         return ((SDL_joylist_item*)joystick->hwdata)->guid;
   568     }
   569     
   570     SDL_zero(guid);
   571     return guid;
   572 }
   573 
   574 #endif /* SDL_JOYSTICK_ANDROID */
   575 
   576 /* vi: set ts=4 sw=4 expandtab: */