test/controllermap.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 03 Jan 2017 23:39:28 -0800
changeset 10745 7461fcef6ae2
parent 10737 3406a0f8b041
child 10747 da1f4eeac65a
permissions -rw-r--r--
Fixed binding the D-pad on some Super NES style controllers
Fixed a case where partial trigger pull could be bound to another button

There is a fundamental problem not resolved by this commit:

Some controllers have axes (triggers, pedals, etc.) that don't start at zero, but we're guaranteed that if we get a value that it's correct. For these controllers, the current code works, where we take the first value we get and use that as the zero point and generate axis motion starting from that point on.

Other controllers have digital axes (D-pad) that assume a zero starting point, and the first value we get is the min or max axis value when the D-pad is moved. For these controllers, the current code thinks that the zero point is the axis value after the D-pad motion and this doesn't work.

My hypothesis is that the first class of devices is more common and that we should solve for that, and add an exception to SDL_JoystickAxesCenteredAtZero() as needed for the second class of devices.
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;
gabomdq@8043
    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
};
slouken@10705
    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@10724
   134
} SDL_GameControllerExtendedBind;
slouken@10724
   135
slouken@10724
   136
static SDL_GameControllerExtendedBind s_arrBindings[BINDING_COUNT];
slouken@10724
   137
slouken@10724
   138
typedef struct
slouken@10724
   139
{
slouken@10724
   140
    SDL_bool m_bMoving;
slouken@10724
   141
    int m_nStartingValue;
slouken@10724
   142
    int m_nFarthestValue;
slouken@10724
   143
} AxisState;
slouken@10724
   144
slouken@10724
   145
static int s_nNumAxes;
slouken@10724
   146
static AxisState *s_arrAxisState;
slouken@10724
   147
    
slouken@10705
   148
static int s_iCurrentBinding;
slouken@10705
   149
static Uint32 s_unPendingAdvanceTime;
slouken@10705
   150
static SDL_bool s_bBindingComplete;
gabomdq@8043
   151
gabomdq@8043
   152
SDL_Texture *
philipp@10359
   153
LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent)
gabomdq@8043
   154
{
gabomdq@8043
   155
    SDL_Surface *temp;
gabomdq@8043
   156
    SDL_Texture *texture;
gabomdq@8043
   157
gabomdq@8043
   158
    /* Load the sprite image */
gabomdq@8043
   159
    temp = SDL_LoadBMP(file);
gabomdq@8043
   160
    if (temp == NULL) {
gabomdq@8043
   161
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
gabomdq@8043
   162
        return NULL;
gabomdq@8043
   163
    }
gabomdq@8043
   164
gabomdq@8043
   165
    /* Set transparent pixel as the pixel at (0,0) */
gabomdq@8043
   166
    if (transparent) {
gabomdq@8043
   167
        if (temp->format->palette) {
gabomdq@8043
   168
            SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
gabomdq@8043
   169
        }
gabomdq@8043
   170
    }
gabomdq@8043
   171
gabomdq@8043
   172
    /* Create textures from the image */
gabomdq@8043
   173
    texture = SDL_CreateTextureFromSurface(renderer, temp);
gabomdq@8043
   174
    if (!texture) {
gabomdq@8043
   175
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
gabomdq@8043
   176
        SDL_FreeSurface(temp);
gabomdq@8043
   177
        return NULL;
gabomdq@8043
   178
    }
gabomdq@8043
   179
    SDL_FreeSurface(temp);
gabomdq@8043
   180
gabomdq@8043
   181
    /* We're ready to roll. :) */
gabomdq@8043
   182
    return texture;
gabomdq@8043
   183
}
gabomdq@8043
   184
slouken@10724
   185
static int
slouken@10724
   186
StandardizeAxisValue(int nValue)
slouken@10705
   187
{
slouken@10724
   188
    if (nValue > SDL_JOYSTICK_AXIS_MAX/2) {
slouken@10724
   189
        return SDL_JOYSTICK_AXIS_MAX;
slouken@10724
   190
    } else if (nValue < SDL_JOYSTICK_AXIS_MIN/2) {
slouken@10724
   191
        return SDL_JOYSTICK_AXIS_MIN;
slouken@10724
   192
    } else {
slouken@10724
   193
        return 0;
slouken@10724
   194
    }
slouken@10724
   195
}
slouken@10724
   196
slouken@10724
   197
static void
slouken@10724
   198
