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