test/testgamecontroller.c
author Alex Baines <alex@abaines.me.uk>
Tue, 19 Aug 2014 23:31:50 +0100
changeset 9097 56d712662a82
parent 8687 1d2ca48523a7
child 9102 a22458d5eed9
permissions -rw-r--r--
Add a SDL_IM_INTERNAL_EDITING event to make IMs like iBus render editing text in its own UI instead of sending TEXTEDITING events.
This is useful for applications that handle TEXTINPUT events but not TEXTEDITING events.
slouken@6690
     1
/*
slouken@8149
     2
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@6690
     3
slouken@6690
     4
  This software is provided 'as-is', without any express or implied
slouken@6690
     5
  warranty.  In no event will the authors be held liable for any damages
slouken@6690
     6
  arising from the use of this software.
slouken@6690
     7
slouken@6690
     8
  Permission is granted to anyone to use this software for any purpose,
slouken@6690
     9
  including commercial applications, and to alter it and redistribute it
slouken@6690
    10
  freely.
slouken@6690
    11
*/
slouken@6690
    12
slouken@6690
    13
/* Simple program to test the SDL game controller routines */
slouken@6690
    14
slouken@6690
    15
#include <stdio.h>
slouken@6690
    16
#include <stdlib.h>
slouken@6690
    17
#include <string.h>
slouken@6690
    18
slouken@6690
    19
#include "SDL.h"
slouken@6690
    20
aschiffler@6771
    21
#ifndef SDL_JOYSTICK_DISABLED
aschiffler@6771
    22
slouken@6690
    23
#ifdef __IPHONEOS__
jorgen@7056
    24
#define SCREEN_WIDTH    320
jorgen@7056
    25
#define SCREEN_HEIGHT    480
slouken@6690
    26
#else
icculus@8199
    27
#define SCREEN_WIDTH    512
icculus@8199
    28
#define SCREEN_HEIGHT   317
slouken@6690
    29
#endif
slouken@6690
    30
icculus@6914
    31
static const char *
icculus@6917
    32
ControllerAxisName(const SDL_GameControllerAxis axis)
icculus@6914
    33
{
icculus@6914
    34
    switch (axis)
icculus@6914
    35
    {
icculus@6914
    36
        #define AXIS_CASE(ax) case SDL_CONTROLLER_AXIS_##ax: return #ax
icculus@6914
    37
        AXIS_CASE(INVALID);
icculus@6914
    38
        AXIS_CASE(LEFTX);
icculus@6914
    39
        AXIS_CASE(LEFTY);
icculus@6914
    40
        AXIS_CASE(RIGHTX);
icculus@6914
    41
        AXIS_CASE(RIGHTY);
icculus@6914
    42
        AXIS_CASE(TRIGGERLEFT);
icculus@6914
    43
        AXIS_CASE(TRIGGERRIGHT);
icculus@6914
    44
        #undef AXIS_CASE
icculus@6914
    45
        default: return "???";
icculus@6914
    46
    }
icculus@6914
    47
}
icculus@6914
    48
icculus@6914
    49
static const char *
icculus@6917
    50
ControllerButtonName(const SDL_GameControllerButton button)
icculus@6914
    51
{
icculus@6914
    52
    switch (button)
icculus@6914
    53
    {
icculus@6914
    54
        #define BUTTON_CASE(btn) case SDL_CONTROLLER_BUTTON_##btn: return #btn
icculus@6914
    55
        BUTTON_CASE(INVALID);
icculus@6914
    56
        BUTTON_CASE(A);
icculus@6914
    57
        BUTTON_CASE(B);
icculus@6914
    58
        BUTTON_CASE(X);
icculus@6914
    59
        BUTTON_CASE(Y);
icculus@6914
    60
        BUTTON_CASE(BACK);
icculus@6914
    61
        BUTTON_CASE(GUIDE);
icculus@6914
    62
        BUTTON_CASE(START);
icculus@6914
    63
        BUTTON_CASE(LEFTSTICK);
icculus@6914
    64
        BUTTON_CASE(RIGHTSTICK);
icculus@6914
    65
        BUTTON_CASE(LEFTSHOULDER);
icculus@6914
    66
        BUTTON_CASE(RIGHTSHOULDER);
icculus@6914
    67
        BUTTON_CASE(DPAD_UP);
icculus@6914
    68
        BUTTON_CASE(DPAD_DOWN);
icculus@6914
    69
        BUTTON_CASE(DPAD_LEFT);
icculus@6914
    70
        BUTTON_CASE(DPAD_RIGHT);
icculus@6914
    71
        #undef BUTTON_CASE
icculus@6914
    72
        default: return "???";
icculus@6914
    73
    }
icculus@6914
    74
}
icculus@6914
    75