SetCurrentBinding(int iBinding)
slouken@10724
   199
{
slouken@10745
   200
    int iIndex;
slouken@10724
   201
    SDL_GameControllerExtendedBind *pBinding;
slouken@10705
   202
slouken@10705
   203
    if (iBinding < 0) {
slouken@10705
   204
        return;
slouken@10705
   205
    }
slouken@10705
   206
slouken@10705
   207
    if (iBinding == BINDING_COUNT) {
slouken@10705
   208
        s_bBindingComplete = SDL_TRUE;
slouken@10705
   209
        return;
slouken@10705
   210
    }
slouken@10705
   211
slouken@10705
   212
    s_iCurrentBinding = iBinding;
slouken@10705
   213
slouken@10705
   214
    pBinding = &s_arrBindings[s_arrBindingOrder[s_iCurrentBinding]];
slouken@10705
   215
    SDL_zerop(pBinding);
slouken@10705
   216
slouken@10745
   217
    for (iIndex = 0; iIndex < s_nNumAxes; ++iIndex) {
slouken@10745
   218
        s_arrAxisState[iIndex].m_nFarthestValue = s_arrAxisState[iIndex].m_nStartingValue;
slouken@10745
   219
    }
slouken@10724
   220
slouken@10705
   221
    s_unPendingAdvanceTime = 0;
slouken@10705
   222
}
slouken@10705
   223
slouken@10745
   224
static SDL_bool
slouken@10745
   225
