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