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