BBindingContainsBinding(const SDL_GameControllerExtendedBind *pBindingA, const SDL_GameControllerExtendedBind *pBindingB)
slouken@10745
   226
{
slouken@10745
   227
    if (pBindingA->bindType != pBindingB->bindType)
slouken@10745
   228
    {
slouken@10745
   229
        return SDL_FALSE;
slouken@10745
   230
    }
slouken@10745
   231
    switch (pBindingA->bindType)
slouken@10745
   232
    {
slouken@10745
   233
    case SDL_CONTROLLER_BINDTYPE_AXIS:
slouken@10745
   234
        if (pBindingA->value.axis.axis != pBindingB->value.axis.axis) {
slouken@10745
   235
            return SDL_FALSE;
slouken@10745
   236
        }
slouken@10745
   237
        {
slouken@10745
   238
            int minA = SDL_min(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
slouken@10745
   239
            int maxA = SDL_max(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
slouken@10745
   240
            int minB = SDL_min(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
slouken@10745
   241
            int maxB = SDL_max(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
slouken@10745
   242
            return (minA <= minB && maxA >= maxB);
slouken@10745
   243
        }
slouken@10745
   244
        /* Not reached */
slouken@10745
   245
    default:
slouken@10745
   246
        return SDL_memcmp(pBindingA, pBindingB, sizeof(*pBindingA)) == 0;
slouken@10745
   247
    }
slouken@10745
   248
}
slouken@10745
   249
slouken@10705
   250
static void
slouken@10724
   251
ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding)
slouken@10705
   252
{
slouken@10724
   253
    SDL_GameControllerExtendedBind *pCurrent;
slouken@10705
   254
    int iIndex;
slouken@10705
   255
    int iCurrentElement = s_arrBindingOrder[s_iCurrentBinding];
slouken@10705
   256
slouken@10705
   257
    /* Do we already have this binding? */
slouken@10705
   258
    for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
slouken@10745
   259
        pCurrent = &s_arrBindings[iIndex];
slouken@10745
   260
        if (BBindingContainsBinding(pCurrent, pBinding)) {
slouken@10705
   261
            if (iIndex == SDL_CONTROLLER_BUTTON_A && iCurrentElement != SDL_CONTROLLER_BUTTON_B) {
slouken@10705
   262
                /* Skip to the next binding */
slouken@10705
   263
                SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   264
                return;
slouken@10705
   265
            }
slouken@10705
   266
slouken@10705
   267
            if (iIndex == SDL_CONTROLLER_BUTTON_B) {
slouken@10705
   268
                /* Go back to the previous binding */
slouken@10705
   269
                SetCurrentBinding(s_iCurrentBinding - 1);
slouken@10705
   270
                return;
slouken@10705
   271
            }
slouken@10705
   272
slouken@10705
   273
            /* Already have this binding, ignore it */
slouken@10705
   274
            return;
slouken@10705
   275
        }
slouken@10705
   276
    }
slouken@10705
   277
slouken@10705
   278
    /* Should the new binding override the existing one? */
slouken@10705
   279
    pCurrent = &s_arrBindings[iCurrentElement];
slouken@10705
   280
    if (pCurrent->bindType != SDL_CONTROLLER_BINDTYPE_NONE) {
slouken@10705
   281
        SDL_bool bNativeDPad, bCurrentDPad;
slouken@10705
   282
        SDL_bool bNativeAxis, bCurrentAxis;
slouken@10705
   283
        
slouken@10705
   284
        bNativeDPad = (iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_UP ||
slouken@10705
   285
                       iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_DOWN ||
slouken@10705
   286
                       iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_LEFT ||
slouken@10705
   287
                       iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
slouken@10705
   288
        bCurrentDPad = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_HAT);
slouken@10705
   289
        if (bNativeDPad == bCurrentDPad) {
slouken@10705
   290
            /* We already have a binding of the type we want, ignore the new one */
slouken@10705
   291
            return;
slouken@10705
   292
        }
slouken@10705
   293
slouken@10705
   294
        bNativeAxis = (iCurrentElement >= SDL_CONTROLLER_BUTTON_MAX);
slouken@10705
   295
        bCurrentAxis = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_AXIS);
slouken@10745
   296
        if (bNativeAxis == bCurrentAxis &&
slouken@10745
   297
            (pBinding->bindType != SDL_CONTROLLER_BINDTYPE_AXIS ||
slouken@10745
   298
             pBinding->value.axis.axis != pCurrent->value.axis.axis)) {
slouken@10705
   299
            /* We already have a binding of the type we want, ignore the new one */
slouken@10705
   300
            return;
slouken@10705
   301
        }
slouken@10705
   302
    }
slouken@10705
   303
slouken@10705
   304
    *pCurrent = *pBinding;
slouken@10705
   305
slouken@10705
   306
    s_unPendingAdvanceTime = SDL_GetTicks();
slouken@10705
   307
}
slouken@10705
   308
slouken@10724
   309
static SDL_bool
slouken@10724
   310
BMergeAxisBindings(int iIndex)
slouken@10724
   311
{
slouken@10724
   312
    SDL_GameControllerExtendedBind *pBindingA = &s_arrBindings[iIndex];
slouken@10724
   313
    SDL_GameControllerExtendedBind *pBindingB = &s_arrBindings[iIndex+1];
slouken@10724
   314
    if (pBindingA->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
slouken@10724
   315
        pBindingB->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
slouken@10724
   316
        pBindingA->value.axis.axis == pBindingB->value.axis.axis) {
slouken@10724
   317
        if (pBindingA->value.axis.axis_min == pBindingB->value.axis.axis_min) {
slouken@10724
   318
            pBindingA->value.axis.axis_min = pBindingA->value.axis.axis_max;
slouken@10724
   319
            pBindingA->value.axis.axis_max = pBindingB->value.axis.axis_max;
slouken@10724
   320
            pBindingB->bindType = SDL_CONTROLLER_BINDTYPE_NONE;
slouken@10724
   321
            return SDL_TRUE;
slouken@10724
   322
        }
slouken@10724
   323
    }
slouken@10724
   324
    return SDL_FALSE;
slouken@10724
   325
}
slouken@10724
   326
slouken@10705
   327
static void
gabomdq@8043
   328
WatchJoystick(SDL_Joystick * joystick)
gabomdq@8043
   329
{
gabomdq@8043
   330
    SDL_Window *window = NULL;
gabomdq@8043
   331
    SDL_Renderer *screen = NULL;
icculus@8202
   332
    SDL_Texture *background, *button, *axis, *marker;
gabomdq@8043
   333
    const char *name = NULL;
slouken@10705
   334
    SDL_bool done = SDL_FALSE;
gabomdq@8043
   335
    SDL_Event event;
gabomdq@8043
   336
    SDL_Rect dst;
gabomdq@8043
   337
    Uint8 alpha=200, alpha_step = -1;
philipp@8786
   338
    Uint32 alpha_ticks = 0;
slouken@10705
   339
    SDL_JoystickID nJoystickID;
gabomdq@8043
   340
gabomdq@8043
   341
    /* Create a window to display joystick axis position */
gabomdq@8046
   342
    window = SDL_CreateWindow("Game Controller Map", SDL_WINDOWPOS_CENTERED,
gabomdq@8043
   343
                              SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
gabomdq@8043
   344
                              SCREEN_HEIGHT, 0);
gabomdq@8043
   345
    if (window == NULL) {
gabomdq@8043
   346
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
slouken@10705
   347
        return;
gabomdq@8043
   348
    }
gabomdq@8043
   349
gabomdq@8043
   350
    screen = SDL_CreateRenderer(window, -1, 0);
gabomdq@8043
   351
    if (screen == NULL) {
gabomdq@8043
   352
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
gabomdq@8043
   353
        SDL_DestroyWindow(window);
slouken@10705
   354
        return;
gabomdq@8043
   355
    }
gabomdq@8043
   356
    
gabomdq@8043
   357
    background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
gabomdq@8043
   358
    button = LoadTexture(screen, "button.bmp", SDL_TRUE);
gabomdq@8043
   359
    axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
gabomdq@8043
   360
    SDL_RaiseWindow(window);
gabomdq@8043
   361
icculus@8202
   362
    /* scale for platforms that don't give you the window size you asked for. */
icculus@8202
   363
    SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
icculus@8202
   364
gabomdq@8043
   365
    /* Print info about the joystick we are watching */
gabomdq@8043
   366
    name = SDL_JoystickName(joystick);
gabomdq@8043
   367
    SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick),
gabomdq@8043
   368
           name ? name : "Unknown Joystick");