icculus@8199
    76
static SDL_Texture *
icculus@8199
    77
LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
icculus@8199
    78
{
icculus@8199
    79
    SDL_Surface *temp = NULL;
icculus@8199
    80
    SDL_Texture *texture = NULL;
icculus@8199
    81
icculus@8199
    82
    temp = SDL_LoadBMP(file);
icculus@8199
    83
    if (temp == NULL) {
icculus@8199
    84
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
icculus@8199
    85
    } else {
icculus@8199
    86
        /* Set transparent pixel as the pixel at (0,0) */
icculus@8199
    87
        if (transparent) {
slouken@8687
    88
            if (temp->format->BytesPerPixel == 1) {
slouken@8687
    89
                SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *)temp->pixels);
slouken@8687
    90
            } else {
slouken@8687
    91
                SDL_assert(!temp->format->palette);
slouken@8687
    92
                SDL_assert(temp->format->BitsPerPixel == 24);
slouken@8687
    93
                SDL_SetColorKey(temp, SDL_TRUE, (*(Uint32 *)temp->pixels) & 0x00FFFFFF);
slouken@8687
    94
            }
icculus@8199
    95
        }
icculus@8199
    96
icculus@8199
    97
        texture = SDL_CreateTextureFromSurface(renderer, temp);
icculus@8199
    98
        if (!texture) {
icculus@8199
    99
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
icculus@8199
   100
        }
icculus@8199
   101
    }
icculus@8199
   102
    if (temp) {
icculus@8199
   103
        SDL_FreeSurface(temp);
icculus@8199
   104
    }
icculus@8199
   105
    return texture;
icculus@8199
   106
}
icculus@8199
   107
slouken@8068
   108
SDL_bool
slouken@6690
   109
WatchGameController(SDL_GameController * gamecontroller)
slouken@6690
   110
{
icculus@8199
   111
    /* This is indexed by SDL_GameControllerButton. */
icculus@8199
   112
    static const struct { int x; int y; } button_positions[] = {
icculus@8199
   113
        {387, 167},  /* A */
icculus@8199
   114
        {431, 132},  /* B */
icculus@8199
   115
        {342, 132},  /* X */
icculus@8199
   116
        {389, 101},  /* Y */
icculus@8199
   117
        {174, 132},  /* BACK */
icculus@8199
   118
        {233, 132},  /* GUIDE */
icculus@8199
   119
        {289, 132},  /* START */
icculus@8199
   120
        {75,  154},  /* LEFTSTICK */
icculus@8199
   121
        {305, 230},  /* RIGHTSTICK */
icculus@8199
   122
        {77,  40},   /* LEFTSHOULDER */
icculus@8199
   123
        {396, 36},   /* RIGHTSHOULDER */
icculus@8199
   124
        {154, 188},  /* DPAD_UP */
icculus@8199
   125
        {154, 249},  /* DPAD_DOWN */
icculus@8199
   126
        {116, 217},  /* DPAD_LEFT */
icculus@8199
   127
        {186, 217},  /* DPAD_RIGHT */
icculus@8199
   128
    };
icculus@8199
   129
icculus@8199
   130
    /* This is indexed by SDL_GameControllerAxis. */
icculus@8199
   131
    static const struct { int x; int y; double angle; } axis_positions[] = {
icculus@8199
   132
        {75,  154, 0.0},  /* LEFTX */
icculus@8199
   133
        {75,  154, 90.0},  /* LEFTY */
icculus@8199
   134
        {305, 230, 0.0},  /* RIGHTX */
icculus@8199
   135
        {305, 230, 90.0},  /* RIGHTY */
icculus@8199
   136
        {91, 0, 90.0},     /* TRIGGERLEFT */
icculus@8199
   137
        {375, 0, 90.0},    /* TRIGGERRIGHT */
icculus@8199
   138
    };
icculus@8199
   139
icculus@6916
   140
    const char *name = SDL_GameControllerName(gamecontroller);
icculus@6914
   141
    const char *basetitle = "Game Controller Test: ";
icculus@6916
   142
    const size_t titlelen = SDL_strlen(basetitle) + SDL_strlen(name) + 1;
aschiffler@7639
   143
    char *title = (char *)SDL_malloc(titlelen);
icculus@8199
   144
    SDL_Texture *background, *button, *axis;
slouken@6690
   145
    SDL_Window *window = NULL;
slouken@6690
   146
    SDL_Renderer *screen = NULL;
slouken@8068
   147
    SDL_bool retval = SDL_FALSE;
slouken@8068
   148
    SDL_bool done = SDL_FALSE;
slouken@6690
   149
    SDL_Event event;
slouken@6690
   150
    int i;
slouken@6690
   151
icculus@6914
   152
    if (title) {
icculus@6916
   153
        SDL_snprintf(title, titlelen, "%s%s", basetitle, name);
icculus@6914
   154
    }
icculus@6914
   155
icculus@8199
   156
    /* Create a window to display controller state */
icculus@6914
   157
    window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED,
slouken@6690
   158
                              SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
philipp@7478
   159
                              SCREEN_HEIGHT, 0);
