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