gabomdq@8043
   369
    SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
gabomdq@8043
   370
           SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
gabomdq@8043
   371
           SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
gabomdq@8043
   372
    
gabomdq@8043
   373
    SDL_Log("\n\n\
gabomdq@8043
   374
    ====================================================================================\n\
gabomdq@8043
   375
    Press the buttons on your controller when indicated\n\
gabomdq@8043
   376
    (Your controller may look different than the picture)\n\
gabomdq@8043
   377
    If you want to correct a mistake, press backspace or the back button on your device\n\
gabomdq@8046
   378
    To skip a button, press SPACE or click/touch the screen\n\
gabomdq@8043
   379
    To exit, press ESC\n\
gabomdq@8043
   380
    ====================================================================================\n");
slouken@10705
   381
slouken@10705
   382
    nJoystickID = SDL_JoystickInstanceID(joystick);
gabomdq@8043
   383
slouken@10724
   384
    s_nNumAxes = SDL_JoystickNumAxes(joystick);
slouken@10724
   385
    s_arrAxisState = SDL_calloc(s_nNumAxes, sizeof(*s_arrAxisState));
slouken@10724
   386
gabomdq@8043
   387
    /* Loop, getting joystick events! */
slouken@10705
   388
    while (!done && !s_bBindingComplete) {
slouken@10705
   389
        int iElement = s_arrBindingOrder[s_iCurrentBinding];
slouken@10705
   390
slouken@10705
   391
        switch (s_arrBindingDisplay[iElement].marker) {
gabomdq@8043
   392
            case MARKER_AXIS:
gabomdq@8043
   393
                marker = axis;
gabomdq@8043
   394
                break;
gabomdq@8043
   395
            case MARKER_BUTTON:
gabomdq@8043
   396
                marker = button;
gabomdq@8043
   397
                break;
gabomdq@8043
   398
            default:
gabomdq@8043
   399
                break;
gabomdq@8043
   400
        }
gabomdq@8043
   401
        
slouken@10705
   402
        dst.x = s_arrBindingDisplay[iElement].x;
slouken@10705
   403
        dst.y = s_arrBindingDisplay[iElement].y;
gabomdq@8043
   404
        SDL_QueryTexture(marker, NULL, NULL, &dst.w, &dst.h);
icculus@8202
   405
slouken@10705
   406
        if (SDL_GetTicks() - alpha_ticks > 5) {
slouken@10705
   407
            alpha_ticks = SDL_GetTicks();
slouken@10705
   408
            alpha += alpha_step;
slouken@10705
   409
            if (alpha == 255) {
slouken@10705
   410
                alpha_step = -1;
gabomdq@8043
   411
            }
slouken@10705
   412
            if (alpha < 128) {
slouken@10705
   413
                alpha_step = 1;
gabomdq@8043
   414
            }
gabomdq@8043
   415
        }
gabomdq@8043
   416
slouken@10705
   417
        SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
slouken@10705
   418
        SDL_RenderClear(screen);
slouken@10705
   419
        SDL_RenderCopy(screen, background, NULL, NULL);
slouken@10705
   420
        SDL_SetTextureAlphaMod(marker, alpha);
slouken@10705
   421
        SDL_SetTextureColorMod(marker, 10, 255, 21);
slouken@10705
   422
        SDL_RenderCopyEx(screen, marker, NULL, &dst, s_arrBindingDisplay[iElement].angle, NULL, SDL_FLIP_NONE);
slouken@10705
   423
        SDL_RenderPresent(screen);
slouken@10705
   424
            
slouken@10705
   425
        while (SDL_PollEvent(&event) > 0) {
slouken@10705
   426
            switch (event.type) {
slouken@10705
   427
            case SDL_JOYDEVICEREMOVED:
slouken@10705
   428
                if (event.jaxis.which == nJoystickID) {
slouken@10705
   429
                    done = SDL_TRUE;
slouken@10705
   430
                }
slouken@10705
   431
                break;
slouken@10705
   432
            case SDL_JOYAXISMOTION:
slouken@10705
   433
                if (event.jaxis.which == nJoystickID) {
slouken@10724
   434
                    AxisState *pAxisState = &s_arrAxisState[event.jaxis.axis];
slouken@10724
   435
                    int nValue = event.jaxis.value;
slouken@10724
   436
                    int nCurrentDistance, nFarthestDistance;
slouken@10724
   437
                    if (!pAxisState->m_bMoving) {
slouken@10724
   438
                        pAxisState->m_bMoving = SDL_TRUE;
slouken@10724
   439
                        pAxisState->m_nStartingValue = nValue;
slouken@10724
   440
                        pAxisState->m_nFarthestValue = nValue;
slouken@10724
   441
                    }
slouken@10724
   442
                    nCurrentDistance = SDL_abs(nValue - pAxisState->m_nStartingValue);
slouken@10724
   443
                    nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
slouken@10724
   444
                    if (nCurrentDistance > nFarthestDistance) {
slouken@10724
   445
                        pAxisState->m_nFarthestValue = nValue;
slouken@10724
   446
                    }
slouken@10745
   447
                    if (nFarthestDistance >= 20000 && nCurrentDistance <= 10000) {
slouken@10745
   448
                        /* We've gone out far enough and started to come back, let's bind this axis */
slouken@10724
   449
                        SDL_GameControllerExtendedBind binding;
slouken@10705
   450
                        SDL_zero(binding);
slouken@10705
   451
                        binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
slouken@10724
   452
                        binding.value.axis.axis = event.jaxis.axis;
slouken@10724
   453
                        binding.value.axis.axis_min = StandardizeAxisValue(pAxisState->m_nStartingValue);
slouken@10724
   454
                        binding.value.axis.axis_max = StandardizeAxisValue(pAxisState->m_nFarthestValue);
slouken@10705
   455
                        ConfigureBinding(&binding);
slouken@10705
   456
                    }
slouken@10705
   457
                }
slouken@10705
   458
                break;
slouken@10705
   459
            case SDL_JOYHATMOTION:
slouken@10705
   460
                if (event.jhat.which == nJoystickID) {
slouken@10705
   461
                    if (event.jhat.value != SDL_HAT_CENTERED) {
slouken@10724
   462
                        SDL_GameControllerExtendedBind binding;
slouken@10705
   463
                        SDL_zero(binding);
slouken@10705
   464
                        binding.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
slouken@10705
   465
                        binding.value.hat.hat = event.jhat.hat;
slouken@10705
   466
                        binding.value.hat.hat_mask = event.jhat.value;
slouken@10705
   467
                        ConfigureBinding(&binding);
slouken@10705
   468
                    }
slouken@10705
   469
                }
slouken@10705
   470
                break;
slouken@10705
   471
            case SDL_JOYBALLMOTION:
slouken@10705
   472
                break;
slouken@10705
   473
            case SDL_JOYBUTTONDOWN:
slouken@10705
   474
                if (event.jbutton.which == nJoystickID) {
slouken@10724
   475
                    SDL_GameControllerExtendedBind binding;
slouken@10705
   476
                    SDL_zero(binding);
slouken@10705
   477
                    binding.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
slouken@10705
   478
                    binding.value.button = event.jbutton.button;
slouken@10705
   479
                    ConfigureBinding(&binding);
slouken@10705
   480
                }
slouken@10705
   481
                break;
slouken@10705
   482
            case SDL_FINGERDOWN:
slouken@10705
   483
            case SDL_MOUSEBUTTONDOWN:
slouken@10705
   484
                /* Skip this step */
slouken@10705
   485
                SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   486
                break;
slouken@10705
   487
            case SDL_KEYDOWN:
slouken@10705
   488
                if (event.key.keysym.sym == SDLK_BACKSPACE || event.key.keysym.sym == SDLK_AC_BACK) {
slouken@10705
   489
                    SetCurrentBinding(s_iCurrentBinding - 1);
slouken@10705
   490
                    break;
slouken@10705
   491
                }
slouken@10705
   492
                if (event.key.keysym.sym == SDLK_SPACE) {
slouken@10705
   493
                    SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   494
                    break;
slouken@10705
   495
                }
slouken@10705
   496
slouken@10705
   497
                if ((event.key.keysym.sym != SDLK_ESCAPE)) {
slouken@10705
   498
                    break;
slouken@10705
   499
                }
slouken@10705
   500
                /* Fall through to signal quit */
slouken@10705
   501
            case SDL_QUIT:
slouken@10705
   502
                done = SDL_TRUE;
slouken@10705
   503
                break;
slouken@10705
   504
            default:
slouken@10705
   505
                break;
slouken@10705
   506
            }
slouken@10705
   507
        }
slouken@10705
   508
slouken@10705
   509
        SDL_Delay(15);
slouken@10705
   510
slouken@10705
   511
        /* Wait 100 ms for joystick events to stop coming in,
slouken@10705
   512
           in case a controller sends multiple events for a single control (e.g. axis and button for trigger)
slouken@10705
   513
        */
slouken@10705
   514
        if (s_unPendingAdvanceTime && SDL_GetTicks() - s_unPendingAdvanceTime >= 100) {
slouken@10705
   515
            SetCurrentBinding(s_iCurrentBinding + 1);
slouken@10705
   516
        }
gabomdq@8043
   517
    }
gabomdq@8043
   518
slouken@10705
   519
    if (s_bBindingComplete) {
slouken@10705
   520
        char mapping[1024];
slouken@10705
   521
        char trimmed_name[128];
slouken@10705
   522
        char *spot;
slouken@10705
   523
        int iIndex;
slouken@10705
   524
        char pszElement[12];
slouken@10705
   525
slouken@10705
   526
        SDL_strlcpy(trimmed_name, name, SDL_arraysize(trimmed_name));
slouken@10705
   527
        while (SDL_isspace(trimmed_name[0])) {
slouken@10705
   528
            SDL_memmove(&trimmed_name[0], &trimmed_name[1], SDL_strlen(trimmed_name));
slouken@10705
   529
        }
slouken@10705
   530
        while (trimmed_name[0] && SDL_isspace(trimmed_name[SDL_strlen(trimmed_name) - 1])) {
slouken@10705
   531
            trimmed_name[SDL_strlen(trimmed_name) - 1] = '\0';
slouken@10705
   532
        }
slouken@10705
   533
        while ((spot = SDL_strchr(trimmed_name, ',')) != NULL) {
slouken@10705
   534
            SDL_memmove(spot, spot + 1, SDL_strlen(spot));
slouken@10705
   535
        }
slouken@10705
   536
slouken@10705
   537
        /* Initialize mapping with GUID and name */
slouken@10705
   538
        SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), mapping, SDL_arraysize(mapping));
