test/testgamecontroller.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Thu, 12 Feb 2015 21:40:53 +0100
changeset 9340 af5be9462bb4
parent 9290 fe975b2313fa
child 9607 7746ab058d12
permissions -rw-r--r--
Fixed test programs for joystick not exiting on events after first disconnect.

Exit was broken since the main loop extraction needed for Emscripten support
because the former local but now global variables were not reset correctly.
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
icculus@9278
    21
#ifdef __EMSCRIPTEN__
icculus@9278
    22
#include <emscripten/emscripten.h>
icculus@9278
    23
#endif
icculus@9278
    24
aschiffler@6771
    25
#ifndef SDL_JOYSTICK_DISABLED
aschiffler@6771
    26
slouken@6690
    27
#ifdef __IPHONEOS__
jorgen@7056
    28
#define SCREEN_WIDTH    320
jorgen@7056
    29
#define SCREEN_HEIGHT    480
slouken@6690
    30
#else
icculus@8199
    31
#define SCREEN_WIDTH    512
icculus@8199
    32
#define SCREEN_HEIGHT   317
slouken@6690
    33
#endif
slouken@6690
    34
icculus@9278
    35
/* This is indexed by SDL_GameControllerButton. */
icculus@9278
    36
static const struct { int x; int y; } button_positions[] = {
icculus@9278
    37
    {387, 167},  /* A */
icculus@9278
    38
    {431, 132},  /* B */
icculus@9278
    39
    {342, 132},  /* X */
icculus@9278
    40
    {389, 101},  /* Y */
icculus@9278
    41
    {174, 132},  /* BACK */
icculus@9278
    42
    {233, 132},  /* GUIDE */
icculus@9278
    43
    {289, 132},  /* START */
icculus@9278
    44
    {75,  154},  /* LEFTSTICK */
icculus@9278
    45
    {305, 230},  /* RIGHTSTICK */
icculus@9278
    46
    {77,  40},   /* LEFTSHOULDER */
icculus@9278
    47
    {396, 36},   /* RIGHTSHOULDER */
icculus@9278
    48
    {154, 188},  /* DPAD_UP */
icculus@9278
    49
    {154, 249},  /* DPAD_DOWN */
icculus@9278
    50
    {116, 217},  /* DPAD_LEFT */
icculus@9278
    51
    {186, 217},  /* DPAD_RIGHT */
icculus@9278
    52
};
icculus@9278
    53
icculus@9278
    54
/* This is indexed by SDL_GameControllerAxis. */
icculus@9278
    55
static const struct { int x; int y; double angle; } axis_positions[] = {
icculus@9278
    56
    {75,  154, 0.0},  /* LEFTX */
icculus@9278
    57
    {75,  154, 90.0},  /* LEFTY */
icculus@9278
    58
    {305, 230, 0.0},  /* RIGHTX */
icculus@9278
    59
    {305, 230, 90.0},  /* RIGHTY */
icculus@9278
    60
    {91, 0, 90.0},     /* TRIGGERLEFT */
icculus@9278
    61
    {375, 0, 90.0},    /* TRIGGERRIGHT */
icculus@9278
    62
};
icculus@9278
    63
icculus@9278
    64
SDL_Renderer *screen = NULL;
icculus@9278
    65
SDL_bool retval = SDL_FALSE;
icculus@9278
    66
SDL_bool done = SDL_FALSE;
icculus@9278
    67
SDL_Texture *background, *button, *axis;
icculus@9278
    68
icculus@8199
    69
static SDL_Texture *
icculus@8199
    70
LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
icculus@8199
    71
{
icculus@8199
    72
    SDL_Surface *temp = NULL;
icculus@8199
    73
    SDL_Texture *texture = NULL;
icculus@8199
    74
icculus@8199
    75
    temp = SDL_LoadBMP(file);
icculus@8199
    76
    if (temp == NULL) {
icculus@8199
    77
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
icculus@8199
    78
    } else {
icculus@8199
    79
        /* Set transparent pixel as the pixel at (0,0) */
icculus@8199
    80
        if (transparent) {
slouken@8687
    81
            if (temp->format->BytesPerPixel == 1) {
slouken@8687
    82
                SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *)temp->pixels);
slouken@8687
    83
            } else {
slouken@8687
    84
                SDL_assert(!temp->format->palette);
slouken@8687
    85
                SDL_assert(temp->format->BitsPerPixel == 24);
slouken@8687
    86
                SDL_SetColorKey(temp, SDL_TRUE, (*(Uint32 *)temp->pixels) & 0x00FFFFFF);
slouken@8687
    87
            }
icculus@8199
    88
        }
