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