slouken@10705
   539
        SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   540
        SDL_strlcat(mapping, trimmed_name, SDL_arraysize(mapping));
slouken@10705
   541
        SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   542
        SDL_strlcat(mapping, "platform:", SDL_arraysize(mapping));
slouken@10705
   543
        SDL_strlcat(mapping, SDL_GetPlatform(), SDL_arraysize(mapping));
slouken@10705
   544
        SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   545
slouken@10705
   546
        for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
slouken@10724
   547
            SDL_GameControllerExtendedBind *pBinding = &s_arrBindings[iIndex];
slouken@10705
   548
            if (pBinding->bindType == SDL_CONTROLLER_BINDTYPE_NONE) {
slouken@10705
   549
                continue;
slouken@10705
   550
            }
slouken@10705
   551
slouken@10705
   552
            if (iIndex < SDL_CONTROLLER_BUTTON_MAX) {
slouken@10705
   553
                SDL_GameControllerButton eButton = (SDL_GameControllerButton)iIndex;
slouken@10705
   554
                SDL_strlcat(mapping, SDL_GameControllerGetStringForButton(eButton), SDL_arraysize(mapping));
slouken@10705
   555
            } else {
slouken@10724
   556
                const char *pszAxisName;
slouken@10724
   557
                switch (iIndex - SDL_CONTROLLER_BUTTON_MAX) {
slouken@10724
   558
                case SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE:
slouken@10724
   559
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   560
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   561
                    }
slouken@10724
   562
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
slouken@10724
   563
                    break;
slouken@10724
   564
                case SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE:
slouken@10724
   565
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   566
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
slouken@10724
   567
                    break;
slouken@10724
   568
                case SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE:
slouken@10724
   569
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   570
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   571
                    }