slouken@6690
   160
    if (window == NULL) {
aschiffler@7639
   161
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
slouken@8068
   162
        return SDL_FALSE;
slouken@6690
   163
    }
slouken@6690
   164
slouken@6690
   165
    screen = SDL_CreateRenderer(window, -1, 0);
slouken@6690
   166
    if (screen == NULL) {
aschiffler@7639
   167
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
slouken@6690
   168
        SDL_DestroyWindow(window);
slouken@8068
   169
        return SDL_FALSE;
slouken@6690
   170
    }
slouken@6690
   171
slouken@6690
   172
    SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
slouken@6690
   173
    SDL_RenderClear(screen);
slouken@6690
   174
    SDL_RenderPresent(screen);
jorgen@7056
   175
    SDL_RaiseWindow(window);
slouken@6690
   176
icculus@8202
   177
    /* scale for platforms that don't give you the window size you asked for. */
icculus@8202
   178
    SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
icculus@8202
   179
icculus@8199
   180
    background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
icculus@8199
   181
    button = LoadTexture(screen, "button.bmp", SDL_TRUE);
icculus@8199
   182
    axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
icculus@8199
   183
icculus@8199
   184
    if (!background || !button || !axis) {
icculus@8199
   185
        SDL_DestroyRenderer(screen);
icculus@8199
   186
        SDL_DestroyWindow(window);
icculus@8199
   187
        return SDL_FALSE;
icculus@8199
   188
    }
icculus@8199
   189
    SDL_SetTextureColorMod(button, 10, 255, 21);
icculus@8199
   190
    SDL_SetTextureColorMod(axis, 10, 255, 21);
icculus@8199
   191
icculus@8199
   192
    /* !!! FIXME: */
icculus@8199
   193
    /*SDL_RenderSetLogicalSize(screen, background->w, background->h);*/
icculus@8199
   194
slouken@6690
   195
    /* Print info about the controller we are watching */
aschiffler@7639
   196
    SDL_Log("Watching controller %s\n",  name ? name : "Unknown Controller");
slouken@7191
   197
slouken@6690
   198
    /* Loop, getting controller events! */
