cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_sysjoystick.c (16009B)


      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
     69static SDL_joylist_item * JoystickByDeviceId(int device_id);
     70
     71static SDL_joylist_item *SDL_joylist = NULL;
     72static SDL_joylist_item *SDL_joylist_tail = NULL;
     73static int numjoysticks = 0;
     74static 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 */
     81static int
     82keycode_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
    185int
    186Android_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
    201int
    202Android_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
    217int
    218Android_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
    229int
    230Android_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
    250int
    251Android_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
    319int 
    320Android_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
    379int
    380SDL_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
    395int SDL_SYS_NumJoysticks()
    396{
    397    return numjoysticks;
    398}
    399
    400void 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
    413static SDL_joylist_item *
    414JoystickByDevIndex(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
    431static SDL_joylist_item *
    432JoystickByDeviceId(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 */
    457const char *
    458SDL_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 */
    464SDL_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 index field of the joystick.
    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 */
    474int
    475SDL_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 is this joystick is attached to the system right now */
    499SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
    500{
    501    return !joystick->closed && (joystick->hwdata != NULL);
    502}
    503
    504void
    505SDL_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 */
    529void
    530SDL_SYS_JoystickClose(SDL_Joystick * joystick)
    531{
    532    if (joystick->hwdata) {
    533        ((SDL_joylist_item*)joystick->hwdata)->joystick = NULL;
    534        joystick->hwdata = NULL;
    535    }
    536    joystick->closed = 1;
    537}
    538
    539/* Function to perform any system-specific joystick related cleanup */
    540void
    541SDL_SYS_JoystickQuit(void)
    542{
    543    SDL_joylist_item *item = NULL;
    544    SDL_joylist_item *next = NULL;
    545
    546    for (item = SDL_joylist; item; item = next) {
    547        next = item->next;
    548        SDL_free(item->name);
    549        SDL_free(item);
    550    }
    551
    552    SDL_joylist = SDL_joylist_tail = NULL;
    553
    554    numjoysticks = 0;
    555    instance_counter = 0;
    556}
    557
    558SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
    559{
    560    return JoystickByDevIndex(device_index)->guid;
    561}
    562
    563SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
    564{
    565    SDL_JoystickGUID guid;
    566    
    567    if (joystick->hwdata != NULL) {
    568        return ((SDL_joylist_item*)joystick->hwdata)->guid;
    569    }
    570    
    571    SDL_zero(guid);
    572    return guid;
    573}
    574
    575#endif /* SDL_JOYSTICK_ANDROID */
    576
    577/* vi: set ts=4 sw=4 expandtab: */