slouken@10724
   572
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
slouken@10724
   573
                    break;
slouken@10724
   574
                case SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE:
slouken@10724
   575
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   576
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
slouken@10724
   577
                    break;
slouken@10724
   578
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE:
slouken@10724
   579
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   580
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   581
                    }
slouken@10724
   582
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
slouken@10724
   583
                    break;
slouken@10724
   584
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE:
slouken@10724
   585
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   586
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
slouken@10724
   587
                    break;
slouken@10724
   588
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE:
slouken@10724
   589
                    if (!BMergeAxisBindings(iIndex)) {
slouken@10724
   590
                        SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
slouken@10724
   591
                    }
slouken@10724
   592
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
slouken@10724
   593
                    break;
slouken@10724
   594
                case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE:
slouken@10724
   595
                    SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
slouken@10724
   596
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
slouken@10724
   597
                    break;
slouken@10724
   598
                case SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT:
slouken@10724
   599
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
slouken@10724
   600
                    break;
slouken@10724
   601
                case SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT:
slouken@10724
   602
                    pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
slouken@10724
   603
                    break;
slouken@10724
   604
                }
slouken@10724
   605
                SDL_strlcat(mapping, pszAxisName, SDL_arraysize(mapping));
slouken@10705
   606
            }
slouken@10705
   607
            SDL_strlcat(mapping, ":", SDL_arraysize(mapping));
