test/controllermap.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 07 Dec 2017 16:08:09 -0800
changeset 11730 ac6c607e065c
parent 10930 badc1f1411ef
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Enable building the Metal renderer by default, and weak link the Metal framework so the SDL library is safe to use on older Macs
Also generate iOS versions of the Metal shaders
gabomdq@8043
     1
/*
slouken@10737
     2
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
gabomdq@8043
     3
gabomdq@8043
     4
  This software is provided 'as-is', without any express or implied
gabomdq@8043
     5
  warranty.  In no event will the authors be held liable for any damages
gabomdq@8043
     6
  arising from the use of this software.
gabomdq@8043
     7
gabomdq@8043
     8
  Permission is granted to anyone to use this software for any purpose,
gabomdq@8043
     9
  including commercial applications, and to alter it and redistribute it
gabomdq@8043
    10
  freely.
gabomdq@8043
    11
*/
gabomdq@8043
    12
gabomdq@8043
    13
/* Game controller mapping generator */
gabomdq@8043
    14
/* Gabriel Jacobo <gabomdq@gmail.com> */
gabomdq@8043
    15
gabomdq@8043
    16
#include <stdio.h>
gabomdq@8043
    17
#include <stdlib.h>
gabomdq@8043
    18
#include <string.h>
gabomdq@8043
    19
gabomdq@8043
    20
#include "SDL.h"
gabomdq@8043
    21
gabomdq@8043
    22
#ifndef SDL_JOYSTICK_DISABLED
gabomdq@8043
    23
gabomdq@8043
    24
#ifdef __IPHONEOS__
gabomdq@8043
    25
#define SCREEN_WIDTH    320
gabomdq@8043
    26
#define SCREEN_HEIGHT   480
gabomdq@8043
    27
#else
gabomdq@8043
    28
#define SCREEN_WIDTH    512
slouken@10526
    29
#define SCREEN_HEIGHT   320
gabomdq@8043
    30
#endif
gabomdq@8043
    31
gabomdq@8043
    32
#define MARKER_BUTTON 1
gabomdq@8043
    33
#define MARKER_AXIS 2
gabomdq@8043
    34
slouken@10724
    35
enum
slouken@10724
    36
{
slouken@10724
    37
    SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
slouken@10724
    38
    SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
slouken@10724
    39
    SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
slouken@10724
    40
    SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
slouken@10724
    41
    SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
slouken@10724
    42
    SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
slouken@10724
    43
    SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
slouken@10724
    44
    SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
slouken@10724
    45
    SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
slouken@10724
    46
    SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
slouken@10724
    47
    SDL_CONTROLLER_BINDING_AXIS_MAX,
slouken@10724
    48
};
slouken@10724
    49
slouken@10724
    50
#define BINDING_COUNT (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_MAX)
slouken@10705
    51
slouken@10705
    52