slouken@6690
   199
    while (!done) {
slouken@6690
   200
        /* blank screen, set up for drawing this frame. */
icculus@8202
   201
        SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
slouken@6690
   202
        SDL_RenderClear(screen);
icculus@8199
   203
        SDL_RenderCopy(screen, background, NULL, NULL);
slouken@6690
   204
slouken@6690
   205
        while (SDL_PollEvent(&event)) {
slouken@6690
   206
            switch (event.type) {
slouken@6690
   207
            case SDL_KEYDOWN:
slouken@6690
   208
                if (event.key.keysym.sym != SDLK_ESCAPE) {
slouken@6690
   209
                    break;
slouken@6690
   210
                }
slouken@6690
   211
                /* Fall through to signal quit */
slouken@6690
   212
            case SDL_QUIT:
slouken@8068
   213
                done = SDL_TRUE;
slouken@6690
   214
                break;
slouken@6690
   215
            default:
slouken@6690
   216
                break;
slouken@6690
   217
            }
slouken@6690
   218
        }
icculus@8199
   219
slouken@6690
   220
        /* Update visual controller state */
icculus@8199
   221
        for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) {
aschiffler@7639
   222
            if (SDL_GameControllerGetButton(gamecontroller, (SDL_GameControllerButton)i) == SDL_PRESSED) {
icculus@8199
   223
                const SDL_Rect dst = { button_positions[i].x, button_positions[i].y, 50, 50 };
icculus@8199
   224
                SDL_RenderCopyEx(screen, button, NULL, &dst, 0, NULL, 0);
slouken@6690
   225
            }
slouken@6690
   226
        }
slouken@6690
   227
icculus@8199
   228
        for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i) {
icculus@8199
   229
            const Sint16 deadzone = 8000;  /* !!! FIXME: real deadzone */
icculus@8199
   230
            const Sint16 value = SDL_GameControllerGetAxis(gamecontroller, (SDL_GameControllerAxis)(i));
icculus@8199
   231
            if (value < -deadzone) {
icculus@8199
   232
                const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 };
icculus@8199
   233
                const double angle = axis_positions[i].angle;
icculus@8199
   234
                SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0);
icculus@8199
   235
            } else if (value > deadzone) {
icculus@8199
   236
                const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 };
icculus@8199
   237
                const double angle = axis_positions[i].angle + 180.0;
icculus@8199
   238
                SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0);
slouken@6690
   239
            }
slouken@6690
   240
        }
slouken@6690
   241
slouken@6690
   242
        SDL_RenderPresent(screen);
slouken@7191
   243
slouken@8068
   244
        if (!SDL_GameControllerGetAttached(gamecontroller)) {
slouken@8068
   245
            done = SDL_TRUE;
slouken@8068
   246
            retval = SDL_TRUE;  /* keep going, wait for reattach. */
slouken@8068
   247
        }
slouken@6690
   248
    }
slouken@6690
   249
slouken@6690
   250
    SDL_DestroyRenderer(screen);
slouken@6690
   251
    SDL_DestroyWindow(window);
slouken@8068
   252
    return retval;
slouken@6690
   253
}
slouken@6690
   254
slouken@6690
   255
int
slouken@6690
   256
main(int argc, char *argv[])
slouken@6690
   257
{
slouken@6690
   258
    int i;
jorgen@7056
   259
    int nController = 0;
jorgen@7056
   260
    int retcode = 0;
jorgen@7056
   261
    char guid[64];
slouken@6690
   262
    SDL_GameController *gamecontroller;
slouken@6690
   263
aschiffler@7639
   264
    /* Enable standard application logging */
aschiffler@7639
   265
	SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
aschiffler@7639
   266
slouken@6690
   267
    /* Initialize SDL (Note: video is required to start event loop) */
slouken@6690
   268
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER ) < 0) {
aschiffler@7639
   269
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
jorgen@7056
   270
        return 1;
slouken@6690
   271
    }
gabomdq@8043
   272
    
gabomdq@8043
   273
    SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
slouken@6690
   274
slouken@6690
   275
    /* Print information about the controller */
slouken@6690
   276
    for (i = 0; i < SDL_NumJoysticks(); ++i) {
jorgen@7056
   277
        const char *name;
icculus@7705
   278
        const char *description;
jorgen@7056
   279
jorgen@7056
   280
        SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i),
jorgen@7056
   281
                                  guid, sizeof (guid));
jorgen@7056
   282
jorgen@7056
   283
        if ( SDL_IsGameController(i) )