slouken@10705
   608
slouken@10705
   609
            pszElement[0] = '\0';
slouken@10705
   610
            switch (pBinding->bindType) {
slouken@10705
   611
            case SDL_CONTROLLER_BINDTYPE_BUTTON:
slouken@10705
   612
                SDL_snprintf(pszElement, sizeof(pszElement), "b%d", pBinding->value.button);
slouken@10705
   613
                break;
slouken@10705
   614
            case SDL_CONTROLLER_BINDTYPE_AXIS:
slouken@10724
   615
                if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MIN) {
slouken@10724
   616
                    /* The negative half axis */
slouken@10724
   617
                    SDL_snprintf(pszElement, sizeof(pszElement), "-a%d", pBinding->value.axis.axis);
slouken@10724
   618
                } else if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MAX) {
slouken@10724
   619
                    /* The positive half axis */
slouken@10724
   620
                    SDL_snprintf(pszElement, sizeof(pszElement), "+a%d", pBinding->value.axis.axis);
slouken@10724
   621
                } else {
slouken@10724
   622
                    SDL_snprintf(pszElement, sizeof(pszElement), "a%d", pBinding->value.axis.axis);
slouken@10724
   623
                    if (pBinding->value.axis.axis_min > pBinding->value.axis.axis_max) {
slouken@10724
   624
                        /* Invert the axis */
slouken@10724
   625
                        SDL_strlcat(pszElement, "~", SDL_arraysize(pszElement));
slouken@10724
   626
                    }
slouken@10724
   627
                }
slouken@10705
   628
                break;
slouken@10705
   629
            case SDL_CONTROLLER_BINDTYPE_HAT:
slouken@10705
   630
                SDL_snprintf(pszElement, sizeof(pszElement), "h%d.%d", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
slouken@10705
   631
                break;
slouken@10705
   632
            default:
slouken@10705
   633
                SDL_assert(!"Unknown bind type");
slouken@10705
   634
                break;
slouken@10705
   635
            }
slouken@10705
   636
            SDL_strlcat(mapping, pszElement, SDL_arraysize(mapping));
slouken@10705
   637
            SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
slouken@10705
   638
        }
slouken@10705
   639
gabomdq@8043
   640
        SDL_Log("Mapping:\n\n%s\n\n", mapping);
gabomdq@8043
   641
        /* Print to stdout as well so the user can cat the output somewhere */
gabomdq@8043
   642
        printf("%s\n", mapping);
gabomdq@8043
   643
    }
slouken@10724
   644
slouken@10724
   645
    SDL_free(s_arrAxisState);
slouken@10724
   646
    s_arrAxisState = NULL;
gabomdq@8043
   647
    
gabomdq@8043
   648
    SDL_DestroyRenderer(screen);
gabomdq@8043
   649
    SDL_DestroyWindow(window);
gabomdq@8043
   650
}
gabomdq@8043
   651
gabomdq@8043
   652
int
gabomdq@8043
   653
