cscg22-gearboy

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

SDL_gamecontroller.c (39290B)


      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#include "../SDL_internal.h"
     22
     23/* This is the game controller API for Simple DirectMedia Layer */
     24
     25#include "SDL_events.h"
     26#include "SDL_assert.h"
     27#include "SDL_sysjoystick.h"
     28#include "SDL_hints.h"
     29#include "SDL_gamecontrollerdb.h"
     30
     31#if !SDL_EVENTS_DISABLED
     32#include "../events/SDL_events_c.h"
     33#endif
     34#define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
     35
     36#define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
     37
     38/* a list of currently opened game controllers */
     39static SDL_GameController *SDL_gamecontrollers = NULL;
     40
     41/* keep track of the hat and mask value that transforms this hat movement into a button/axis press */
     42struct _SDL_HatMapping
     43{
     44    int hat;
     45    Uint8 mask;
     46};
     47
     48#define k_nMaxReverseEntries 20
     49
     50/**
     51 * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask
     52 * MAX 4 hats supported
     53 */
     54#define k_nMaxHatEntries 0x3f + 1
     55
     56/* our in memory mapping db between joystick objects and controller mappings */
     57struct _SDL_ControllerMapping
     58{
     59    SDL_JoystickGUID guid;
     60    const char *name;
     61
     62    /* mapping of axis/button id to controller version */
     63    int axes[SDL_CONTROLLER_AXIS_MAX];
     64    int buttonasaxis[SDL_CONTROLLER_AXIS_MAX];
     65
     66    int buttons[SDL_CONTROLLER_BUTTON_MAX];
     67    int axesasbutton[SDL_CONTROLLER_BUTTON_MAX];
     68    struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX];
     69
     70    /* reverse mapping, joystick indices to buttons */
     71    SDL_GameControllerAxis raxes[k_nMaxReverseEntries];
     72    SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries];
     73
     74    SDL_GameControllerButton rbuttons[k_nMaxReverseEntries];
     75    SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries];
     76    SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries];
     77
     78};
     79
     80
     81/* our hard coded list of mapping support */
     82typedef struct _ControllerMapping_t
     83{
     84    SDL_JoystickGUID guid;
     85    char *name;
     86    char *mapping;
     87    struct _ControllerMapping_t *next;
     88} ControllerMapping_t;
     89
     90static ControllerMapping_t *s_pSupportedControllers = NULL;
     91static ControllerMapping_t *s_pXInputMapping = NULL;
     92
     93/* The SDL game controller structure */
     94struct _SDL_GameController
     95{
     96    SDL_Joystick *joystick; /* underlying joystick device */
     97    int ref_count;
     98    Uint8 hatState[4]; /* the current hat state for this controller */
     99    struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */
    100    struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
    101};
    102
    103
    104int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
    105int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
    106
    107/*
    108 * Event filter to fire controller events from joystick ones
    109 */
    110int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
    111{
    112    switch(event->type) {
    113    case SDL_JOYAXISMOTION:
    114        {
    115            SDL_GameController *controllerlist;
    116
    117            if (event->jaxis.axis >= k_nMaxReverseEntries) break;
    118
    119            controllerlist = SDL_gamecontrollers;
    120            while (controllerlist) {
    121                if (controllerlist->joystick->instance_id == event->jaxis.which) {
    122                    if (controllerlist->mapping.raxes[event->jaxis.axis] >= 0) /* simple axis to axis, send it through */ {
    123                        SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis];
    124                        Sint16 value = event->jaxis.value;
    125                        switch (axis) {
    126                            case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
    127                            case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
    128                                /* Shift it to be 0 - 32767. */
    129                                value = value / 2 + 16384;
    130                            default:
    131                                break;
    132                        }
    133                        SDL_PrivateGameControllerAxis(controllerlist, axis, value);
    134                    } else if (controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0) { /* simulate an axis as a button */
    135                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED);
    136                    }
    137                    break;
    138                }
    139                controllerlist = controllerlist->next;
    140            }
    141        }
    142        break;
    143    case SDL_JOYBUTTONDOWN:
    144    case SDL_JOYBUTTONUP:
    145        {
    146            SDL_GameController *controllerlist;
    147
    148            if (event->jbutton.button >= k_nMaxReverseEntries) break;
    149
    150            controllerlist = SDL_gamecontrollers;
    151            while (controllerlist) {
    152                if (controllerlist->joystick->instance_id == event->jbutton.which) {
    153                    if (controllerlist->mapping.rbuttons[event->jbutton.button] >= 0) { /* simple button as button */
    154                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state);
    155                    } else if (controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0) { /* an button pretending to be an axis */
    156                        SDL_PrivateGameControllerAxis(controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0);
    157                    }
    158                    break;
    159                }
    160                controllerlist = controllerlist->next;
    161            }
    162        }
    163        break;
    164    case SDL_JOYHATMOTION:
    165        {
    166            SDL_GameController *controllerlist;
    167
    168            if (event->jhat.hat >= 4) break;
    169
    170            controllerlist = SDL_gamecontrollers;
    171            while (controllerlist) {
    172                if (controllerlist->joystick->instance_id == event->jhat.which) {
    173                    Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value;
    174                    /* Get list of removed bits (button release) */
    175                    Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame;
    176                    /* the hat idx in the high nibble */
    177                    int bHighHat = event->jhat.hat << 4;
    178
    179                    if (bChanged & SDL_HAT_DOWN)
    180                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED);
    181                    if (bChanged & SDL_HAT_UP)
    182                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED);
    183                    if (bChanged & SDL_HAT_LEFT)
    184                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED);
    185                    if (bChanged & SDL_HAT_RIGHT)
    186                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED);
    187
    188                    /* Get list of added bits (button press) */
    189                    bChanged = event->jhat.value ^ bSame;
    190
    191                    if (bChanged & SDL_HAT_DOWN)
    192                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED);
    193                    if (bChanged & SDL_HAT_UP)
    194                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED);
    195                    if (bChanged & SDL_HAT_LEFT)
    196                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED);
    197                    if (bChanged & SDL_HAT_RIGHT)
    198                        SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED);
    199
    200                    /* update our state cache */
    201                    controllerlist->hatState[event->jhat.hat] = event->jhat.value;
    202
    203                    break;
    204                }
    205                controllerlist = controllerlist->next;
    206            }
    207        }
    208        break;
    209    case SDL_JOYDEVICEADDED:
    210        {
    211            if (SDL_IsGameController(event->jdevice.which)) {
    212                SDL_Event deviceevent;
    213                deviceevent.type = SDL_CONTROLLERDEVICEADDED;
    214                deviceevent.cdevice.which = event->jdevice.which;
    215                SDL_PushEvent(&deviceevent);
    216            }
    217        }
    218        break;
    219    case SDL_JOYDEVICEREMOVED:
    220        {
    221            SDL_GameController *controllerlist = SDL_gamecontrollers;
    222            while (controllerlist) {
    223                if (controllerlist->joystick->instance_id == event->jdevice.which) {
    224                    SDL_Event deviceevent;
    225                    deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
    226                    deviceevent.cdevice.which = event->jdevice.which;
    227                    SDL_PushEvent(&deviceevent);
    228                    break;
    229                }
    230                controllerlist = controllerlist->next;
    231            }
    232        }
    233        break;
    234    default:
    235        break;
    236    }
    237
    238    return 1;
    239}
    240
    241/*
    242 * Helper function to scan the mappings database for a controller with the specified GUID
    243 */
    244ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
    245{
    246    ControllerMapping_t *pSupportedController = s_pSupportedControllers;
    247    while (pSupportedController) {
    248        if (SDL_memcmp(guid, &pSupportedController->guid, sizeof(*guid)) == 0) {
    249            return pSupportedController;
    250        }
    251        pSupportedController = pSupportedController->next;
    252    }
    253    return NULL;
    254}
    255
    256/*
    257 * Helper function to determine pre-calculated offset to certain joystick mappings
    258 */
    259ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
    260{
    261#if SDL_JOYSTICK_XINPUT
    262    if (SDL_SYS_IsXInputGamepad_DeviceIndex(device_index) && s_pXInputMapping) {
    263        return s_pXInputMapping;
    264    }
    265    else
    266#endif /* SDL_JOYSTICK_XINPUT */
    267    {
    268        SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
    269        return SDL_PrivateGetControllerMappingForGUID(&jGUID);
    270    }
    271}
    272
    273static const char* map_StringForControllerAxis[] = {
    274    "leftx",
    275    "lefty",
    276    "rightx",
    277    "righty",
    278    "lefttrigger",
    279    "righttrigger",
    280    NULL
    281};
    282
    283/*
    284 * convert a string to its enum equivalent
    285 */
    286SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
    287{
    288    int entry;
    289    if (!pchString || !pchString[0])
    290        return SDL_CONTROLLER_AXIS_INVALID;
    291
    292    for (entry = 0; map_StringForControllerAxis[entry]; ++entry) {
    293        if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry]))
    294            return entry;
    295    }
    296    return SDL_CONTROLLER_AXIS_INVALID;
    297}
    298
    299/*
    300 * convert an enum to its string equivalent
    301 */
    302const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
    303{
    304    if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) {
    305        return map_StringForControllerAxis[axis];
    306    }
    307    return NULL;
    308}
    309
    310static const char* map_StringForControllerButton[] = {
    311    "a",
    312    "b",
    313    "x",
    314    "y",
    315    "back",
    316    "guide",
    317    "start",
    318    "leftstick",
    319    "rightstick",
    320    "leftshoulder",
    321    "rightshoulder",
    322    "dpup",
    323    "dpdown",
    324    "dpleft",
    325    "dpright",
    326    NULL
    327};
    328
    329/*
    330 * convert a string to its enum equivalent
    331 */
    332SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString)
    333{
    334    int entry;
    335    if (!pchString || !pchString[0])
    336        return SDL_CONTROLLER_BUTTON_INVALID;
    337
    338    for (entry = 0; map_StringForControllerButton[entry]; ++entry) {
    339        if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0)
    340            return entry;
    341    }
    342    return SDL_CONTROLLER_BUTTON_INVALID;
    343}
    344
    345/*
    346 * convert an enum to its string equivalent
    347 */
    348const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
    349{
    350    if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) {
    351        return map_StringForControllerButton[axis];
    352    }
    353    return NULL;
    354}
    355
    356/*
    357 * given a controller button name and a joystick name update our mapping structure with it
    358 */
    359void SDL_PrivateGameControllerParseButton(const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping)
    360{
    361    int iSDLButton = 0;
    362    SDL_GameControllerButton button;
    363    SDL_GameControllerAxis axis;
    364    button = SDL_GameControllerGetButtonFromString(szGameButton);
    365    axis = SDL_GameControllerGetAxisFromString(szGameButton);
    366    iSDLButton = SDL_atoi(&szJoystickButton[1]);
    367
    368    if (szJoystickButton[0] == 'a') {
    369        if (iSDLButton >= k_nMaxReverseEntries) {
    370            SDL_SetError("Axis index too large: %d", iSDLButton);
    371            return;
    372        }
    373        if (axis != SDL_CONTROLLER_AXIS_INVALID) {
    374            pMapping->axes[ axis ] = iSDLButton;
    375            pMapping->raxes[ iSDLButton ] = axis;
    376        } else if (button != SDL_CONTROLLER_BUTTON_INVALID) {
    377            pMapping->axesasbutton[ button ] = iSDLButton;
    378            pMapping->raxesasbutton[ iSDLButton ] = button;
    379        } else {
    380            SDL_assert(!"How did we get here?");
    381        }
    382
    383    } else if (szJoystickButton[0] == 'b') {
    384        if (iSDLButton >= k_nMaxReverseEntries) {
    385            SDL_SetError("Button index too large: %d", iSDLButton);
    386            return;
    387        }
    388        if (button != SDL_CONTROLLER_BUTTON_INVALID) {
    389            pMapping->buttons[ button ] = iSDLButton;
    390            pMapping->rbuttons[ iSDLButton ] = button;
    391        } else if (axis != SDL_CONTROLLER_AXIS_INVALID) {
    392            pMapping->buttonasaxis[ axis ] = iSDLButton;
    393            pMapping->rbuttonasaxis[ iSDLButton ] = axis;
    394        } else {
    395            SDL_assert(!"How did we get here?");
    396        }
    397    } else if (szJoystickButton[0] == 'h') {
    398        int hat = SDL_atoi(&szJoystickButton[1]);
    399        int mask = SDL_atoi(&szJoystickButton[3]);
    400        if (hat >= 4) {
    401            SDL_SetError("Hat index too large: %d", iSDLButton);
    402        }
    403
    404        if (button != SDL_CONTROLLER_BUTTON_INVALID) {
    405            int ridx;
    406            pMapping->hatasbutton[ button ].hat = hat;
    407            pMapping->hatasbutton[ button ].mask = mask;
    408            ridx = (hat << 4) | mask;
    409            pMapping->rhatasbutton[ ridx ] = button;
    410        } else if (axis != SDL_CONTROLLER_AXIS_INVALID) {
    411            SDL_assert(!"Support hat as axis");
    412        } else {
    413            SDL_assert(!"How did we get here?");
    414        }
    415    }
    416}
    417
    418
    419/*
    420 * given a controller mapping string update our mapping object
    421 */
    422static void
    423SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMapping *pMapping, const char *pchString)
    424{
    425    char szGameButton[20];
    426    char szJoystickButton[20];
    427    SDL_bool bGameButton = SDL_TRUE;
    428    int i = 0;
    429    const char *pchPos = pchString;
    430
    431    SDL_memset(szGameButton, 0x0, sizeof(szGameButton));
    432    SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton));
    433
    434    while (pchPos && *pchPos) {
    435        if (*pchPos == ':') {
    436            i = 0;
    437            bGameButton = SDL_FALSE;
    438        } else if (*pchPos == ' ') {
    439
    440        } else if (*pchPos == ',') {
    441            i = 0;
    442            bGameButton = SDL_TRUE;
    443            SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping);
    444            SDL_memset(szGameButton, 0x0, sizeof(szGameButton));
    445            SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton));
    446
    447        } else if (bGameButton) {
    448            if (i >= sizeof(szGameButton)) {
    449                SDL_SetError("Button name too large: %s", szGameButton);
    450                return;
    451            }
    452            szGameButton[i] = *pchPos;
    453            i++;
    454        } else {
    455            if (i >= sizeof(szJoystickButton)) {
    456                SDL_SetError("Joystick button name too large: %s", szJoystickButton);
    457                return;
    458            }
    459            szJoystickButton[i] = *pchPos;
    460            i++;
    461        }
    462        pchPos++;
    463    }
    464
    465    SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping);
    466
    467}
    468
    469/*
    470 * Make a new button mapping struct
    471 */
    472void SDL_PrivateLoadButtonMapping(struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
    473{
    474    int j;
    475
    476    pMapping->guid = guid;
    477    pMapping->name = pchName;
    478
    479    /* set all the button mappings to non defaults */
    480    for (j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++) {
    481        pMapping->axes[j] = -1;
    482        pMapping->buttonasaxis[j] = -1;
    483    }
    484    for (j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++) {
    485        pMapping->buttons[j] = -1;
    486        pMapping->axesasbutton[j] = -1;
    487        pMapping->hatasbutton[j].hat = -1;
    488    }
    489
    490    for (j = 0; j < k_nMaxReverseEntries; j++) {
    491        pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
    492        pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
    493        pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
    494        pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
    495    }
    496
    497    for (j = 0; j < k_nMaxHatEntries; j++) {
    498        pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
    499    }
    500
    501    SDL_PrivateGameControllerParseControllerConfigString(pMapping, pchMapping);
    502}
    503
    504
    505/*
    506 * grab the guid string from a mapping string
    507 */
    508char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
    509{
    510    const char *pFirstComma = SDL_strchr(pMapping, ',');
    511    if (pFirstComma) {
    512        char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1);
    513        if (!pchGUID) {
    514            SDL_OutOfMemory();
    515            return NULL;
    516        }
    517        SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping);
    518        pchGUID[ pFirstComma - pMapping ] = 0;
    519        return pchGUID;
    520    }
    521    return NULL;
    522}
    523
    524
    525/*
    526 * grab the name string from a mapping string
    527 */
    528char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
    529{
    530    const char *pFirstComma, *pSecondComma;
    531    char *pchName;
    532
    533    pFirstComma = SDL_strchr(pMapping, ',');
    534    if (!pFirstComma)
    535        return NULL;
    536
    537    pSecondComma = SDL_strchr(pFirstComma + 1, ',');
    538    if (!pSecondComma)
    539        return NULL;
    540
    541    pchName = SDL_malloc(pSecondComma - pFirstComma);
    542    if (!pchName) {
    543        SDL_OutOfMemory();
    544        return NULL;
    545    }
    546    SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma);
    547    pchName[ pSecondComma - pFirstComma - 1 ] = 0;
    548    return pchName;
    549}
    550
    551
    552/*
    553 * grab the button mapping string from a mapping string
    554 */
    555char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
    556{
    557    const char *pFirstComma, *pSecondComma;
    558
    559    pFirstComma = SDL_strchr(pMapping, ',');
    560    if (!pFirstComma)
    561        return NULL;
    562
    563    pSecondComma = SDL_strchr(pFirstComma + 1, ',');
    564    if (!pSecondComma)
    565        return NULL;
    566
    567    return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
    568}
    569
    570void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
    571{
    572    SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
    573    while (gamecontrollerlist) {
    574        if (!SDL_memcmp(&gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) {
    575            SDL_Event event;
    576            event.type = SDL_CONTROLLERDEVICEREMAPPED;
    577            event.cdevice.which = gamecontrollerlist->joystick->instance_id;
    578            SDL_PushEvent(&event);
    579
    580            /* Not really threadsafe.  Should this lock access within SDL_GameControllerEventWatcher? */
    581            SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
    582        }
    583
    584        gamecontrollerlist = gamecontrollerlist->next;
    585    }
    586}
    587
    588/*
    589 * Add or update an entry into the Mappings Database
    590 */
    591int
    592SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw)
    593{
    594    const char *platform = SDL_GetPlatform();
    595    int controllers = 0;
    596    char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
    597    size_t db_size, platform_len;
    598    
    599    if (rw == NULL) {
    600        return SDL_SetError("Invalid RWops");
    601    }
    602    db_size = (size_t)SDL_RWsize(rw);
    603    
    604    buf = (char *)SDL_malloc(db_size + 1);
    605    if (buf == NULL) {
    606        if (freerw) {
    607            SDL_RWclose(rw);
    608        }
    609        return SDL_SetError("Could allocate space to not read DB into memory");
    610    }
    611    
    612    if (SDL_RWread(rw, buf, db_size, 1) != 1) {
    613        if (freerw) {
    614            SDL_RWclose(rw);
    615        }
    616        SDL_free(buf);
    617        return SDL_SetError("Could not read DB");
    618    }
    619    
    620    if (freerw) {
    621        SDL_RWclose(rw);
    622    }
    623    
    624    buf[db_size] = '\0';
    625    line = buf;
    626    
    627    while (line < buf + db_size) {
    628        line_end = SDL_strchr(line, '\n');
    629        if (line_end != NULL) {
    630            *line_end = '\0';
    631        } else {
    632            line_end = buf + db_size;
    633        }
    634        
    635        /* Extract and verify the platform */
    636        tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD);
    637        if (tmp != NULL) {
    638            tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD);
    639            comma = SDL_strchr(tmp, ',');
    640            if (comma != NULL) {
    641                platform_len = comma - tmp + 1;
    642                if (platform_len + 1 < SDL_arraysize(line_platform)) {
    643                    SDL_strlcpy(line_platform, tmp, platform_len);
    644                    if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 &&
    645                        SDL_GameControllerAddMapping(line) > 0) {
    646                        controllers++;
    647                    }
    648                }
    649            }
    650        }
    651        
    652        line = line_end + 1;
    653    }
    654
    655    SDL_free(buf);
    656    return controllers;
    657}
    658
    659/*
    660 * Add or update an entry into the Mappings Database
    661 */
    662int
    663SDL_GameControllerAddMapping(const char *mappingString)
    664{
    665    char *pchGUID;
    666    char *pchName;
    667    char *pchMapping;
    668    SDL_JoystickGUID jGUID;
    669    ControllerMapping_t *pControllerMapping;
    670    SDL_bool is_xinput_mapping = SDL_FALSE;
    671
    672    pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString);
    673    if (!pchGUID) {
    674        return SDL_SetError("Couldn't parse GUID from %s", mappingString);
    675    }
    676    if (!SDL_strcasecmp(pchGUID, "xinput")) {
    677        is_xinput_mapping = SDL_TRUE;
    678    }
    679    jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
    680    SDL_free(pchGUID);
    681
    682    pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
    683    if (!pchName) {
    684        return SDL_SetError("Couldn't parse name from %s", mappingString);
    685    }
    686
    687    pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
    688    if (!pchMapping) {
    689        SDL_free(pchName);
    690        return SDL_SetError("Couldn't parse %s", mappingString);
    691    }
    692
    693    pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
    694
    695    if (pControllerMapping) {
    696        /* Update existing mapping */
    697        SDL_free(pControllerMapping->name);
    698        pControllerMapping->name = pchName;
    699        SDL_free(pControllerMapping->mapping);
    700        pControllerMapping->mapping = pchMapping;
    701        /* refresh open controllers */
    702        SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
    703        return 0;
    704    } else {
    705        pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
    706        if (!pControllerMapping) {
    707            SDL_free(pchName);
    708            SDL_free(pchMapping);
    709            return SDL_OutOfMemory();
    710        }
    711        if (is_xinput_mapping) {
    712            s_pXInputMapping = pControllerMapping;
    713        }
    714        pControllerMapping->guid = jGUID;
    715        pControllerMapping->name = pchName;
    716        pControllerMapping->mapping = pchMapping;
    717        pControllerMapping->next = s_pSupportedControllers;
    718        s_pSupportedControllers = pControllerMapping;
    719        return 1;
    720    }
    721}
    722
    723/*
    724 * Get the mapping string for this GUID
    725 */
    726char *
    727SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
    728{
    729    char *pMappingString = NULL;
    730    ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
    731    if (mapping) {
    732        char pchGUID[33];
    733        size_t needed;
    734        SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
    735        /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
    736        needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
    737        pMappingString = SDL_malloc(needed);
    738        SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
    739    }
    740    return pMappingString;
    741}
    742
    743/*
    744 * Get the mapping string for this device
    745 */
    746char *
    747SDL_GameControllerMapping(SDL_GameController * gamecontroller)
    748{
    749    return SDL_GameControllerMappingForGUID(gamecontroller->mapping.guid);
    750}
    751
    752static void
    753SDL_GameControllerLoadHints()
    754{
    755    const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
    756    if (hint && hint[0]) {
    757        size_t nchHints = SDL_strlen(hint);
    758        char *pUserMappings = SDL_malloc(nchHints + 1);
    759        char *pTempMappings = pUserMappings;
    760        SDL_memcpy(pUserMappings, hint, nchHints);
    761        pUserMappings[nchHints] = '\0';
    762        while (pUserMappings) {
    763            char *pchNewLine = NULL;
    764
    765            pchNewLine = SDL_strchr(pUserMappings, '\n');
    766            if (pchNewLine)
    767                *pchNewLine = '\0';
    768
    769            SDL_GameControllerAddMapping(pUserMappings);
    770
    771            if (pchNewLine) {
    772                pUserMappings = pchNewLine + 1;
    773            } else {
    774                pUserMappings = NULL;
    775            }
    776        }
    777        SDL_free(pTempMappings);
    778    }
    779}
    780
    781/*
    782 * Initialize the game controller system, mostly load our DB of controller config mappings
    783 */
    784int
    785SDL_GameControllerInit(void)
    786{
    787    int i = 0;
    788    const char *pMappingString = NULL;
    789    s_pSupportedControllers = NULL;
    790    pMappingString = s_ControllerMappings[i];
    791    while (pMappingString) {
    792        SDL_GameControllerAddMapping(pMappingString);
    793
    794        i++;
    795        pMappingString = s_ControllerMappings[i];
    796    }
    797
    798    /* load in any user supplied config */
    799    SDL_GameControllerLoadHints();
    800
    801    /* watch for joy events and fire controller ones if needed */
    802    SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL);
    803
    804    /* Send added events for controllers currently attached */
    805    for (i = 0; i < SDL_NumJoysticks(); ++i) {
    806        if (SDL_IsGameController(i)) {
    807            SDL_Event deviceevent;
    808            deviceevent.type = SDL_CONTROLLERDEVICEADDED;
    809            deviceevent.cdevice.which = i;
    810            SDL_PushEvent(&deviceevent);
    811        }
    812    }
    813
    814    return (0);
    815}
    816
    817
    818/*
    819 * Get the implementation dependent name of a controller
    820 */
    821const char *
    822SDL_GameControllerNameForIndex(int device_index)
    823{
    824    ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
    825    if (pSupportedController) {
    826        return pSupportedController->name;
    827    }
    828    return NULL;
    829}
    830
    831
    832/*
    833 * Return 1 if the joystick at this device index is a supported controller
    834 */
    835SDL_bool
    836SDL_IsGameController(int device_index)
    837{
    838    ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
    839    if (pSupportedController) {
    840        return SDL_TRUE;
    841    }
    842
    843    return SDL_FALSE;
    844}
    845
    846/*
    847 * Open a controller for use - the index passed as an argument refers to
    848 * the N'th controller on the system.  This index is the value which will
    849 * identify this controller in future controller events.
    850 *
    851 * This function returns a controller identifier, or NULL if an error occurred.
    852 */
    853SDL_GameController *
    854SDL_GameControllerOpen(int device_index)
    855{
    856    SDL_GameController *gamecontroller;
    857    SDL_GameController *gamecontrollerlist;
    858    ControllerMapping_t *pSupportedController = NULL;
    859
    860    if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
    861        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
    862        return (NULL);
    863    }
    864
    865    gamecontrollerlist = SDL_gamecontrollers;
    866    /* If the controller is already open, return it */
    867    while (gamecontrollerlist) {
    868        if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
    869                gamecontroller = gamecontrollerlist;
    870                ++gamecontroller->ref_count;
    871                return (gamecontroller);
    872        }
    873        gamecontrollerlist = gamecontrollerlist->next;
    874    }
    875
    876    /* Find a controller mapping */
    877    pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
    878    if (!pSupportedController) {
    879        SDL_SetError("Couldn't find mapping for device (%d)", device_index);
    880        return (NULL);
    881    }
    882
    883    /* Create and initialize the joystick */
    884    gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
    885    if (gamecontroller == NULL) {
    886        SDL_OutOfMemory();
    887        return NULL;
    888    }
    889
    890    SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
    891    gamecontroller->joystick = SDL_JoystickOpen(device_index);
    892    if (!gamecontroller->joystick) {
    893        SDL_free(gamecontroller);
    894        return NULL;
    895    }
    896
    897    SDL_PrivateLoadButtonMapping(&gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
    898
    899    /* Add joystick to list */
    900    ++gamecontroller->ref_count;
    901    /* Link the joystick in the list */
    902    gamecontroller->next = SDL_gamecontrollers;
    903    SDL_gamecontrollers = gamecontroller;
    904
    905    SDL_SYS_JoystickUpdate(gamecontroller->joystick);
    906
    907    return (gamecontroller);
    908}
    909
    910/*
    911 * Manually pump for controller updates.
    912 */
    913void
    914SDL_GameControllerUpdate(void)
    915{
    916    /* Just for API completeness; the joystick API does all the work. */
    917    SDL_JoystickUpdate();
    918}
    919
    920
    921/*
    922 * Get the current state of an axis control on a controller
    923 */
    924Sint16
    925SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
    926{
    927    if (!gamecontroller)
    928        return 0;
    929
    930    if (gamecontroller->mapping.axes[axis] >= 0) {
    931        Sint16 value = (SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axes[axis]));
    932        switch (axis) {
    933            case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
    934            case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
    935                /* Shift it to be 0 - 32767. */
    936                value = value / 2 + 16384;
    937            default:
    938                break;
    939        }
    940        return value;
    941    } else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) {
    942        Uint8 value;
    943        value = SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis]);
    944        if (value > 0)
    945            return 32767;
    946        return 0;
    947    }
    948    return 0;
    949}
    950
    951
    952/*
    953 * Get the current state of a button on a controller
    954 */
    955Uint8
    956SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
    957{
    958    if (!gamecontroller)
    959        return 0;
    960
    961    if (gamecontroller->mapping.buttons[button] >= 0) {
    962        return (SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttons[button]));
    963    } else if (gamecontroller->mapping.axesasbutton[button] >= 0) {
    964        Sint16 value;
    965        value = SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button]);
    966        if (ABS(value) > 32768/2)
    967            return 1;
    968        return 0;
    969    } else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) {
    970        Uint8 value;
    971        value = SDL_JoystickGetHat(gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat);
    972
    973        if (value & gamecontroller->mapping.hatasbutton[button].mask)
    974            return 1;
    975        return 0;
    976    }
    977
    978    return 0;
    979}
    980
    981/*
    982 * Return if the joystick in question is currently attached to the system,
    983 *  \return 0 if not plugged in, 1 if still present.
    984 */
    985SDL_bool
    986SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)
    987{
    988    if (!gamecontroller)
    989        return SDL_FALSE;
    990
    991    return SDL_JoystickGetAttached(gamecontroller->joystick);
    992}
    993
    994
    995/*
    996 * Get the number of multi-dimensional axis controls on a joystick
    997 */
    998const char *
    999SDL_GameControllerName(SDL_GameController * gamecontroller)
   1000{
   1001    if (!gamecontroller)
   1002        return NULL;
   1003
   1004    return (gamecontroller->mapping.name);
   1005}
   1006
   1007
   1008/*
   1009 * Get the joystick for this controller
   1010 */
   1011SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
   1012{
   1013    if (!gamecontroller)
   1014        return NULL;
   1015
   1016    return gamecontroller->joystick;
   1017}
   1018
   1019/**
   1020 * Get the SDL joystick layer binding for this controller axis mapping
   1021 */
   1022SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
   1023{
   1024    SDL_GameControllerButtonBind bind;
   1025    SDL_memset(&bind, 0x0, sizeof(bind));
   1026
   1027    if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
   1028        return bind;
   1029
   1030    if (gamecontroller->mapping.axes[axis] >= 0) {
   1031        bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
   1032        bind.value.button = gamecontroller->mapping.axes[axis];
   1033    } else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) {
   1034        bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   1035        bind.value.button = gamecontroller->mapping.buttonasaxis[axis];
   1036    }
   1037
   1038    return bind;
   1039}
   1040
   1041
   1042/**
   1043 * Get the SDL joystick layer binding for this controller button mapping
   1044 */
   1045SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
   1046{
   1047    SDL_GameControllerButtonBind bind;
   1048    SDL_memset(&bind, 0x0, sizeof(bind));
   1049
   1050    if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
   1051        return bind;
   1052
   1053    if (gamecontroller->mapping.buttons[button] >= 0) {
   1054        bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
   1055        bind.value.button = gamecontroller->mapping.buttons[button];
   1056    } else if (gamecontroller->mapping.axesasbutton[button] >= 0) {
   1057        bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
   1058        bind.value.axis = gamecontroller->mapping.axesasbutton[button];
   1059    } else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) {
   1060        bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
   1061        bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
   1062        bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
   1063    }
   1064
   1065    return bind;
   1066}
   1067
   1068
   1069/*
   1070 * Close a joystick previously opened with SDL_JoystickOpen()
   1071 */
   1072void
   1073SDL_GameControllerClose(SDL_GameController * gamecontroller)
   1074{
   1075    SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
   1076
   1077    if (!gamecontroller)
   1078        return;
   1079
   1080    /* First decrement ref count */
   1081    if (--gamecontroller->ref_count > 0) {
   1082        return;
   1083    }
   1084
   1085    SDL_JoystickClose(gamecontroller->joystick);
   1086
   1087    gamecontrollerlist = SDL_gamecontrollers;
   1088    gamecontrollerlistprev = NULL;
   1089    while (gamecontrollerlist) {
   1090        if (gamecontroller == gamecontrollerlist) {
   1091            if (gamecontrollerlistprev) {
   1092                /* unlink this entry */
   1093                gamecontrollerlistprev->next = gamecontrollerlist->next;
   1094            } else {
   1095                SDL_gamecontrollers = gamecontroller->next;
   1096            }
   1097
   1098            break;
   1099        }
   1100        gamecontrollerlistprev = gamecontrollerlist;
   1101        gamecontrollerlist = gamecontrollerlist->next;
   1102    }
   1103
   1104    SDL_free(gamecontroller);
   1105}
   1106
   1107
   1108/*
   1109 * Quit the controller subsystem
   1110 */
   1111void
   1112SDL_GameControllerQuit(void)
   1113{
   1114    ControllerMapping_t *pControllerMap;
   1115    while (SDL_gamecontrollers) {
   1116        SDL_gamecontrollers->ref_count = 1;
   1117        SDL_GameControllerClose(SDL_gamecontrollers);
   1118    }
   1119
   1120    while (s_pSupportedControllers) {
   1121        pControllerMap = s_pSupportedControllers;
   1122        s_pSupportedControllers = s_pSupportedControllers->next;
   1123        SDL_free(pControllerMap->name);
   1124        SDL_free(pControllerMap->mapping);
   1125        SDL_free(pControllerMap);
   1126    }
   1127
   1128    SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL);
   1129
   1130}
   1131
   1132/*
   1133 * Event filter to transform joystick events into appropriate game controller ones
   1134 */
   1135int
   1136SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
   1137{
   1138    int posted;
   1139
   1140    /* translate the event, if desired */
   1141    posted = 0;
   1142#if !SDL_EVENTS_DISABLED
   1143    if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
   1144        SDL_Event event;
   1145        event.type = SDL_CONTROLLERAXISMOTION;
   1146        event.caxis.which = gamecontroller->joystick->instance_id;
   1147        event.caxis.axis = axis;
   1148        event.caxis.value = value;
   1149        posted = SDL_PushEvent(&event) == 1;
   1150    }
   1151#endif /* !SDL_EVENTS_DISABLED */
   1152    return (posted);
   1153}
   1154
   1155
   1156/*
   1157 * Event filter to transform joystick events into appropriate game controller ones
   1158 */
   1159int
   1160SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
   1161{
   1162    int posted;
   1163#if !SDL_EVENTS_DISABLED
   1164    SDL_Event event;
   1165
   1166    if (button == SDL_CONTROLLER_BUTTON_INVALID)
   1167        return (0);
   1168
   1169    switch (state) {
   1170    case SDL_PRESSED:
   1171        event.type = SDL_CONTROLLERBUTTONDOWN;
   1172        break;
   1173    case SDL_RELEASED:
   1174        event.type = SDL_CONTROLLERBUTTONUP;
   1175        break;
   1176    default:
   1177        /* Invalid state -- bail */
   1178        return (0);
   1179    }
   1180#endif /* !SDL_EVENTS_DISABLED */
   1181
   1182    /* translate the event, if desired */
   1183    posted = 0;
   1184#if !SDL_EVENTS_DISABLED
   1185    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   1186        event.cbutton.which = gamecontroller->joystick->instance_id;
   1187        event.cbutton.button = button;
   1188        event.cbutton.state = state;
   1189        posted = SDL_PushEvent(&event) == 1;
   1190    }
   1191#endif /* !SDL_EVENTS_DISABLED */
   1192    return (posted);
   1193}
   1194
   1195/*
   1196 * Turn off controller events
   1197 */
   1198int
   1199SDL_GameControllerEventState(int state)
   1200{
   1201#if SDL_EVENTS_DISABLED
   1202    return SDL_IGNORE;
   1203#else
   1204    const Uint32 event_list[] = {
   1205        SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
   1206        SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
   1207    };
   1208    unsigned int i;
   1209
   1210    switch (state) {
   1211    case SDL_QUERY:
   1212        state = SDL_IGNORE;
   1213        for (i = 0; i < SDL_arraysize(event_list); ++i) {
   1214            state = SDL_EventState(event_list[i], SDL_QUERY);
   1215            if (state == SDL_ENABLE) {
   1216                break;
   1217            }
   1218        }
   1219        break;
   1220    default:
   1221        for (i = 0; i < SDL_arraysize(event_list); ++i) {
   1222            SDL_EventState(event_list[i], state);
   1223        }
   1224        break;
   1225    }
   1226    return (state);
   1227#endif /* SDL_EVENTS_DISABLED */
   1228}
   1229
   1230/* vi: set ts=4 sw=4 expandtab: */