icculus@8199
    89
icculus@8199
    90
        texture = SDL_CreateTextureFromSurface(renderer, temp);
icculus@8199
    91
        if (!texture) {
icculus@8199
    92
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
icculus@8199
    93
        }
icculus@8199
    94
    }
icculus@8199
    95
    if (temp) {
icculus@8199
    96
        SDL_FreeSurface(temp);
icculus@8199
    97
    }
icculus@8199
    98
    return texture;
icculus@8199
    99
}
icculus@8199
   100
icculus@9278
   101
void
icculus@9278
   102
loop(void *arg)
icculus@9278
   103
{
icculus@9278
   104
    SDL_Event event;
icculus@9278
   105
    int i;
icculus@9278
   106
    SDL_GameController *gamecontroller = (SDL_GameController *)arg;
icculus@9278
   107
icculus@9278
   108
    /* blank screen, set up for drawing this frame. */
icculus@9278
   109
    SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
icculus@9278
   110
    SDL_RenderClear(screen);
icculus@9278
   111
    SDL_RenderCopy(screen, background, NULL, NULL);
icculus@9278
   112
icculus@9278
   113
    while (SDL_PollEvent(&event)) {
icculus@9278
   114
        switch (event.type) {
icculus@9278
   115
        case SDL_KEYDOWN:
icculus@9278
   116
            if (event.key.keysym.sym != SDLK_ESCAPE) {
icculus@9278
   117
                break;
icculus@9278
   118
            }
icculus@9278
   119
            /* Fall through to signal quit */
icculus@9278
   120
        case SDL_QUIT:
icculus@9278
   121
            done = SDL_TRUE;
icculus@9278
   122
            break;
icculus@9278
   123
        default:
icculus@9278
   124
            break;
icculus@9278
   125
        }
icculus@9278
   126
    }
icculus@9278
   127
icculus@9278
   128
    /* Update visual controller state */
icculus@9278
   129
    for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) {
icculus@9278
   130
        if (SDL_GameControllerGetButton(gamecontroller, (SDL_GameControllerButton)i) == SDL_PRESSED) {
icculus@9278
   131
            const SDL_Rect dst = { button_positions[i].x, button_positions[i].y, 50, 50 };
icculus@9278
   132
            SDL_RenderCopyEx(screen, button, NULL, &dst, 0, NULL, 0);
icculus@9278
   133
        }
icculus@9278
   134
    }
icculus@9278
   135
icculus@9278
   136
    for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i) {
icculus@9278
   137
        const Sint16 deadzone = 8000;  /* !!! FIXME: real deadzone */
icculus@9278
   138
        const Sint16 value = SDL_GameControllerGetAxis(gamecontroller, (SDL_GameControllerAxis)(i));
icculus@9278
   139
        if (value < -deadzone) {
icculus@9278
   140
            const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 };
icculus@9278
   141
            const double angle = axis_positions[i].angle;
icculus@9278
   142
            SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0);
icculus@9278
   143
        } else if (value > deadzone) {
icculus@9278
   144
            const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 };
icculus@9278
   145
            const double angle = axis_positions[i].angle + 180.0;
icculus@9278
   146
            SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0);
icculus@9278
   147
        }
icculus@9278
   148
    }
icculus@9278
   149
icculus@9278
   150
    SDL_RenderPresent(screen);
icculus@9278
   151
icculus@9278
   152
    if (!SDL_GameControllerGetAttached(gamecontroller)) {
icculus@9278
   153
        done = SDL_TRUE;
icculus@9278
   154
        retval = SDL_TRUE;  /* keep going, wait for reattach. */
icculus@9278
   155
    }
icculus@9278
   156
}
icculus@9278
   157
slouken@8068
   158
SDL_bool
slouken@6690
   159
WatchGameController(SDL_GameController * gamecontroller)
slouken@6690
   160
{
icculus@6916
   161
    const char *name = SDL_GameControllerName(gamecontroller);
icculus@6914
   162
    const char *basetitle = "Game Controller Test: ";
icculus@6916
   163
    const size_t titlelen = SDL_strlen(basetitle) + SDL_strlen(name) + 1;
aschiffler@7639
   164
    char *title = (char *)SDL_malloc(titlelen);
slouken@6690
   165
    SDL_Window *window = NULL;
philipp@9340
   166
philipp@9340
   167
    retval = SDL_FALSE;
philipp@9340
   168
    done = SDL_FALSE;
philipp@9340
   169
icculus@6914
   170
    if (title) {
icculus@6916
   171
        SDL_snprintf(title, titlelen, "%s%s", basetitle, name);
icculus@6914
   172
    }
icculus@6914
   173
icculus@8199
   174
    /* Create a window to display controller state */
icculus@6914
   175
    window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED,
slouken@6690
   176
                              SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
philipp@7478
   177
                              SCREEN_HEIGHT, 0);