main(int argc, char *argv[])
gabomdq@8043
   654
{
gabomdq@8043
   655
    const char *name;
gabomdq@8043
   656
    int i;
gabomdq@8043
   657
    SDL_Joystick *joystick;
gabomdq@8043
   658
gabomdq@8043
   659
    /* Enable standard application logging */
philipp@9922
   660
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
gabomdq@8043
   661
gabomdq@8043
   662
    /* Initialize SDL (Note: video is required to start event loop) */
gabomdq@8043
   663
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
gabomdq@8043
   664
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
gabomdq@8043
   665
        exit(1);
gabomdq@8043
   666
    }
gabomdq@8043
   667
gabomdq@8043
   668
    /* Print information about the joysticks */
gabomdq@8043
   669
    SDL_Log("There are %d joysticks attached\n", SDL_NumJoysticks());
gabomdq@8043
   670
    for (i = 0; i < SDL_NumJoysticks(); ++i) {
gabomdq@8043
   671
        name = SDL_JoystickNameForIndex(i);
gabomdq@8043
   672
        SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
gabomdq@8043
   673
        joystick = SDL_JoystickOpen(i);
gabomdq@8043
   674
        if (joystick == NULL) {
gabomdq@8043
   675
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
gabomdq@8043
   676
                    SDL_GetError());
gabomdq@8043
   677
        } else {
gabomdq@8043
   678
            char guid[64];
gabomdq@8043
   679
            SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
gabomdq@8043
   680
                                      guid, sizeof (guid));
gabomdq@8043
   681
            SDL_Log("       axes: %d\n", SDL_JoystickNumAxes(joystick));
gabomdq@8043
   682
            SDL_Log("      balls: %d\n", SDL_JoystickNumBalls(joystick));
gabomdq@8043
   683
            SDL_Log("       hats: %d\n", SDL_JoystickNumHats(joystick));
gabomdq@8043
   684
            SDL_Log("    buttons: %d\n", SDL_JoystickNumButtons(joystick));
gabomdq@8043
   685
            SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick));
gabomdq@8043
   686
            SDL_Log("       guid: %s\n", guid);
slouken@10597
   687
            SDL_Log("    VID/PID: 0x%.4x/0x%.4x\n", SDL_JoystickGetVendor(joystick), SDL_JoystickGetProduct(joystick));
gabomdq@8043
   688
            SDL_JoystickClose(joystick);
gabomdq@8043
   689
        }
gabomdq@8043
   690
    }
gabomdq@8043
   691
gabomdq@8762
   692
#ifdef __ANDROID__
gabomdq@8043
   693
    if (SDL_NumJoysticks() > 0) {
gabomdq@8043
   694
#else
gabomdq@8043
   695
    if (argv[1]) {
gabomdq@8043
   696
#endif
philipp@8078
   697
        int device;
gabomdq@8762
   698
#ifdef __ANDROID__
philipp@8078
   699
        device = 0;
gabomdq@8043
   700
#else
philipp@8078
   701
        device = atoi(argv[1]);
gabomdq@8043
   702
#endif
philipp@8078
   703
        joystick = SDL_JoystickOpen(device);
slouken@10705
   704
        if (joystick == NULL) {
slouken@10705
   705
            SDL_Log("Couldn't open joystick %d: %s\n", device, SDL_GetError());
slouken@10705
   706
        } else {
slouken@10705
   707
            WatchJoystick(joystick);
slouken@10705
   708
            SDL_JoystickClose(joystick);
gabomdq@8043
   709
        }
gabomdq@8043
   710
    }
gabomdq@8043
   711
    else {
gabomdq@8043
   712
        SDL_Log("\n\nUsage: ./controllermap number\nFor example: ./controllermap 0\nOr: ./controllermap 0 >> gamecontrollerdb.txt");
gabomdq@8043
   713
    }
gabomdq@8043
   714
    SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
gabomdq@8043
   715
gabomdq@8043
   716
    return 0;
gabomdq@8043
   717
}
gabomdq@8043
   718
gabomdq@8043
   719
#else
gabomdq@8043
   720
gabomdq@8043
   721
int
gabomdq@8043
   722
main(int argc, char *argv[])
gabomdq@8043
   723
{
gabomdq@8043
   724
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
gabomdq@8043
   725
    exit(1);
gabomdq@8043
   726
}
gabomdq@8043
   727
gabomdq@8043
   728
#endif
slouken@10597
   729
slouken@10597
   730
/* vi: set ts=4 sw=4 expandtab: */