src/joystick/android/SDL_sysjoystick.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Wed, 15 Apr 2015 21:29:55 +0200
changeset 9561 d8ad01792399
parent 9433 bd062398b648
child 9579 9a5b4bf6f4d1
permissions -rw-r--r--
Fixed typo in internal joystick documentation comments.
     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     SDL_Log("Added joystick %s with device_id %d", name, device_id);
   315 
   316     return numjoysticks;
   317 }
   318 
   319 int 
   320 Android_RemoveJoystick(int device_id)
   321 {
   322     SDL_joylist_item *item = SDL_joylist;
   323     SDL_joylist_item *prev = NULL;
   324 #if !SDL_EVENTS_DISABLED
   325     SDL_Event event;
   326 #endif
   327     
   328     /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
   329     while (item != NULL) {
   330         if (item->device_id == device_id) {
   331             break;
   332         }
   333         prev = item;
   334         item = item->next;
   335     }
   336     
   337     if (item == NULL) {
   338         return -1;
   339     }
   340 
   341     const int retval = item->device_instance;
   342     if (item->joystick) {
   343         item->joystick->hwdata = NULL;
   344     }
   345         
   346     if (prev != NULL) {
   347         prev->next = item->next;
   348     } else {
   349         SDL_assert(SDL_joylist == item);
   350         SDL_joylist = item->next;
   351     }
   352     if (item == SDL_joylist_tail) {
   353         SDL_joylist_tail = prev;
   354     }
   355 
   356     /* Need to decrement the joystick count before we post the event */
   357     --numjoysticks;
   358 
   359 #if !SDL_EVENTS_DISABLED
   360     event.type = SDL_JOYDEVICEREMOVED;
   361 
   362     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   363         event.jdevice.which = item->device_instance;
   364         if ( (SDL_EventOK == NULL) ||
   365              (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
   366             SDL_PushEvent(&event);
   367         }
   368     }
   369 #endif /* !SDL_EVENTS_DISABLED */
   370 
   371     SDL_Log("Removed joystick with device_id %d", device_id);
   372     
   373     SDL_free(item->name);
   374     SDL_free(item);
   375     return retval;
   376 }
   377 
   378 
   379 int
   380 SDL_SYS_JoystickInit(void)
   381 {
   382     const char *hint;
   383     SDL_SYS_JoystickDetect();
   384     
   385     hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
   386     if (!hint || SDL_atoi(hint)) {
   387         /* Default behavior, accelerometer as joystick */
   388         Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
   389     }
   390    
   391     return (numjoysticks);
   392 
   393 }
   394 
   395 int SDL_SYS_NumJoysticks()
   396 {
   397     return numjoysticks;
   398 }
   399 
   400 void SDL_SYS_JoystickDetect()
   401 {
   402     /* Support for device connect/disconnect is API >= 16 only,
   403      * so we poll every three seconds
   404      * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
   405      */
   406     static Uint32 timeout = 0;
   407     if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
   408         timeout = SDL_GetTicks() + 3000;
   409         Android_JNI_PollInputDevices();
   410     }
   411 }
   412 
   413 static SDL_joylist_item *
   414 JoystickByDevIndex(int device_index)
   415 {
   416     SDL_joylist_item *item = SDL_joylist;
   417 
   418     if ((device_index < 0) || (device_index >= numjoysticks)) {
   419         return NULL;
   420     }
   421 
   422     while (device_index > 0) {
   423         SDL_assert(item != NULL);
   424         device_index--;
   425         item = item->next;
   426     }
   427 
   428     return item;
   429 }
   430 
   431 static SDL_joylist_item *
   432 JoystickByDeviceId(int device_id)
   433 {
   434     SDL_joylist_item *item = SDL_joylist;
   435 
   436     while (item != NULL) {
   437         if (item->device_id == device_id) {
   438             return item;
   439         }
   440         item = item->next;
   441     }
   442     
   443     /* Joystick not found, try adding it */
   444     SDL_SYS_JoystickDetect();
   445     
   446     while (item != NULL) {
   447         if (item->device_id == device_id) {
   448             return item;
   449         }
   450         item = item->next;
   451     }
   452 
   453     return NULL;
   454 }
   455 
   456 /* Function to get the device-dependent name of a joystick */
   457 const char *
   458 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   459 {
   460     return JoystickByDevIndex(device_index)->name;
   461 }
   462 
   463 /* Function to perform the mapping from device index to the instance id for this index */
   464 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   465 {
   466     return JoystickByDevIndex(device_index)->device_instance;
   467 }
   468 
   469 /* Function to open a joystick for use.
   470    The joystick to open is specified by the device index.
   471    This should fill the nbuttons and naxes fields of the joystick structure.
   472    It returns 0, or -1 if there is an error.
   473  */
   474 int
   475 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   476 {
   477     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   478 
   479     if (item == NULL ) {
   480         return SDL_SetError("No such device");
   481     }
   482     
   483     if (item->joystick != NULL) {
   484         return SDL_SetError("Joystick already opened");
   485     }
   486 
   487     joystick->instance_id = item->device_instance;
   488     joystick->hwdata = (struct joystick_hwdata *) item;
   489     item->joystick = joystick;
   490     joystick->nhats = item->nhats;
   491     joystick->nballs = item->nballs;
   492     joystick->nbuttons = item->nbuttons;
   493     joystick->naxes = item->naxes;
   494 
   495     return (0);
   496 }
   497 
   498 /* Function to determine if this joystick is attached to the system right now */
   499 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   500 {
   501     return joystick->hwdata != NULL;
   502 }
   503 
   504 void
   505 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   506 {
   507     int i;
   508     Sint16 value;
   509     float values[3];
   510     SDL_joylist_item *item = SDL_joylist;
   511 
   512     while (item) {
   513         if (item->is_accelerometer) {
   514             if (item->joystick) {
   515                 if (Android_JNI_GetAccelerometerValues(values)) {
   516                     for ( i = 0; i < 3; i++ ) {
   517                         value = (Sint16)(values[i] * 32767.0f);
   518                         SDL_PrivateJoystickAxis(item->joystick, i, value);
   519                     }
   520                 }
   521             }
   522             break;
   523         }
   524         item = item->next;
   525     }
   526 }
   527 
   528 /* Function to close a joystick after use */
   529 void
   530 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   531 {
   532 }
   533 
   534 /* Function to perform any system-specific joystick related cleanup */
   535 void
   536 SDL_SYS_JoystickQuit(void)
   537 {
   538     SDL_joylist_item *item = NULL;
   539     SDL_joylist_item *next = NULL;
   540 
   541     for (item = SDL_joylist; item; item = next) {
   542         next = item->next;
   543         SDL_free(item->name);
   544         SDL_free(item);
   545     }
   546 
   547     SDL_joylist = SDL_joylist_tail = NULL;
   548 
   549     numjoysticks = 0;
   550     instance_counter = 0;
   551 }
   552 
   553 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   554 {
   555     return JoystickByDevIndex(device_index)->guid;
   556 }
   557 
   558 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   559 {
   560     SDL_JoystickGUID guid;
   561     
   562     if (joystick->hwdata != NULL) {
   563         return ((SDL_joylist_item*)joystick->hwdata)->guid;
   564     }
   565     
   566     SDL_zero(guid);
   567     return guid;
   568 }
   569 
   570 #endif /* SDL_JOYSTICK_ANDROID */
   571 
   572 /* vi: set ts=4 sw=4 expandtab: */