slouken@6690
   178
    if (window == NULL) {
aschiffler@7639
   179
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
slouken@8068
   180
        return SDL_FALSE;
slouken@6690
   181
    }
slouken@6690
   182
slouken@6690
   183
    screen = SDL_CreateRenderer(window, -1, 0);
slouken@6690
   184
    if (screen == NULL) {
aschiffler@7639
   185
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
slouken@6690
   186
        SDL_DestroyWindow(window);
slouken@8068
   187
        return SDL_FALSE;
slouken@6690
   188
    }
slouken@6690
   189
slouken@6690
   190
    SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
slouken@6690
   191
    SDL_RenderClear(screen);
slouken@6690
   192
    SDL_RenderPresent(screen);
jorgen@7056
   193
    SDL_RaiseWindow(window);
slouken@6690
   194
icculus@8202
   195
    /* scale for platforms that don't give you the window size you asked for. */
icculus@8202
   196
    SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
icculus@8202
   197
icculus@8199
   198
    background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
icculus@8199
   199
    button = LoadTexture(screen, "button.bmp", SDL_TRUE);
icculus@8199
   200
    axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
icculus@8199
   201
icculus@8199
   202
    if (!background || !button || !axis) {
icculus@8199
   203
        SDL_DestroyRenderer(screen);
icculus@8199
   204
        SDL_DestroyWindow(window);
icculus@8199
   205
        return SDL_FALSE;
icculus@8199
   206
    }
icculus@8199
   207
    SDL_SetTextureColorMod(button, 10, 255, 21);
icculus@8199
   208
    SDL_SetTextureColorMod(axis, 10, 255, 21);
icculus@8199
   209
icculus@8199
   210
    /* !!! FIXME: */
icculus@8199
   211
    /*SDL_RenderSetLogicalSize(screen, background->w, background->h);*/
icculus@8199
   212
slouken@6690
   213
    /* Print info about the controller we are watching */
aschiffler@7639
   214
    SDL_Log("Watching controller %s\n",  name ? name : "Unknown Controller");
slouken@7191
   215
slouken@6690
   216
    /* Loop, getting controller events! */
icculus@9278
   217
#ifdef __EMSCRIPTEN__
icculus@9278
   218
    emscripten_set_main_loop_arg(loop, gamecontroller, 0, 1);
icculus@9278
   219
#else
slouken@6690
   220
    while (!done) {
philipp@9290
   221
        loop(gamecontroller);
slouken@6690
   222
    }
icculus@9278
   223
#endif
slouken@6690
   224
slouken@6690
   225
    SDL_DestroyRenderer(screen);
philipp@9340
   226
    screen = NULL;
philipp@9340
   227
    background = NULL;
philipp@9340
   228
    button = NULL;
philipp@9340
   229
    axis = NULL;
slouken@6690
   230
    SDL_DestroyWindow(window);
slouken@8068
   231
    return retval;
slouken@6690
   232
}
slouken@6690
   233
slouken@6690
   234
int
slouken@6690
   235
main(int argc, char *argv[])
slouken@6690
   236
{
slouken@6690
   237
    int i;
jorgen@7056
   238
    int nController = 0;
jorgen@7056
   239
    int retcode = 0;
jorgen@7056
   240
    char guid[64];
slouken@6690
   241
    SDL_GameController *gamecontroller;
slouken@6690
   242
aschiffler@7639
   243
    /* Enable standard application logging */
aschiffler@7639
   244
	SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
aschiffler@7639
   245
slouken@6690
   246
    /* Initialize SDL (Note: video is required to start event loop) */
slouken@6690
   247
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER ) < 0) {
aschiffler@7639
   248
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
jorgen@7056
   249
        return 1;
slouken@6690
   250
    }
gabomdq@8043
   251
    
gabomdq@8043
   252
    SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
slouken@6690
   253
slouken@6690
   254
    /* Print information about the controller */
slouken@6690
   255
    for (i = 0; i < SDL_NumJoysticks(); ++i) {
jorgen@7056
   256
        const char *name;
icculus@7705
   257
        const char *description;
jorgen@7056
   258
jorgen@7056
   259
        SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i),
