src/joystick/SDL_gamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 14 Jul 2013 18:17:28 -0700
changeset 7523 9e9ab1dc3811
parent 7422 172b0c6e51d6
child 7677 871d43c6968a
child 8477 ad08f0d710f3
permissions -rw-r--r--
Fixed bug 1919 - Window icon disappears as soon as a renderer is created

Sebastian

Setting a window icon works just fine until a renderer is added to the window.
After adding the renderer the icon disappears.

Reproduce by:
- Take the example code from the wiki: http://wiki.libsdl.org/moin.fcg/SDL_SetWindowIcon

- Add the following two lines after SDL_FreeSurface(surface);
SDL_Delay(1000);
SDL_Renderer* ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

-compile and run

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