static struct 
gabomdq@8043
    53
{
gabomdq@8043
    54
    int x, y;
gabomdq@8043
    55
    double angle;
gabomdq@8043
    56
    int marker;
slouken@10705
    57
slouken@10705
    58
} s_arrBindingDisplay[BINDING_COUNT] = {
slouken@10705
    59
    { 387, 167, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_A */
slouken@10705
    60
    { 431, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_B */
slouken@10705
    61
    { 342, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_X */
slouken@10705
    62
    { 389, 101, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_Y */
slouken@10705
    63
    { 174, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_BACK */
slouken@10705
    64
    { 233, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_GUIDE */
slouken@10705
    65
    { 289, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_START */
slouken@10705
    66
    {  75, 154, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_LEFTSTICK */
slouken@10705
    67
    { 305, 230, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_RIGHTSTICK */
slouken@10705
    68
    {  77,  40, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_LEFTSHOULDER */
slouken@10705
    69
    { 396,  36, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_RIGHTSHOULDER */
slouken@10705
    70
    { 154, 188, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_UP */
slouken@10705
    71
    { 154, 249, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_DOWN */
slouken@10705
    72
    { 116, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_LEFT */
slouken@10705
    73
    { 186, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_RIGHT */
slouken@10724
    74
    {  74, 153, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE */
slouken@10724
    75
    {  74, 153, 90.0,  MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE */
slouken@10724
    76
    {  74, 153, 0.0,   MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE */
slouken@10724
    77
    {  74, 153, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE */
slouken@10724
    78
    { 306, 231, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE */
slouken@10724
    79
    { 306, 231, 90.0,  MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE */
slouken@10724
    80
    { 306, 231, 0.0,   MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE */
slouken@10724
    81
    { 306, 231, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE */
slouken@10724
    82
    {  91, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT */
slouken@10724
    83
    { 375, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT */
slouken@10705
    84
};
gabomdq@8043
    85
slouken@10705
    86
static int s_arrBindingOrder[BINDING_COUNT] = {
slouken@10705
    87
    SDL_CONTROLLER_BUTTON_A,
slouken@10705
    88
    SDL_CONTROLLER_BUTTON_B,
slouken@10705
    89
    SDL_CONTROLLER_BUTTON_Y,
slouken@10705
    90
    SDL_CONTROLLER_BUTTON_X,
slouken@10724
    91
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
slouken@10724
    92
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
slouken@10724
    93
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
slouken@10724
    94
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
slouken@10705
    95
    SDL_CONTROLLER_BUTTON_LEFTSTICK,
slouken@10724
    96
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
slouken@10724
    97
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
slouken@10724
    98
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
slouken@10724
    99
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
slouken@10705
   100
    SDL_CONTROLLER_BUTTON_RIGHTSTICK,
slouken@10705
   101
    SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
slouken@10724
   102
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
slouken@10705
   103
    SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
slouken@10724
   104
    SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
slouken@10705
   105
    SDL_CONTROLLER_BUTTON_DPAD_UP,
slouken@10705
   106
    SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
slouken@10705
   107
    SDL_CONTROLLER_BUTTON_DPAD_DOWN,
slouken@10705
   108
    SDL_CONTROLLER_BUTTON_DPAD_LEFT,
slouken@10705
   109
    SDL_CONTROLLER_BUTTON_BACK,
slouken@10705
   110
    SDL_CONTROLLER_BUTTON_GUIDE,
slouken@10705
   111
    SDL_CONTROLLER_BUTTON_START,
slouken@10705
   112
};
slouken@10705
   113
slouken@10724
   114
typedef struct
slouken@10724
   115
{
slouken@10724
   116
    SDL_GameControllerBindType bindType;
slouken@10724
   117
    union
slouken@10724
   118
    {
slouken@10724
   119
        int button;
slouken@10724
   120
slouken@10724
   121
        struct {
slouken@10724
   122
            int axis;
slouken@10724
   123
            int axis_min;
slouken@10724
   124
            int axis_max;
slouken@10724
   125
        } axis;
slouken@10724
   126
slouken@10724
   127
        struct {
slouken@10724
   128
            int hat;
slouken@10724
   129
            int hat_mask;
slouken@10724
   130
        } hat;
slouken@10724
   131
slouken@10724
   132
    } value;
slouken@10724
   133
slouken@10824
   134
    SDL_bool committed;
slouken@10824
   135
slouken@10724
   136
} SDL_GameControllerExtendedBind;
slouken@10724
   137
slouken@10724
   138
static SDL_GameControllerExtendedBind s_arrBindings[BINDING_COUNT];
slouken@10724
   139
slouken@10724
   140
typedef struct
slouken@10724
   141
{
slouken@10724
   142
    SDL_bool m_bMoving;
slouken@10724
   143
    int m_nStartingValue;
slouken@10724
   144
    int m_nFarthestValue;
slouken@10724
   145
} AxisState;
slouken@10724
   146
slouken@10724
   147
static int s_nNumAxes;
slouken@10724
   148
static AxisState *s_arrAxisState;
slouken@10724
   149
    
slouken@10705
   150
static int s_iCurrentBinding;
slouken@10705
   151
static Uint32 s_unPendingAdvanceTime;
slouken@10705
   152
static SDL_bool s_bBindingComplete;
gabomdq@8043
   153
gabomdq@8043
   154
SDL_Texture *
philipp@10359
   155
LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent)
gabomdq@8043
   156
{
gabomdq@8043
   157
    SDL_Surface *temp;
gabomdq@8043
   158
    SDL_Texture *texture;
gabomdq@8043
   159
gabomdq@8043
   160
    /* Load the sprite image */
gabomdq@8043
   161
    temp = SDL_LoadBMP(file);
gabomdq@8043
   162
    if (temp == NULL) {
gabomdq@8043
   163
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
gabomdq@8043
   164
        return NULL;
gabomdq@8043
   165
    }
gabomdq@8043
   166
gabomdq@8043
   167
    /* Set transparent pixel as the pixel at (0,0) */
gabomdq@8043
   168
    if (transparent) {
gabomdq@8043
   169
        if (temp->format->palette) {
gabomdq@8043
   170
            SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
gabomdq@8043
   171
        }
gabomdq@8043
   172
    }
gabomdq@8043
   173
gabomdq@8043
   174
    /* Create textures from the image */
gabomdq@8043
   175
    texture = SDL_CreateTextureFromSurface(renderer, temp);
gabomdq@8043
   176
    if (!texture) {
gabomdq@8043
   177
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
gabomdq@8043
   178
        SDL_FreeSurface(temp);
gabomdq@8043
   179
        return NULL;
gabomdq@8043
   180
    }
gabomdq@8043
   181
    SDL_FreeSurface(temp);
gabomdq@8043
   182
gabomdq@8043
   183
    /* We're ready to roll. :) */
gabomdq@8043
   184
    return texture;
gabomdq@8043
   185
}
gabomdq@8043
   186
slouken@10724
   187
static int
slouken@10724
   188
StandardizeAxisValue(int nValue)
slouken@10705
   189
{
slouken@10724
   190
    if (nValue > SDL_JOYSTICK_AXIS_MAX/2) {
slouken@10724
   191
        return SDL_JOYSTICK_AXIS_MAX;
slouken@10724
   192
    } else if (nValue < SDL_JOYSTICK_AXIS_MIN/2) {
slouken@10724
   193
        return SDL_JOYSTICK_AXIS_MIN;
slouken@10724
   194
    } else {
slouken@10724
   195
        return 0;
slouken@10724
   196
    }
slouken@10724
   197
}
slouken@10724
   198
slouken@10724
   199
static void
slouken@10724
   200
SetCurrentBinding(int iBinding)
slouken@10724
   201
{
slouken@10745
   202
    int iIndex;
slouken@10724
   203
    SDL_GameControllerExtendedBind *pBinding;
slouken@10705
   204
slouken@10705
   205
    if (iBinding < 0) {
slouken@10705
   206
        return;
slouken@10705
   207
    }
slouken@10705
   208
slouken@10705
   209
    if (iBinding == BINDING_COUNT) {
slouken@10705
   210
        s_bBindingComplete = SDL_TRUE;
slouken@10705
   211
        return;
slouken@10705
   212
    }
slouken@10705
   213
slouken@10705
   214
    s_iCurrentBinding = iBinding;
slouken@10705
   215
slouken@10705
   216
    pBinding = &s_arrBindings[s_arrBindingOrder[s_iCurrentBinding]];
slouken@10705
   217
    SDL_zerop(pBinding);
slouken@10705
   218
slouken@10745
   219
    for (iIndex = 0; iIndex < s_nNumAxes; ++iIndex) {
slouken@10745
   220
        s_arrAxisState[iIndex].m_nFarthestValue = s_arrAxisState[iIndex].m_nStartingValue;
slouken@10745
   221
    }
slouken@10724
   222
slouken@10705
   223
    s_unPendingAdvanceTime = 0;
slouken@10705
   224
}
slouken@10705
   225
slouken@10745
   226
static SDL_bool
slouken@10745
   227
BBindingContainsBinding(const SDL_GameControllerExtendedBind *pBindingA, const SDL_GameControllerExtendedBind *pBindingB)
slouken@10745
   228
{
slouken@10745
   229
    if (pBindingA->bindType != pBindingB->bindType)
slouken@10745
   230
    {
slouken@10745
   231
        return SDL_FALSE;
slouken@10745
   232
    }
slouken@10745
   233
    switch (pBindingA->bindType)
slouken@10745
   234
    {
slouken@10745
   235
    case SDL_CONTROLLER_BINDTYPE_AXIS:
slouken@10745
   236
        if (pBindingA->value.axis.axis != pBindingB->value.axis.axis) {
slouken@10745
   237
            return SDL_FALSE;
slouken@10745
   238
        }
slouken@10824
   239
        if (!pBindingA->committed) {
slouken@10824
   240
            return SDL_FALSE;
slouken@10824
   241
        }
slouken@10745
   242
        {
slouken@10745
   243
            int minA = SDL_min(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
slouken@10745
   244
            int maxA = SDL_max(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
slouken@10745
   245
            int minB = SDL_min(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
slouken@10745
   246
            int maxB = SDL_max(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
slouken@10745
   247
            return (minA <= minB && maxA >= maxB);
slouken@10745
   248
        }
slouken@10745
   249
        /* Not reached */
slouken@10745
   250
    default:
slouken@10745
   251
        return SDL_memcmp(pBindingA, pBindingB, sizeof(*pBindingA)) == 0;
slouken@10745
   252
    }
slouken@10745
   253
}
slouken@10745
   254
slouken@10705
   255
static void
slouken@10724
   256
ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding)
slouken@10705
   257
{
slouken@10724
   258
    SDL_GameControllerExtendedBind *pCurrent;
slouken@10705
   259
    int iIndex;
slouken@10705
   260
    int iCurrentElement = s_arrBindingOrder[s_iCurrentBinding];
slouken@10705
   261
slouken@10705
   262
    /* Do we already have this binding? */
slouken@10705
   263
    for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
slouken@10745
   264
        pCurrent = &s_arrBindings[iIndex];
slouken@10745
   265
        if (BBindingContainsBinding(pCurrent, pBinding)) {
slouken@10705
   266
            if (iIndex == SDL_CONTROLLER_BUTTON_A && iCurrentElement != SDL_CONTROLLER_BUTTON_B) {
slouken@10705
   267
                /* Skip to the next binding */
slouken@10705
   268
                SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   269
                return;
slouken@10705
   270
            }
slouken@10705
   271
slouken@10705
   272
            if (iIndex == SDL_CONTROLLER_BUTTON_B) {
slouken@10705
   273
                /* Go back to the previous binding */
slouken@10705
   274
                SetCurrentBinding(s_iCurrentBinding - 1);
slouken@10705
   275
                return;
slouken@10705
   276
            }
slouken@10705
   277
slouken@10705
   278
            /* Already have this binding, ignore it */
slouken@10705
   279
            return;
slouken@10705
   280
        }
slouken@10705
   281
    }
slouken@10705
   282
slouken@10824
   283
#ifdef DEBUG_CONTROLLERMAP
slouken@10824
   284
    switch ( pBinding->bindType )
slouken@10824
   285
    {
slouken@10824
   286
    case SDL_CONTROLLER_BINDTYPE_NONE:
slouken@10824
   287
            break;
slouken@10824
   288
    case SDL_CONTROLLER_BINDTYPE_BUTTON:
slouken@10824
   289
            SDL_Log("Configuring button binding for button %d\n", pBinding->value.button);
slouken@10824
   290
            break;
slouken@10824
   291
    case SDL_CONTROLLER_BINDTYPE_AXIS:
slouken@10824
   292
            SDL_Log("Configuring axis binding for axis %d %d/%d committed = %s\n", pBinding->value.axis.axis, pBinding->value.axis.axis_min, pBinding->value.axis.axis_max, pBinding->committed ? "true" : "false");
slouken@10824
   293
            break;
slouken@10824
   294
    case SDL_CONTROLLER_BINDTYPE_HAT:
slouken@10824
   295
            SDL_Log("Configuring hat binding for hat %d %d\n", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
slouken@10824
   296
            break;
slouken@10824
   297
    }
slouken@10824
   298
#endif /* DEBUG_CONTROLLERMAP */
slouken@10824
   299
slouken@10705
   300
    /* Should the new binding override the existing one? */
slouken@10705
   301
    pCurrent = &s_arrBindings[iCurrentElement];
slouken@10705
   302
    if (pCurrent->bindType != SDL_CONTROLLER_BINDTYPE_NONE) {
slouken@10705
   303
        SDL_bool bNativeDPad, bCurrentDPad;
slouken@10705
   304
        SDL_bool bNativeAxis, bCurrentAxis;
slouken@10705
   305
        
slouken@10705
   306
        bNativeDPad = (iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_UP ||
slouken@10705
   307
                       iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_DOWN ||
slouken@10705
   308
                       iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_LEFT ||
slouken@10705
   309
                       iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
slouken@10705
   310
        bCurrentDPad = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_HAT);
slouken@10824
   311
        if (bNativeDPad && bCurrentDPad) {
slouken@10705
   312
            /* We already have a binding of the type we want, ignore the new one */
slouken@10705
   313
            return;
slouken@10705
   314
        }
slouken@10705
   315
slouken@10705
   316
        bNativeAxis = (iCurrentElement >= SDL_CONTROLLER_BUTTON_MAX);
slouken@10705
   317
        bCurrentAxis = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_AXIS);
slouken@10745
   318
        if (bNativeAxis == bCurrentAxis &&
slouken@10745
   319
            (pBinding->bindType != SDL_CONTROLLER_BINDTYPE_AXIS ||
slouken@10745
   320
             pBinding->value.axis.axis != pCurrent->value.axis.axis)) {
slouken@10705
   321
            /* We already have a binding of the type we want, ignore the new one */
slouken@10705
   322
            return;
slouken@10705
   323
        }
slouken@10705
   324
    }
slouken@10705
   325
slouken@10705
   326
    *pCurrent = *pBinding;
slouken@10705
   327
slouken@10824
   328
    if (pBinding->committed) {
slouken@10824
   329
        s_unPendingAdvanceTime = SDL_GetTicks();
slouken@10824
   330
    } else {
slouken@10824
   331
        s_unPendingAdvanceTime = 0;
slouken@10824
   332
    }
slouken@10705
   333
}
slouken@10705
   334
slouken@10724
   335
static SDL_bool
slouken@10724
   336
BMergeAxisBindings(int iIndex)
slouken@10724
   337
{
slouken@10724
   338
    SDL_GameControllerExtendedBind *pBindingA = &s_arrBindings[iIndex];
slouken@10724
   339
    SDL_GameControllerExtendedBind *pBindingB = &s_arrBindings[iIndex+1];
slouken@10724
   340
    if (pBindingA->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
slouken@10724
   341
        pBindingB->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
slouken@10724
   342
        pBindingA->value.axis.axis == pBindingB->value.axis.axis) {
slouken@10724
   343
        if (pBindingA->value.axis.axis_min == pBindingB->value.axis.axis_min) {
slouken@10724
   344
            pBindingA->value.axis.axis_min = pBindingA->value.axis.axis_max;
slouken@10724
   345
            pBindingA->value.axis.axis_max = pBindingB->value.axis.axis_max;
slouken@10724
   346
            pBindingB->bindType = SDL_CONTROLLER_BINDTYPE_NONE;
slouken@10724
   347
            return SDL_TRUE;
slouken@10724
   348
        }
slouken@10724
   349
    }
slouken@10724
   350
    return SDL_FALSE;
slouken@10724
   351
}
slouken@10724
   352
slouken@10705
   353
static void
gabomdq@8043
   354
WatchJoystick(SDL_Joystick * joystick)
gabomdq@8043
   355
{
gabomdq@8043
   356
    SDL_Window *window = NULL;
gabomdq@8043
   357
    SDL_Renderer *screen = NULL;
icculus@8202
   358
    SDL_Texture *background, *button, *axis, *marker;
gabomdq@8043
   359
    const char *name = NULL;
slouken@10705
   360
    SDL_bool done = SDL_FALSE;
gabomdq@8043
   361
    SDL_Event event;
gabomdq@8043
   362
    SDL_Rect dst;
gabomdq@8043
   363
    Uint8 alpha=200, alpha_step = -1;
philipp@8786
   364
    Uint32 alpha_ticks = 0;
slouken@10705
   365
    SDL_JoystickID nJoystickID;
slouken@10752
   366
    int iIndex;
gabomdq@8043
   367
gabomdq@8043
   368
    /* Create a window to display joystick axis position */
gabomdq@8046
   369
    window = SDL_CreateWindow("Game Controller Map", SDL_WINDOWPOS_CENTERED,
gabomdq@8043
   370
                              SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
gabomdq@8043
   371
                              SCREEN_HEIGHT, 0);
gabomdq@8043
   372
    if (window == NULL) {
gabomdq@8043
   373
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
slouken@10705
   374
        return;
gabomdq@8043
   375
    }
gabomdq@8043
   376
gabomdq@8043
   377
    screen = SDL_CreateRenderer(window, -1, 0);
gabomdq@8043
   378
    if (screen == NULL) {
gabomdq@8043
   379
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
gabomdq@8043
   380
        SDL_DestroyWindow(window);
slouken@10705
   381
        return;
gabomdq@8043
   382
    }
gabomdq@8043
   383
    
gabomdq@8043
   384
    background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
gabomdq@8043
   385
    button = LoadTexture(screen, "button.bmp", SDL_TRUE);
gabomdq@8043
   386
    axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
gabomdq@8043
   387
    SDL_RaiseWindow(window);
gabomdq@8043
   388
icculus@8202
   389
    /* scale for platforms that don't give you the window size you asked for. */
icculus@8202
   390
    SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
icculus@8202
   391
gabomdq@8043
   392
    /* Print info about the joystick we are watching */
gabomdq@8043
   393
    name = SDL_JoystickName(joystick);
gabomdq@8043
   394
    SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick),
gabomdq@8043
   395
           name ? name : "Unknown Joystick");
gabomdq@8043
   396
    SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
gabomdq@8043
   397
           SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
gabomdq@8043
   398
           SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
gabomdq@8043
   399
    
gabomdq@8043
   400
    SDL_Log("\n\n\
gabomdq@8043
   401
    ====================================================================================\n\
gabomdq@8043
   402
    Press the buttons on your controller when indicated\n\
gabomdq@8043
   403
    (Your controller may look different than the picture)\n\
gabomdq@8043
   404
    If you want to correct a mistake, press backspace or the back button on your device\n\
gabomdq@8046
   405
    To skip a button, press SPACE or click/touch the screen\n\
gabomdq@8043
   406
    To exit, press ESC\n\
gabomdq@8043
   407
    ====================================================================================\n");
slouken@10705
   408
slouken@10705
   409
    nJoystickID = SDL_JoystickInstanceID(joystick);
gabomdq@8043
   410
slouken@10724
   411
    s_nNumAxes = SDL_JoystickNumAxes(joystick);
philipp@10930
   412
    s_arrAxisState = (AxisState *)SDL_calloc(s_nNumAxes, sizeof(*s_arrAxisState));
slouken@10752
   413
    for (iIndex = 0; iIndex < s_nNumAxes; ++iIndex) {
slouken@10752
   414
        AxisState *pAxisState = &s_arrAxisState[iIndex];
slouken@10752
   415
        Sint16 nInitialValue;
slouken@10752
   416
        pAxisState->m_bMoving = SDL_JoystickGetAxisInitialState(joystick, iIndex, &nInitialValue);
slouken@10752
   417
        pAxisState->m_nStartingValue = nInitialValue;
slouken@10752
   418
        pAxisState->m_nFarthestValue = nInitialValue;
slouken@10752
   419
    }
slouken@10724
   420
gabomdq@8043
   421
    /* Loop, getting joystick events! */
slouken@10705
   422
    while (!done && !s_bBindingComplete) {
slouken@10705
   423
        int iElement = s_arrBindingOrder[s_iCurrentBinding];
slouken@10705
   424
slouken@10705
   425
        switch (s_arrBindingDisplay[iElement].marker) {
gabomdq@8043
   426
            case MARKER_AXIS:
gabomdq@8043
   427
                marker = axis;
gabomdq@8043
   428
                break;
gabomdq@8043
   429
            case MARKER_BUTTON:
gabomdq@8043
   430
                marker = button;
gabomdq@8043
   431
                break;
gabomdq@8043
   432
            default:
gabomdq@8043
   433
                break;
gabomdq@8043
   434
        }
gabomdq@8043
   435
        
slouken@10705
   436
        dst.x = s_arrBindingDisplay[iElement].x;
slouken@10705
   437
        dst.y = s_arrBindingDisplay[iElement].y;
gabomdq@8043
   438
        SDL_QueryTexture(marker, NULL, NULL, &dst.w, &dst.h);
icculus@8202
   439
slouken@10705
   440
        if (SDL_GetTicks() - alpha_ticks > 5) {
slouken@10705
   441
            alpha_ticks = SDL_GetTicks();
slouken@10705
   442
            alpha += alpha_step;
slouken@10705
   443
            if (alpha == 255) {
slouken@10705
   444
                alpha_step = -1;
gabomdq@8043
   445
            }
slouken@10705
   446
            if (alpha < 128) {
slouken@10705
   447
                alpha_step = 1;
gabomdq@8043
   448
            }
gabomdq@8043
   449
        }
gabomdq@8043
   450
slouken@10705
   451
        SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
slouken@10705
   452
        SDL_RenderClear(screen);
slouken@10705
   453
        SDL_RenderCopy(screen, background, NULL, NULL);
slouken@10705
   454
        SDL_SetTextureAlphaMod(marker, alpha);
slouken@10705
   455
        SDL_SetTextureColorMod(marker, 10, 255, 21);
slouken@10705
   456
        SDL_RenderCopyEx(screen, marker, NULL, &dst, s_arrBindingDisplay[iElement].angle, NULL, SDL_FLIP_NONE);
slouken@10705
   457
        SDL_RenderPresent(screen);
slouken@10705
   458
            
slouken@10705
   459
        while (SDL_PollEvent(&event) > 0) {
slouken@10705
   460
            switch (event.type) {
slouken@10705
   461
            case SDL_JOYDEVICEREMOVED:
slouken@10705
   462
                if (event.jaxis.which == nJoystickID) {
slouken@10705
   463
                    done = SDL_TRUE;
slouken@10705
   464
                }
slouken@10705
   465
                break;
slouken@10705
   466
            case SDL_JOYAXISMOTION:
slouken@10705
   467
                if (event.jaxis.which == nJoystickID) {
slouken@10724
   468
                    AxisState *pAxisState = &s_arrAxisState[event.jaxis.axis];
slouken@10724
   469
                    int nValue = event.jaxis.value;
slouken@10724
   470
                    int nCurrentDistance, nFarthestDistance;
slouken@10724
   471
                    if (!pAxisState->m_bMoving) {
slouken@10724
   472
                        pAxisState->m_bMoving = SDL_TRUE;
slouken@10724
   473
                        pAxisState->m_nStartingValue = nValue;
slouken@10724
   474
                        pAxisState->m_nFarthestValue = nValue;
slouken@10724
   475
                    }
slouken@10724
   476
                    nCurrentDistance = SDL_abs(nValue - pAxisState->m_nStartingValue);
slouken@10724
   477
                    nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
slouken@10724
   478
                    if (nCurrentDistance > nFarthestDistance) {
slouken@10724
   479
                        pAxisState->m_nFarthestValue = nValue;
slouken@10824
   480
                        nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
slouken@10724
   481
                    }
slouken@10824
   482
slouken@10824
   483
#ifdef DEBUG_CONTROLLERMAP
slouken@10824
   484
                    SDL_Log("AXIS %d nValue %d nCurrentDistance %d nFarthestDistance %d\n", event.jaxis.axis, nValue, nCurrentDistance, nFarthestDistance);
slouken@10824
   485
#endif
slouken@10824
   486
                    if (nFarthestDistance >= 16000) {
slouken@10824
   487
                        /* If we've gone out far enough and started to come back, let's bind this axis */
slouken@10824
   488
                        SDL_bool bCommitBinding = (nCurrentDistance <= 10000) ? SDL_TRUE : SDL_FALSE;
slouken@10724
   489
                        SDL_GameControllerExtendedBind binding;
slouken@10705
   490
                        SDL_zero(binding);
slouken@10705
   491
                        binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
slouken@10724
   492
                        binding.value.axis.axis = event.jaxis.axis;
slouken@10724
   493
                        binding.value.axis.axis_min = StandardizeAxisValue(pAxisState->m_nStartingValue);
slouken@10724
   494
                        binding.value.axis.axis_max = StandardizeAxisValue(pAxisState->m_nFarthestValue);
slouken@10824
   495
                        binding.committed = bCommitBinding;
slouken@10705
   496
                        ConfigureBinding(&binding);
slouken@10705
   497
                    }
slouken@10705
   498
                }
slouken@10705
   499
                break;
slouken@10705
   500
            case SDL_JOYHATMOTION:
slouken@10705
   501
                if (event.jhat.which == nJoystickID) {
slouken@10705
   502
                    if (event.jhat.value != SDL_HAT_CENTERED) {
slouken@10724
   503
                        SDL_GameControllerExtendedBind binding;
slouken@10824
   504
slouken@10824
   505
#ifdef DEBUG_CONTROLLERMAP
slouken@10824
   506
                        SDL_Log("HAT %d %d\n", event.jhat.hat, event.jhat.value);
slouken@10824
   507
#endif
slouken@10705
   508
                        SDL_zero(binding);
slouken@10705
   509
                        binding.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
slouken@10705
   510
                        binding.value.hat.hat = event.jhat.hat;
slouken@10705
   511
                        binding.value.hat.hat_mask = event.jhat.value;
slouken@10824
   512
                        binding.committed = SDL_TRUE;
slouken@10705
   513
                        ConfigureBinding(&binding);
slouken@10705
   514
                    }
slouken@10705
   515
                }
slouken@10705
   516
                break;
slouken@10705
   517
            case SDL_JOYBALLMOTION:
slouken@10705
   518
                break;
slouken@10705
   519
            case SDL_JOYBUTTONDOWN:
slouken@10705
   520
                if (event.jbutton.which == nJoystickID) {
slouken@10724
   521
                    SDL_GameControllerExtendedBind binding;
slouken@10824
   522
slouken@10824
   523
#ifdef DEBUG_CONTROLLERMAP
slouken@10824
   524
                    SDL_Log("BUTTON %d\n", event.jbutton.button);
slouken@10824
   525
#endif
slouken@10705
   526
                    SDL_zero(binding);
slouken@10705
   527
                    binding.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
slouken@10705
   528
                    binding.value.button = event.jbutton.button;
slouken@10824
   529
                    binding.committed = SDL_TRUE;
slouken@10705
   530
                    ConfigureBinding(&binding);
slouken@10705
   531
                }
slouken@10705
   532
                break;
slouken@10705
   533
            case SDL_FINGERDOWN:
slouken@10705
   534
            case SDL_MOUSEBUTTONDOWN:
slouken@10705
   535
                /* Skip this step */
slouken@10705
   536
                SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   537
                break;
slouken@10705
   538
            case SDL_KEYDOWN:
slouken@10705
   539
                if (event.key.keysym.sym == SDLK_BACKSPACE || event.key.keysym.sym == SDLK_AC_BACK) {
slouken@10705
   540
                    SetCurrentBinding(s_iCurrentBinding - 1);
slouken@10705
   541
                    break;
slouken@10705
   542
                }
slouken@10705
   543
                if (event.key.keysym.sym == SDLK_SPACE) {
slouken@10705
   544
                    SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   545
                    break;
slouken@10705
   546
                }
slouken@10705
   547
slouken@10705
   548
                if ((event.key.keysym.sym != SDLK_ESCAPE)) {
slouken@10705
   549
                    break;
slouken@10705
   550
                }
slouken@10705
   551
                /* Fall through to signal quit */
slouken@10705
   552
            case SDL_QUIT:
slouken@10705
   553
                done = SDL_TRUE;
slouken@10705
   554
                break;
slouken@10705
   555
            default:
slouken@10705
   556
                break;
slouken@10705
   557
            }
slouken@10705
   558
        }
slouken@10705
   559
slouken@10705
   560
        SDL_Delay(15);
slouken@10705
   561
slouken@10705
   562
        /* Wait 100 ms for joystick events to stop coming in,
slouken@10705
   563
           in case a controller sends multiple events for a single control (e.g. axis and button for trigger)
slouken@10705
   564
        */
slouken@10705
   565
        if (s_unPendingAdvanceTime && SDL_GetTicks() - s_unPendingAdvanceTime >= 100) {
slouken@10705
   566
            SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   567
        }
gabomdq@8043
   568
    }
gabomdq@8043
   569
slouken@10705
   570
    if (s_bBindingComplete) {
slouken@10705
   571
        char mapping[1024];
slouken@10705
   572
        char trimmed_name[128];
slouken@10705
   573
        char *spot;
slouken@10705
   574
        int iIndex;
slouken@10705
   575
        char pszElement[12];
slouken@10705
   576
slouken@10705
   577
        SDL_strlcpy(trimmed_name, name, SDL_arraysize(trimmed_name));
slouken@10705
   578
        while (SDL_isspace(trimmed_name[0])) {
slouken@10705
   579
            SDL_memmove(&trimmed_name[0], &trimmed_name[1], SDL_strlen(trimmed_name));
slouken@10705
   580
        }
slouken@10705
   581
        while (trimmed_name[0] && SDL_isspace(trimmed_name[SDL_strlen(trimmed_name) - 1])) {
slouken@10705
   582
            trimmed_name[SDL_strlen(trimmed_name) - 1] = '\0';
slouken@10705
   583
        }
slouken@10705
   584
        while ((spot = SDL_strchr(trimmed_name, ',')) != NULL) {
slouken@10705
   585
            SDL_memmove(spot, spot + 1, SDL_strlen(spot));
slouken@10705
   586
        }
slouken@10705
   587
slouken@10705
   588
        /* Initialize mapping with GUID and name */
slouken@10705
   589
        SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), mapping, SDL_arraysize(mapping));
slouken@10705
   590
        SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   591
        SDL_strlcat(mapping, trimmed_name, SDL_arraysize(mapping));
slouken@10705
   592
        SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   593
        SDL_strlcat(mapping, "platform:", SDL_arraysize(mapping));
slouken@10705
   594
        SDL_strlcat(mapping, SDL_GetPlatform(), SDL_arraysize(mapping));
slouken@10705
   595
        SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   596
slouken@10705
   597
        for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
slouken@10724
   598
            SDL_GameControllerExtendedBind *pBinding = &s_arrBindings[iIndex];
slouken@10705
   599
            if (pBinding->bindType == SDL_CONTROLLER_BINDTYPE_NONE) {
slouken@10705
   600
                continue;
slouken@10705
   601
            }
slouken@10705
   602
slouken@10705
   603
            if (iIndex < SDL_CONTROLLER_BUTTON_MAX) {
slouken@10705
   604
                SDL_GameControllerButton eButton = (SDL_GameControllerButton)iIndex;
slouken@10705
   605
                SDL_strlcat(mapping, SDL_GameControllerGetStringForButton(eButton), SDL_arraysize(mapping));
slouken@10705
   606
            } else {
slouken@10724
   607
                const char *pszAxisName;
slouken@10724
   608
                switch (iIndex - SDL_CONTROLLER_BUTTON_MAX) {
slouken@10724
   609
                case SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE:
slouken@10724
   610
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   611
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   612
                    }
slouken@10724
   613
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
slouken@10724
   614
                    break;
slouken@10724
   615
                case SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE:
slouken@10724
   616
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   617
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
slouken@10724
   618
                    break;
slouken@10724
   619
                case SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE:
slouken@10724
   620
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   621
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   622
                    }
slouken@10724
   623
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
slouken@10724
   624
                    break;
slouken@10724
   625
                case SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE:
slouken@10724
   626
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   627
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
slouken@10724
   628
                    break;
slouken@10724
   629
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE:
slouken@10724
   630
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   631
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   632
                    }
slouken@10724
   633
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
slouken@10724
   634
                    break;
slouken@10724
   635
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE:
slouken@10724
   636
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   637
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
slouken@10724
   638
                    break;
slouken@10724
   639
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE:
slouken@10724
   640
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   641
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   642
                    }
slouken@10724
   643
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
slouken@10724
   644
                    break;
slouken@10724
   645
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE:
slouken@10724
   646
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   647
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
slouken@10724
   648
                    break;
slouken@10724
   649
                case SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT:
slouken@10724
   650
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
slouken@10724
   651
                    break;
slouken@10724
   652
                case SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT:
slouken@10724
   653
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
slouken@10724
   654
                    break;
slouken@10724
   655
                }
slouken@10724
   656
                SDL_strlcat(mapping, pszAxisName, SDL_arraysize(mapping));
slouken@10705
   657
            }
slouken@10705
   658
            SDL_strlcat(mapping, ":", SDL_arraysize(mapping));
slouken@10705
   659
slouken@10705
   660
            pszElement[0] = '\0';
slouken@10705
   661
            switch (pBinding->bindType) {
slouken@10705
   662
            case SDL_CONTROLLER_BINDTYPE_BUTTON:
slouken@10705
   663
                SDL_snprintf(pszElement, sizeof(pszElement), "b%d", pBinding->value.button);
slouken@10705
   664
                break;
slouken@10705
   665
            case SDL_CONTROLLER_BINDTYPE_AXIS:
slouken@10724
   666
                if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MIN) {
slouken@10724
   667
                    /* The negative half axis */
slouken@10724
   668
                    SDL_snprintf(pszElement, sizeof(pszElement), "-a%d", pBinding->value.axis.axis);
slouken@10724
   669
                } else if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MAX) {
slouken@10724
   670
                    /* The positive half axis */
slouken@10724
   671
                    SDL_snprintf(pszElement, sizeof(pszElement), "+a%d", pBinding->value.axis.axis);
slouken@10724
   672
                } else {
slouken@10724
   673
                    SDL_snprintf(pszElement, sizeof(pszElement), "a%d", pBinding->value.axis.axis);
slouken@10724
   674
                    if (pBinding->value.axis.axis_min > pBinding->value.axis.axis_max) {
slouken@10724
   675
                        /* Invert the axis */
slouken@10724
   676
                        SDL_strlcat(pszElement, "~", SDL_arraysize(pszElement));
slouken@10724
   677
                    }
slouken@10724
   678
                }
slouken@10705
   679
                break;
slouken@10705
   680
            case SDL_CONTROLLER_BINDTYPE_HAT:
slouken@10705
   681
                SDL_snprintf(pszElement, sizeof(pszElement), "h%d.%d", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
slouken@10705
   682
                break;
slouken@10705
   683
            default:
slouken@10705
   684
                SDL_assert(!"Unknown bind type");
slouken@10705
   685
                break;
slouken@10705
   686
            }
slouken@10705
   687
            SDL_strlcat(mapping, pszElement, SDL_arraysize(mapping));
slouken@10705
   688
            SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   689
        }
slouken@10705
   690
gabomdq@8043
   691
        SDL_Log("Mapping:\n\n%s\n\n", mapping);
gabomdq@8043
   692
        /* Print to stdout as well so the user can cat the output somewhere */
gabomdq@8043
   693
        printf("%s\n", mapping);
gabomdq@8043
   694
    }
slouken@10724
   695
slouken@10724
   696
    SDL_free(s_arrAxisState);
slouken@10724
   697
    s_arrAxisState = NULL;
gabomdq@8043
   698
    
gabomdq@8043
   699
    SDL_DestroyRenderer(screen);
gabomdq@8043
   700
    SDL_DestroyWindow(window);
gabomdq@8043
   701
}
gabomdq@8043
   702
gabomdq@8043
   703
int
gabomdq@8043
   704
main(int argc, char *argv[])
gabomdq@8043
   705
{
gabomdq@8043
   706
    const char *name;
gabomdq@8043
   707
    int i;
gabomdq@8043
   708
    SDL_Joystick *joystick;
gabomdq@8043
   709
gabomdq@8043
   710
    /* Enable standard application logging */
philipp@9922
   711
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
gabomdq@8043
   712
gabomdq@8043
   713
    /* Initialize SDL (Note: video is required to start event loop) */
gabomdq@8043
   714
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
gabomdq@8043
   715
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
gabomdq@8043
   716
        exit(1);
gabomdq@8043
   717
    }
gabomdq@8043
   718
gabomdq@8043
   719
    /* Print information about the joysticks */
gabomdq@8043
   720
    SDL_Log("There are %d joysticks attached\n", SDL_NumJoysticks());
gabomdq@8043
   721
    for (i = 0; i < SDL_NumJoysticks(); ++i) {
gabomdq@8043
   722
        name = SDL_JoystickNameForIndex(i);
gabomdq@8043
   723
        SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
gabomdq@8043
   724
        joystick = SDL_JoystickOpen(i);
gabomdq@8043
   725
        if (joystick == NULL) {
gabomdq@8043
   726
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
gabomdq@8043
   727
                    SDL_GetError());
gabomdq@8043
   728
        } else {
gabomdq@8043
   729
            char guid[64];
gabomdq@8043
   730
            SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
gabomdq@8043
   731
                                      guid, sizeof (guid));
gabomdq@8043
   732
            SDL_Log("       axes: %d\n", SDL_JoystickNumAxes(joystick));
gabomdq@8043
   733
            SDL_Log("      balls: %d\n", SDL_JoystickNumBalls(joystick));
gabomdq@8043
   734
            SDL_Log("       hats: %d\n", SDL_JoystickNumHats(joystick));
gabomdq@8043
   735
            SDL_Log("    buttons: %d\n", SDL_JoystickNumButtons(joystick));
gabomdq@8043
   736
            SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick));
gabomdq@8043
   737
            SDL_Log("       guid: %s\n", guid);
slouken@10597
   738
            SDL_Log("    VID/PID: 0x%.4x/0x%.4x\n", SDL_JoystickGetVendor(joystick), SDL_JoystickGetProduct(joystick));
gabomdq@8043
   739
            SDL_JoystickClose(joystick);
gabomdq@8043
   740
        }
gabomdq@8043
   741
    }
gabomdq@8043
   742
gabomdq@8762
   743
#ifdef __ANDROID__
gabomdq@8043
   744
    if (SDL_NumJoysticks() > 0) {
gabomdq@8043
   745
#else
gabomdq@8043
   746
    if (argv[1]) {
gabomdq@8043
   747
#endif
philipp@8078
   748
        int device;
gabomdq@8762
   749
#ifdef __ANDROID__
philipp@8078
   750
        device = 0;
gabomdq@8043
   751
#else
philipp@8078
   752
        device = atoi(argv[1]);
gabomdq@8043
   753
#endif
philipp@8078
   754
        joystick = SDL_JoystickOpen(device);
slouken@10705
   755
        if (joystick == NULL) {
slouken@10705
   756
            SDL_Log("Couldn't open joystick %d: %s\n", device, SDL_GetError());
slouken@10705
   757
        } else {
slouken@10705
   758
            WatchJoystick(joystick);
slouken@10705
   759
            SDL_JoystickClose(joystick);
gabomdq@8043
   760
        }
gabomdq@8043
   761
    }
gabomdq@8043
   762
    else {
gabomdq@8043
   763
        SDL_Log("\n\nUsage: ./controllermap number\nFor example: ./controllermap 0\nOr: ./controllermap 0 >> gamecontrollerdb.txt");
gabomdq@8043
   764
    }
gabomdq@8043
   765
    SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
gabomdq@8043
   766
gabomdq@8043
   767
    return 0;
gabomdq@8043
   768
}
gabomdq@8043
   769
gabomdq@8043
   770
#else
gabomdq@8043
   771
gabomdq@8043
   772
int
gabomdq@8043
   773
main(int argc, char *argv[])
gabomdq@8043
   774
{
gabomdq@8043
   775
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
gabomdq@8043
   776
    exit(1);
gabomdq@8043
   777
}
gabomdq@8043
   778
gabomdq@8043
   779
#endif
slouken@10597
   780
slouken@10597
   781
/* vi: set ts=4 sw=4 expandtab: */