jorgen@7056
   260
                                  guid, sizeof (guid));
jorgen@7056
   261
jorgen@7056
   262
        if ( SDL_IsGameController(i) )
jorgen@7056
   263
        {
jorgen@7056
   264
            nController++;
jorgen@7056
   265
            name = SDL_GameControllerNameForIndex(i);
icculus@7705
   266
            description = "Controller";
jorgen@7056
   267
        } else {
jorgen@7056
   268
            name = SDL_JoystickNameForIndex(i);
icculus@7705
   269
            description = "Joystick";
jorgen@7056
   270
        }
aschiffler@7639
   271
        SDL_Log("%s %d: %s (guid %s)\n", description, i, name ? name : "Unknown", guid);
slouken@6690
   272
    }
aschiffler@7639
   273
    SDL_Log("There are %d game controller(s) attached (%d joystick(s))\n", nController, SDL_NumJoysticks());
slouken@6690
   274
slouken@6690
   275
    if (argv[1]) {
slouken@8068
   276
        SDL_bool reportederror = SDL_FALSE;
slouken@8068
   277
        SDL_bool keepGoing = SDL_TRUE;
slouken@8068
   278
        SDL_Event event;
jorgen@7056
   279
        int device = atoi(argv[1]);
jorgen@7056
   280
        if (device >= SDL_NumJoysticks()) {
aschiffler@7639
   281
			SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%i is an invalid joystick index.\n", device);
jorgen@7056
   282
            retcode = 1;
jorgen@7056
   283
        } else {
jorgen@7056
   284
            SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(device),
jorgen@7056
   285
                                      guid, sizeof (guid));
aschiffler@7639
   286
            SDL_Log("Attempting to open device %i, guid %s\n", device, guid);
jorgen@7056
   287
            gamecontroller = SDL_GameControllerOpen(device);
slouken@8068
   288
            while (keepGoing) {
slouken@8068
   289
                if (gamecontroller == NULL) {
slouken@8068
   290
                    if (!reportederror) {
slouken@8068
   291
                        if (gamecontroller == NULL) {
slouken@8068
   292
                            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open gamecontroller %d: %s\n", device, SDL_GetError());
slouken@8068
   293
                            retcode = 1;
slouken@8068
   294
                        }
slouken@8068
   295
                        keepGoing = SDL_FALSE;
slouken@8068
   296
                        reportederror = SDL_TRUE;
slouken@8068
   297
                    }
slouken@8068
   298
                } else {
slouken@8068
   299
                    reportederror = SDL_FALSE;
slouken@8068
   300
                    keepGoing = WatchGameController(gamecontroller);
slouken@8068
   301
                    SDL_GameControllerClose(gamecontroller);
slouken@8068
   302
                }
slouken@8068
   303
slouken@8068
   304
                gamecontroller = NULL;
slouken@8068
   305
                if (keepGoing) {
slouken@8068
   306
                    SDL_Log("Waiting for attach\n");
slouken@8068
   307
                }
slouken@8068
   308
                while (keepGoing) {
slouken@8068
   309
                    SDL_WaitEvent(&event);
slouken@8068
   310
                    if ((event.type == SDL_QUIT) || (event.type == SDL_FINGERDOWN)
slouken@8068
   311
                        || (event.type == SDL_MOUSEBUTTONDOWN)) {
slouken@8068
   312
                        keepGoing = SDL_FALSE;
slouken@8068
   313
                    } else if (event.type == SDL_CONTROLLERDEVICEADDED) {
slouken@8068
   314
                        gamecontroller = SDL_GameControllerOpen(event.cdevice.which);
slouken@8068
   315
                        break;
slouken@8068
   316
                    }
slouken@8068
   317
                }
jorgen@7056
   318
            }
jorgen@7056
   319
        }
jorgen@7056
   320
    }
slouken@6690
   321
jorgen@7056
   322
    SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
jorgen@7056
   323
jorgen@7056
   324
    return retcode;
slouken@6690
   325
}
aschiffler@6771
   326
aschiffler@6771
   327
#else
aschiffler@6771
   328
aschiffler@6771
   329
int
aschiffler@6771
   330
main(int argc, char *argv[])
aschiffler@6771
   331
{
aschiffler@7639
   332
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
aschiffler@6771
   333
    exit(1);
aschiffler@6771
   334
}
aschiffler@6771
   335
aschiffler@6771
   336
#endif