test/testgamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 28 Nov 2014 04:51:33 -0800
changeset 9246 a761913e5e91
parent 9102 a22458d5eed9
child 9278 8900afb78a19
permissions -rw-r--r--
Fixed bug 2786 - "UCS-2-INTERNAL" iconv encoding is not supported everywhere, use UTF-16LE instead

Jonas Kulla

src/main/windows/SDL_windows_main.c:137:
cmdline = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char *)(text), (SDL_wcslen(text)+1)*sizeof(WCHAR));

I'm trying to compile an SDL2 application for windows using the mingw-w64 32bit toolchain provided by my distro (Fedora 19). However, even the simplest test program that does nothing at all fails to startup with a "Fatal error - out of memory" message because the mingw iconv library provided by my distro does not support the "UCS-2-INTERNAL" encoding and the conversion returns null.

From my little bit of research, it turns out that even though this encoding is supported by the external GNU libiconv library, some glibc versions (?) don't support it with their internal iconv routines, and will instead provide the native endian encoding when "UCS-2" is specified.

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