Adds controllermap utility to test suite.

Gabriel Jacobo 2013-12-02 19:35:04 -03:00
parent 45ae148aef
commit 95ec90aa8a
8 changed files with 445 additions and 1 deletions

View File

@ -26,6 +26,8 @@
The easiest way to generate a new mapping is to start Steam in Big Picture The easiest way to generate a new mapping is to start Steam in Big Picture
mode, configure your joystick and then look in config/config.vdf in your mode, configure your joystick and then look in config/config.vdf in your
Steam installation directory for the "SDL_GamepadBind" entry. Steam installation directory for the "SDL_GamepadBind" entry.
Alternatively, you can use the app located in test/controllermap
*/ */
static const char *s_ControllerMappings [] = static const char *s_ControllerMappings [] =
{ {

View File

@ -55,6 +55,7 @@ TARGETS = \
torturethread$(EXE) \ torturethread$(EXE) \
testrendercopyex$(EXE) \ testrendercopyex$(EXE) \
testmessage$(EXE) \ testmessage$(EXE) \
controllermap$(EXE) \
all: Makefile $(TARGETS) all: Makefile $(TARGETS)
@ -238,6 +239,10 @@ testrendercopyex$(EXE): $(srcdir)/testrendercopyex.c
testmessage$(EXE): $(srcdir)/testmessage.c testmessage$(EXE): $(srcdir)/testmessage.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) $(CC) -o $@ $^ $(CFLAGS) $(LIBS)
controllermap$(EXE): $(srcdir)/controllermap.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
clean: clean:
rm -f $(TARGETS) rm -f $(TARGETS)

View File

@ -25,3 +25,6 @@ These are test programs for the SDL library:
testver Check the version and dynamic loading and endianness testver Check the version and dynamic loading and endianness
testwm2 Test window manager -- title, icon, events testwm2 Test window manager -- title, icon, events
torturethread Simple test for thread creation/destruction torturethread Simple test for thread creation/destruction
controllermap Useful to generate Game Controller API compatible maps

BIN
test/axis.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
test/button.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
test/controllermap.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

432
test/controllermap.c Normal file
View File

@ -0,0 +1,432 @@
/*
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/
/* Game controller mapping generator */
/* Gabriel Jacobo <gabomdq@gmail.com> */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"
#ifndef SDL_JOYSTICK_DISABLED
#ifdef __IPHONEOS__
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 480
#else
#define SCREEN_WIDTH 512
#define SCREEN_HEIGHT 317
#endif
#define MAP_WIDTH 512
#define MAP_HEIGHT 317
#define MARKER_BUTTON 1
#define MARKER_AXIS 2
typedef struct MappingStep
{
int x, y;
double angle;
int marker;
char *field;
int axis, button, hat, hat_value;
char mapping[4096];
}MappingStep;
SDL_Texture *
LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
{
SDL_Surface *temp;
SDL_Texture *texture;
/* Load the sprite image */
temp = SDL_LoadBMP(file);
if (temp == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
return NULL;
}
/* Set transparent pixel as the pixel at (0,0) */
if (transparent) {
if (temp->format->palette) {
SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
} else {
switch (temp->format->BitsPerPixel) {
case 15:
SDL_SetColorKey(temp, SDL_TRUE,
(*(Uint16 *) temp->pixels) & 0x00007FFF);
break;
case 16:
SDL_SetColorKey(temp, SDL_TRUE, *(Uint16 *) temp->pixels);
break;
case 24:
SDL_SetColorKey(temp, SDL_TRUE,
(*(Uint32 *) temp->pixels) & 0x00FFFFFF);
break;
case 32:
SDL_SetColorKey(temp, SDL_TRUE, *(Uint32 *) temp->pixels);
break;
}
}
}
/* Create textures from the image */
texture = SDL_CreateTextureFromSurface(renderer, temp);
if (!texture) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
SDL_FreeSurface(temp);
return NULL;
}
SDL_FreeSurface(temp);
/* We're ready to roll. :) */
return texture;
}
static void
DrawRect(SDL_Renderer *r, const int x, const int y, const int w, const int h)
{
const SDL_Rect area = { x, y, w, h };
SDL_RenderFillRect(r, &area);
}
static SDL_bool
WatchJoystick(SDL_Joystick * joystick)
{
SDL_Window *window = NULL;
SDL_Renderer *screen = NULL;
SDL_Texture *target, *background, *button, *axis, *marker;
const char *name = NULL;
SDL_bool retval = SDL_FALSE;
SDL_bool done = SDL_FALSE, next=SDL_FALSE;
SDL_Event event;
SDL_Rect dst;
int i, s, _s;
Uint8 alpha=200, alpha_step = -1;
Uint32 alpha_ticks;
char mapping[4096], temp[4096];
MappingStep *step;
MappingStep steps[] = {
{342, 132, 0.0, MARKER_BUTTON, "x", -1, -1, -1, -1, ""},
{387, 167, 0.0, MARKER_BUTTON, "a", -1, -1, -1, -1, ""},
{431, 132, 0.0, MARKER_BUTTON, "b", -1, -1, -1, -1, ""},
{389, 101, 0.0, MARKER_BUTTON, "y", -1, -1, -1, -1, ""},
{174, 132, 0.0, MARKER_BUTTON, "back", -1, -1, -1, -1, ""},
{233, 132, 0.0, MARKER_BUTTON, "guide", -1, -1, -1, -1, ""},
{289, 132, 0.0, MARKER_BUTTON, "start", -1, -1, -1, -1, ""},
{116, 217, 0.0, MARKER_BUTTON, "dpleft", -1, -1, -1, -1, ""},
{154, 249, 0.0, MARKER_BUTTON, "dpdown", -1, -1, -1, -1, ""},
{186, 217, 0.0, MARKER_BUTTON, "dpright", -1, -1, -1, -1, ""},
{154, 188, 0.0, MARKER_BUTTON, "dpup", -1, -1, -1, -1, ""},
{77, 40, 0.0, MARKER_BUTTON, "leftshoulder", -1, -1, -1, -1, ""},
{91, 0, 0.0, MARKER_BUTTON, "lefttrigger", -1, -1, -1, -1, ""},
{396, 36, 0.0, MARKER_BUTTON, "rightshoulder", -1, -1, -1, -1, ""},
{375, 0, 0.0, MARKER_BUTTON, "righttrigger", -1, -1, -1, -1, ""},
{75, 154, 0.0, MARKER_BUTTON, "leftstick", -1, -1, -1, -1, ""},
{305, 230, 0.0, MARKER_BUTTON, "rightstick", -1, -1, -1, -1, ""},
{75, 154, 0.0, MARKER_AXIS, "leftx", -1, -1, -1, -1, ""},
{75, 154, 90.0, MARKER_AXIS, "lefty", -1, -1, -1, -1, ""},
{305, 230, 0.0, MARKER_AXIS, "rightx", -1, -1, -1, -1, ""},
{305, 230, 90.0, MARKER_AXIS, "righty", -1, -1, -1, -1, ""},
};
/* Create a window to display joystick axis position */
window = SDL_CreateWindow("Joystick Test", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
SCREEN_HEIGHT, 0);
if (window == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
return SDL_FALSE;
}
screen = SDL_CreateRenderer(window, -1, 0);
if (screen == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
return SDL_FALSE;
}
target = SDL_CreateTexture(screen, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, MAP_WIDTH, MAP_HEIGHT);
background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
button = LoadTexture(screen, "button.bmp", SDL_TRUE);
axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
SDL_RaiseWindow(window);
/* Print info about the joystick we are watching */
name = SDL_JoystickName(joystick);
SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick),
name ? name : "Unknown Joystick");
SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
SDL_Log("\n\n\
====================================================================================\n\
Press the buttons on your controller when indicated\n\
(Your controller may look different than the picture)\n\
If you want to correct a mistake, press backspace or the back button on your device\n\
To exit, press ESC\n\
====================================================================================\n");
/* Initialize mapping with GUID and name */
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), temp, SDL_arraysize(temp));
SDL_snprintf(mapping, SDL_arraysize(mapping), "%s,%s,platform:%s,",
temp, name ? name : "Unknown Joystick", SDL_GetPlatform());
/* Loop, getting joystick events! */
for(s=0; s<SDL_arraysize(steps) && !done;) {
/* blank screen, set up for drawing this frame. */
step = &steps[s];
SDL_strlcpy(step->mapping, mapping, SDL_arraysize(step->mapping));
step->axis = -1;
step->button = -1;
step->hat = -1;
step->hat_value = -1;
SDL_SetClipboardText("TESTING TESTING 123");
switch(step->marker) {
case MARKER_AXIS:
marker = axis;
break;
case MARKER_BUTTON:
marker = button;
break;
default:
break;
}
dst.x = step->x;
dst.y = step->y;
SDL_QueryTexture(marker, NULL, NULL, &dst.w, &dst.h);
next=SDL_FALSE;
while (!done && !next) {
if (SDL_GetTicks() - alpha_ticks > 5) {
alpha_ticks = SDL_GetTicks();
alpha += alpha_step;
if (alpha == 255) {
alpha_step = -1;
}
if (alpha < 128) {
alpha_step = 1;
}
}
SDL_SetRenderTarget(screen, target);
SDL_RenderCopy(screen, background, NULL, NULL);
SDL_SetTextureAlphaMod(marker, alpha);
SDL_SetTextureColorMod(marker, 10, 255, 21);
SDL_RenderCopyEx(screen, marker, NULL, &dst, step->angle, NULL, 0);
SDL_SetRenderTarget(screen, NULL);
SDL_RenderCopy(screen, target, NULL, NULL);
SDL_RenderPresent(screen);
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_JOYAXISMOTION:
if (event.jaxis.value > 20000 || event.jaxis.value < -20000) {
for (_s = 0; _s < s; _s++) {
if (steps[_s].axis == event.jaxis.axis) {
break;
}
}
if (_s == s) {
step->axis = event.jaxis.axis;
SDL_strlcat(mapping, step->field, SDL_arraysize(mapping));
SDL_snprintf(temp, SDL_arraysize(temp), ":a%u,", event.jaxis.axis);
SDL_strlcat(mapping, temp, SDL_arraysize(mapping));
s++;
next=SDL_TRUE;
}
}
break;
case SDL_JOYHATMOTION:
for (_s = 0; _s < s; _s++) {
if (steps[_s].hat == event.jhat.hat && steps[_s].hat_value == event.jhat.value) {
break;
}
}
if (_s == s) {
step->hat = event.jhat.hat;
step->hat_value = event.jhat.value;
SDL_strlcat(mapping, step->field, SDL_arraysize(mapping));
SDL_snprintf(temp, SDL_arraysize(temp), ":h%u.%u,", event.jhat.hat, event.jhat.value );
SDL_strlcat(mapping, temp, SDL_arraysize(mapping));
s++;
next=SDL_TRUE;
}
break;
case SDL_JOYBALLMOTION:
break;
case SDL_JOYBUTTONUP:
for (_s = 0; _s < s; _s++) {
if (steps[_s].button == event.jbutton.button) {
break;
}
}
if (_s == s) {
step->button = event.jbutton.button;
SDL_strlcat(mapping, step->field, SDL_arraysize(mapping));
SDL_snprintf(temp, SDL_arraysize(temp), ":b%u,", event.jbutton.button);
SDL_strlcat(mapping, temp, SDL_arraysize(mapping));
s++;
next=SDL_TRUE;
}
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_BACKSPACE || event.key.keysym.sym == SDLK_AC_BACK) {
/* Undo! */
if (s > 0) {
SDL_strlcpy(mapping, step->mapping, SDL_arraysize(step->mapping));
s--;
next = SDL_TRUE;
}
break;
}
if ((event.key.keysym.sym != SDLK_ESCAPE)) {
break;
}
/* Fall through to signal quit */
case SDL_FINGERDOWN:
case SDL_MOUSEBUTTONDOWN:
case SDL_QUIT:
done = SDL_TRUE;
break;
default:
break;
}
}
}
}
if (s == SDL_arraysize(steps) ) {
SDL_Log("Mapping:\n\n%s\n\n", mapping);
/* Print to stdout as well so the user can cat the output somewhere */
printf("%s\n", mapping);
}
while(SDL_PollEvent(&event)) {};
SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window);
return retval;
}
int
main(int argc, char *argv[])
{
const char *name;
int i;
SDL_Joystick *joystick;
/* Enable standard application logging */
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
/* Initialize SDL (Note: video is required to start event loop) */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
/* Print information about the joysticks */
SDL_Log("There are %d joysticks attached\n", SDL_NumJoysticks());
for (i = 0; i < SDL_NumJoysticks(); ++i) {
name = SDL_JoystickNameForIndex(i);
SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
joystick = SDL_JoystickOpen(i);
if (joystick == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
SDL_GetError());
} else {
char guid[64];
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
guid, sizeof (guid));
SDL_Log(" axes: %d\n", SDL_JoystickNumAxes(joystick));
SDL_Log(" balls: %d\n", SDL_JoystickNumBalls(joystick));
SDL_Log(" hats: %d\n", SDL_JoystickNumHats(joystick));
SDL_Log(" buttons: %d\n", SDL_JoystickNumButtons(joystick));
SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick));
SDL_Log(" guid: %s\n", guid);
SDL_JoystickClose(joystick);
}
}
#ifdef ANDROID
if (SDL_NumJoysticks() > 0) {
#else
if (argv[1]) {
#endif
SDL_bool reportederror = SDL_FALSE;
SDL_bool keepGoing = SDL_TRUE;
SDL_Event event;
#ifdef ANDROID
joystick = SDL_JoystickOpen(0);
#else
joystick = SDL_JoystickOpen(atoi(argv[1]));
#endif
while ( keepGoing ) {
if (joystick == NULL) {
if ( !reportederror ) {
SDL_Log("Couldn't open joystick %d: %s\n", atoi(argv[1]), SDL_GetError());
keepGoing = SDL_FALSE;
reportederror = SDL_TRUE;
}
} else {
reportederror = SDL_FALSE;
keepGoing = WatchJoystick(joystick);
SDL_JoystickClose(joystick);
}
joystick = NULL;
if (keepGoing) {
SDL_Log("Waiting for attach\n");
}
while (keepGoing) {
SDL_WaitEvent(&event);
if ((event.type == SDL_QUIT) || (event.type == SDL_FINGERDOWN)
|| (event.type == SDL_MOUSEBUTTONDOWN)) {
keepGoing = SDL_FALSE;
} else if (event.type == SDL_JOYDEVICEADDED) {
joystick = SDL_JoystickOpen(atoi(argv[1]));
break;
}
}
}
}
else {
SDL_Log("\n\nUsage: ./controllermap number\nFor example: ./controllermap 0\nOr: ./controllermap 0 >> gamecontrollerdb.txt");
}
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
#ifdef ANDROID
exit(0);
#else
return 0;
#endif
}
#else
int
main(int argc, char *argv[])
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
exit(1);
}
#endif

View File

@ -226,6 +226,8 @@ main(int argc, char *argv[])
return 1; return 1;
} }
SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
/* Print information about the controller */ /* Print information about the controller */
for (i = 0; i < SDL_NumJoysticks(); ++i) { for (i = 0; i < SDL_NumJoysticks(); ++i) {
const char *name; const char *name;