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 /* Game controller mapping generator */
     14 /* Gabriel Jacobo <gabomdq (at) gmail.com> */
     15 
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 #include "SDL.h"
     21 
     22 #ifndef SDL_JOYSTICK_DISABLED
     23 
     24 #ifdef __IPHONEOS__
     25 #define SCREEN_WIDTH    320
     26 #define SCREEN_HEIGHT   480
     27 #else
     28 #define SCREEN_WIDTH    512
     29 #define SCREEN_HEIGHT   317
     30 #endif
     31 
     32 #define MAP_WIDTH 512
     33 #define MAP_HEIGHT 317
     34 
     35 #define MARKER_BUTTON 1
     36 #define MARKER_AXIS 2
     37 
     38 typedef struct MappingStep
     39 {
     40     int x, y;
     41     double angle;
     42     int marker;
     43     char *field;
     44     int axis, button, hat, hat_value;
     45     char mapping[4096];
     46 }MappingStep;
     47 
     48 
     49 SDL_Texture *
     50 LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
     51 {
     52     SDL_Surface *temp;
     53     SDL_Texture *texture;
     54 
     55     /* Load the sprite image */
     56     temp = SDL_LoadBMP(file);
     57     if (temp == NULL) {
     58         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
     59         return NULL;
     60     }
     61 
     62     /* Set transparent pixel as the pixel at (0,0) */
     63     if (transparent) {
     64         if (temp->format->palette) {
     65             SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
     66         } else {
     67             switch (temp->format->BitsPerPixel) {
     68             case 15:
     69                 SDL_SetColorKey(temp, SDL_TRUE,
     70                                 (*(Uint16 *) temp->pixels) & 0x00007FFF);
     71                 break;
     72             case 16:
     73                 SDL_SetColorKey(temp, SDL_TRUE, *(Uint16 *) temp->pixels);
     74                 break;
     75             case 24:
     76                 SDL_SetColorKey(temp, SDL_TRUE,
     77                                 (*(Uint32 *) temp->pixels) & 0x00FFFFFF);
     78                 break;
     79             case 32:
     80                 SDL_SetColorKey(temp, SDL_TRUE, *(Uint32 *) temp->pixels);
     81                 break;
     82             }
     83         }
     84     }
     85 
     86     /* Create textures from the image */
     87     texture = SDL_CreateTextureFromSurface(renderer, temp);
     88     if (!texture) {
     89         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
     90         SDL_FreeSurface(temp);
     91         return NULL;
     92     }
     93     SDL_FreeSurface(temp);
     94 
     95     /* We're ready to roll. :) */
     96     return texture;
     97 }
     98 
     99 static SDL_bool
    100 WatchJoystick(SDL_Joystick * joystick)
    101 {
    102     SDL_Window *window = NULL;
    103     SDL_Renderer *screen = NULL;
    104     SDL_Texture *background, *button, *axis, *marker;
    105     const char *name = NULL;
    106     SDL_bool retval = SDL_FALSE;
    107     SDL_bool done = SDL_FALSE, next=SDL_FALSE;
    108     SDL_Event event;
    109     SDL_Rect dst;
    110     int s, _s;
    111     Uint8 alpha=200, alpha_step = -1;
    112     Uint32 alpha_ticks;
    113     char mapping[4096], temp[4096];
    114     MappingStep *step;
    115     MappingStep steps[] = {
    116         {342, 132,  0.0,  MARKER_BUTTON, "x", -1, -1, -1, -1, ""},
    117         {387, 167,  0.0,  MARKER_BUTTON, "a", -1, -1, -1, -1, ""},
    118         {431, 132,  0.0,  MARKER_BUTTON, "b", -1, -1, -1, -1, ""},
    119         {389, 101,  0.0,  MARKER_BUTTON, "y", -1, -1, -1, -1, ""},
    120         {174, 132,  0.0,  MARKER_BUTTON, "back", -1, -1, -1, -1, ""},
    121         {233, 132,  0.0,  MARKER_BUTTON, "guide", -1, -1, -1, -1, ""},
    122         {289, 132,  0.0,  MARKER_BUTTON, "start", -1, -1, -1, -1, ""},
    123         {116, 217,  0.0,  MARKER_BUTTON, "dpleft", -1, -1, -1, -1, ""},
    124         {154, 249,  0.0,  MARKER_BUTTON, "dpdown", -1, -1, -1, -1, ""},
    125         {186, 217,  0.0,  MARKER_BUTTON, "dpright", -1, -1, -1, -1, ""},
    126         {154, 188,  0.0,  MARKER_BUTTON, "dpup", -1, -1, -1, -1, ""},
    127         {77,  40,   0.0,  MARKER_BUTTON, "leftshoulder", -1, -1, -1, -1, ""},
    128         {91, 0,    0.0,  MARKER_BUTTON, "lefttrigger", -1, -1, -1, -1, ""},
    129         {396, 36,   0.0,  MARKER_BUTTON, "rightshoulder", -1, -1, -1, -1, ""},
    130         {375, 0,    0.0,  MARKER_BUTTON, "righttrigger", -1, -1, -1, -1, ""},
    131         {75,  154,  0.0,  MARKER_BUTTON, "leftstick", -1, -1, -1, -1, ""},
    132         {305, 230,  0.0,  MARKER_BUTTON, "rightstick", -1, -1, -1, -1, ""},
    133         {75,  154,  0.0,  MARKER_AXIS,   "leftx", -1, -1, -1, -1, ""},
    134         {75,  154,  90.0, MARKER_AXIS,   "lefty", -1, -1, -1, -1, ""},
    135         {305, 230,  0.0,  MARKER_AXIS,   "rightx", -1, -1, -1, -1, ""},
    136         {305, 230,  90.0, MARKER_AXIS,   "righty", -1, -1, -1, -1, ""},
    137     };
    138 
    139     /* Create a window to display joystick axis position */
    140     window = SDL_CreateWindow("Game Controller Map", SDL_WINDOWPOS_CENTERED,
    141                               SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
    142                               SCREEN_HEIGHT, 0);
    143     if (window == NULL) {
    144         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
    145         return SDL_FALSE;
    146     }
    147 
    148     screen = SDL_CreateRenderer(window, -1, 0);
    149     if (screen == NULL) {
    150         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
    151         SDL_DestroyWindow(window);
    152         return SDL_FALSE;
    153     }
    154 
    155     background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
    156     button = LoadTexture(screen, "button.bmp", SDL_TRUE);
    157     axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
    158     SDL_RaiseWindow(window);
    159 
    160     /* scale for platforms that don't give you the window size you asked for. */
    161     SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
    162 
    163     /* Print info about the joystick we are watching */
    164     name = SDL_JoystickName(joystick);
    165     SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick),
    166            name ? name : "Unknown Joystick");
    167     SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
    168            SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
    169            SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
    170 
    171     SDL_Log("\n\n\
    172     ====================================================================================\n\
    173     Press the buttons on your controller when indicated\n\
    174     (Your controller may look different than the picture)\n\
    175     If you want to correct a mistake, press backspace or the back button on your device\n\
    176     To skip a button, press SPACE or click/touch the screen\n\
    177     To exit, press ESC\n\
    178     ====================================================================================\n");
    179 
    180     /* Initialize mapping with GUID and name */
    181     SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), temp, SDL_arraysize(temp));
    182     SDL_snprintf(mapping, SDL_arraysize(mapping), "%s,%s,platform:%s,",
    183         temp, name ? name : "Unknown Joystick", SDL_GetPlatform());
    184 
    185     /* Loop, getting joystick events! */
    186     for(s=0; s<SDL_arraysize(steps) && !done;) {
    187         /* blank screen, set up for drawing this frame. */
    188         step = &steps[s];
    189         SDL_strlcpy(step->mapping, mapping, SDL_arraysize(step->mapping));
    190         step->axis = -1;
    191         step->button = -1;
    192         step->hat = -1;
    193         step->hat_value = -1;
    194         SDL_SetClipboardText("TESTING TESTING 123");
    195 
    196         switch(step->marker) {
    197             case MARKER_AXIS:
    198                 marker = axis;
    199                 break;
    200             case MARKER_BUTTON:
    201                 marker = button;
    202                 break;
    203             default:
    204                 break;
    205         }
    206 
    207         dst.x = step->x;
    208         dst.y = step->y;
    209         SDL_QueryTexture(marker, NULL, NULL, &dst.w, &dst.h);
    210         next=SDL_FALSE;
    211 
    212         SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
    213 
    214         while (!done && !next) {
    215             if (SDL_GetTicks() - alpha_ticks > 5) {
    216                 alpha_ticks = SDL_GetTicks();
    217                 alpha += alpha_step;
    218                 if (alpha == 255) {
    219                     alpha_step = -1;
    220                 }
    221                 if (alpha < 128) {
    222                     alpha_step = 1;
    223                 }
    224             }
    225 
    226             SDL_RenderClear(screen);
    227             SDL_RenderCopy(screen, background, NULL, NULL);
    228             SDL_SetTextureAlphaMod(marker, alpha);
    229             SDL_SetTextureColorMod(marker, 10, 255, 21);
    230             SDL_RenderCopyEx(screen, marker, NULL, &dst, step->angle, NULL, 0);
    231             SDL_RenderPresent(screen);
    232 
    233             if (SDL_PollEvent(&event)) {
    234                 switch (event.type) {
    235                 case SDL_JOYAXISMOTION:
    236                     if (event.jaxis.value > 20000 || event.jaxis.value < -20000) {
    237                         for (_s = 0; _s < s; _s++) {
    238                             if (steps[_s].axis == event.jaxis.axis) {
    239                                 break;
    240                             }
    241                         }
    242                         if (_s == s) {
    243                             step->axis = event.jaxis.axis;
    244                             SDL_strlcat(mapping, step->field, SDL_arraysize(mapping));
    245                             SDL_snprintf(temp, SDL_arraysize(temp), ":a%u,", event.jaxis.axis);
    246                             SDL_strlcat(mapping, temp, SDL_arraysize(mapping));
    247                             s++;
    248                             next=SDL_TRUE;
    249                         }
    250                     }
    251 
    252                     break;
    253                 case SDL_JOYHATMOTION:
    254                         for (_s = 0; _s < s; _s++) {
    255                             if (steps[_s].hat == event.jhat.hat && steps[_s].hat_value == event.jhat.value) {
    256                                 break;
    257                             }
    258                         }
    259                         if (_s == s) {
    260                             step->hat = event.jhat.hat;
    261                             step->hat_value = event.jhat.value;
    262                             SDL_strlcat(mapping, step->field, SDL_arraysize(mapping));
    263                             SDL_snprintf(temp, SDL_arraysize(temp), ":h%u.%u,", event.jhat.hat, event.jhat.value );
    264                             SDL_strlcat(mapping, temp, SDL_arraysize(mapping));
    265                             s++;
    266                             next=SDL_TRUE;
    267                         }
    268                     break;
    269                 case SDL_JOYBALLMOTION:
    270                     break;
    271                 case SDL_JOYBUTTONUP:
    272                     for (_s = 0; _s < s; _s++) {
    273                         if (steps[_s].button == event.jbutton.button) {
    274                             break;
    275                         }
    276                     }
    277                     if (_s == s) {
    278                         step->button = event.jbutton.button;
    279                         SDL_strlcat(mapping, step->field, SDL_arraysize(mapping));
    280                         SDL_snprintf(temp, SDL_arraysize(temp), ":b%u,", event.jbutton.button);
    281                         SDL_strlcat(mapping, temp, SDL_arraysize(mapping));
    282                         s++;
    283                         next=SDL_TRUE;
    284                     }
    285                     break;
    286                 case SDL_FINGERDOWN:
    287                 case SDL_MOUSEBUTTONDOWN:
    288                     /* Skip this step */
    289                     s++;
    290                     next=SDL_TRUE;
    291                     break;
    292                 case SDL_KEYDOWN:
    293                     if (event.key.keysym.sym == SDLK_BACKSPACE || event.key.keysym.sym == SDLK_AC_BACK) {
    294                         /* Undo! */
    295                         if (s > 0) {
    296                             SDL_strlcpy(mapping, step->mapping, SDL_arraysize(step->mapping));
    297                             s--;
    298                             next = SDL_TRUE;
    299                         }
    300                         break;
    301                     }
    302                     if (event.key.keysym.sym == SDLK_SPACE) {
    303                         /* Skip this step */
    304                         s++;
    305                         next=SDL_TRUE;
    306                         break;
    307                     }
    308 
    309                     if ((event.key.keysym.sym != SDLK_ESCAPE)) {
    310                         break;
    311                     }
    312                     /* Fall through to signal quit */
    313                 case SDL_QUIT:
    314                     done = SDL_TRUE;
    315                     break;
    316                 default:
    317                     break;
    318                 }
    319             }
    320         }
    321 
    322     }
    323 
    324     if (s == SDL_arraysize(steps) ) {
    325         SDL_Log("Mapping:\n\n%s\n\n", mapping);
    326         /* Print to stdout as well so the user can cat the output somewhere */
    327         printf("%s\n", mapping);
    328     }
    329 
    330     while(SDL_PollEvent(&event)) {};
    331 
    332     SDL_DestroyRenderer(screen);
    333     SDL_DestroyWindow(window);
    334     return retval;
    335 }
    336 
    337 int
    338 main(int argc, char *argv[])
    339 {
    340     const char *name;
    341     int i;
    342     SDL_Joystick *joystick;
    343 
    344     /* Enable standard application logging */
    345     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
    346 
    347     /* Initialize SDL (Note: video is required to start event loop) */
    348     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
    349         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
    350         exit(1);
    351     }
    352 
    353     /* Print information about the joysticks */
    354     SDL_Log("There are %d joysticks attached\n", SDL_NumJoysticks());
    355     for (i = 0; i < SDL_NumJoysticks(); ++i) {
    356         name = SDL_JoystickNameForIndex(i);
    357         SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
    358         joystick = SDL_JoystickOpen(i);
    359         if (joystick == NULL) {
    360             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
    361                     SDL_GetError());
    362         } else {
    363             char guid[64];
    364             SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
    365                                       guid, sizeof (guid));
    366             SDL_Log("       axes: %d\n", SDL_JoystickNumAxes(joystick));
    367             SDL_Log("      balls: %d\n", SDL_JoystickNumBalls(joystick));
    368             SDL_Log("       hats: %d\n", SDL_JoystickNumHats(joystick));
    369             SDL_Log("    buttons: %d\n", SDL_JoystickNumButtons(joystick));
    370             SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick));
    371             SDL_Log("       guid: %s\n", guid);
    372             SDL_JoystickClose(joystick);
    373         }
    374     }
    375 
    376 #ifdef ANDROID
    377     if (SDL_NumJoysticks() > 0) {
    378 #else
    379     if (argv[1]) {
    380 #endif
    381         SDL_bool reportederror = SDL_FALSE;
    382         SDL_bool keepGoing = SDL_TRUE;
    383         SDL_Event event;
    384         int device;
    385 #ifdef ANDROID
    386         device = 0;
    387 #else
    388         device = atoi(argv[1]);
    389 #endif
    390         joystick = SDL_JoystickOpen(device);
    391 
    392         while ( keepGoing ) {
    393             if (joystick == NULL) {
    394                 if ( !reportederror ) {
    395                     SDL_Log("Couldn't open joystick %d: %s\n", device, SDL_GetError());
    396                     keepGoing = SDL_FALSE;
    397                     reportederror = SDL_TRUE;
    398                 }
    399             } else {
    400                 reportederror = SDL_FALSE;
    401                 keepGoing = WatchJoystick(joystick);
    402                 SDL_JoystickClose(joystick);
    403             }
    404 
    405             joystick = NULL;
    406             if (keepGoing) {
    407                 SDL_Log("Waiting for attach\n");
    408             }
    409             while (keepGoing) {
    410                 SDL_WaitEvent(&event);
    411                 if ((event.type == SDL_QUIT) || (event.type == SDL_FINGERDOWN)
    412                     || (event.type == SDL_MOUSEBUTTONDOWN)) {
    413                     keepGoing = SDL_FALSE;
    414                 } else if (event.type == SDL_JOYDEVICEADDED) {
    415                     joystick = SDL_JoystickOpen(device);
    416                     break;
    417                 }
    418             }
    419         }
    420     }
    421     else {
    422         SDL_Log("\n\nUsage: ./controllermap number\nFor example: ./controllermap 0\nOr: ./controllermap 0 >> gamecontrollerdb.txt");
    423     }
    424     SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
    425 
    426     return 0;
    427 }
    428 
    429 #else
    430 
    431 int
    432 main(int argc, char *argv[])
    433 {
    434     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
    435     exit(1);
    436 }
    437 
    438 #endif
    439