jorgen@7056
   284
        {
jorgen@7056
   285
            nController++;
jorgen@7056
   286
            name = SDL_GameControllerNameForIndex(i);
icculus@7705
   287
            description = "Controller";
jorgen@7056
   288
        } else {
jorgen@7056
   289
            name = SDL_JoystickNameForIndex(i);
icculus@7705
   290
            description = "Joystick";
jorgen@7056
   291
        }
aschiffler@7639
   292
        SDL_Log("%s %d: %s (guid %s)\n", description, i, name ? name : "Unknown", guid);
slouken@6690
   293
    }
aschiffler@7639
   294
    SDL_Log("There are %d game controller(s) attached (%d joystick(s))\n", nController, SDL_NumJoysticks());
slouken@6690
   295
slouken@6690
   296
    if (argv[1]) {
slouken@8068
   297
        SDL_bool reportederror = SDL_FALSE;
slouken@8068
   298
        SDL_bool keepGoing = SDL_TRUE;
slouken@8068
   299
        SDL_Event event;
jorgen@7056
   300
        int device = atoi(argv[1]);
jorgen@7056
   301
        if (device >= SDL_NumJoysticks()) {
aschiffler@7639
   302
			SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%i is an invalid joystick index.\n", device);
jorgen@7056
   303
            retcode = 1;
jorgen@7056
   304
        } else {
jorgen@7056
   305
            SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(device),
jorgen@7056
   306
                                      guid, sizeof (guid));
aschiffler@7639
   307
            SDL_Log("Attempting to open device %i, guid %s\n", device, guid);
jorgen@7056
   308
            gamecontroller = SDL_GameControllerOpen(device);
slouken@8068
   309
            while (keepGoing) {
slouken@8068
   310
                if (gamecontroller == NULL) {
slouken@8068
   311
                    if (!reportederror) {
slouken@8068
   312
                        if (gamecontroller == NULL) {
slouken@8068
   313
                            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open gamecontroller %d: %s\n", device, SDL_GetError());
slouken@8068
   314
                            retcode = 1;
slouken@8068
   315
                        }
slouken@8068
   316
                        keepGoing = SDL_FALSE;
slouken@8068
   317
                        reportederror = SDL_TRUE;
slouken@8068
   318
                    }
slouken@8068
   319
                } else {
slouken@8068
   320
                    reportederror = SDL_FALSE;
slouken@8068
   321
                    keepGoing = WatchGameController(gamecontroller);
slouken@8068
   322
                    SDL_GameControllerClose(gamecontroller);
slouken@8068
   323
                }
slouken@8068
   324
slouken@8068
   325
                gamecontroller = NULL;
slouken@8068
   326
                if (keepGoing) {
slouken@8068
   327
                    SDL_Log("Waiting for attach\n");
slouken@8068
   328
                }
slouken@8068
   329
                while (keepGoing) {
slouken@8068
   330
                    SDL_WaitEvent(&event);
slouken@8068
   331
                    if ((event.type == SDL_QUIT) || (event.type == SDL_FINGERDOWN)
slouken@8068
   332
                        || (event.type == SDL_MOUSEBUTTONDOWN)) {
slouken@8068
   333
                        keepGoing = SDL_FALSE;
slouken@8068
   334
                    } else if (event.type == SDL_CONTROLLERDEVICEADDED) {
slouken@8068
   335
                        gamecontroller = SDL_GameControllerOpen(event.cdevice.which);
slouken@8068
   336
                        break;
slouken@8068
   337
                    }
slouken@8068
   338
                }
jorgen@7056
   339
            }
jorgen@7056
   340
        }
jorgen@7056
   341
    }
slouken@6690
   342
jorgen@7056
   343
    SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
jorgen@7056
   344
jorgen@7056
   345
    return retcode;
slouken@6690
   346
}
aschiffler@6771
   347
aschiffler@6771
   348
#else
aschiffler@6771
   349
aschiffler@6771
   350
int
aschiffler@6771
   351
main(int argc, char *argv[])
aschiffler@6771
   352
{
aschiffler@7639
   353
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
aschiffler@6771
   354
    exit(1);
aschiffler@6771
   355
}
aschiffler@6771
   356
aschiffler@6771
   357
#endif