testgamecontroller.c
Go to the documentation of this file.
/*
Copyright (C) 1997-2016 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.
*/
/* Simple program to test the SDL game controller routines */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
#ifndef SDL_JOYSTICK_DISABLED
#ifdef __IPHONEOS__
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320
#else
#define SCREEN_WIDTH 512
#define SCREEN_HEIGHT 317
#endif
/* This is indexed by SDL_GameControllerButton. */
static const struct { int x; int y; } button_positions[] = {
{387, 167}, /* A */
{431, 132}, /* B */
{342, 132}, /* X */
{389, 101}, /* Y */
{174, 132}, /* BACK */
{233, 132}, /* GUIDE */
{289, 132}, /* START */
{75, 154}, /* LEFTSTICK */
{305, 230}, /* RIGHTSTICK */
{77, 40}, /* LEFTSHOULDER */
{396, 36}, /* RIGHTSHOULDER */
{154, 188}, /* DPAD_UP */
{154, 249}, /* DPAD_DOWN */
{116, 217}, /* DPAD_LEFT */
{186, 217}, /* DPAD_RIGHT */
};
/* This is indexed by SDL_GameControllerAxis. */
static const struct { int x; int y; double angle; } axis_positions[] = {
{75, 154, 0.0}, /* LEFTX */
{75, 154, 90.0}, /* LEFTY */
{305, 230, 0.0}, /* RIGHTX */
{305, 230, 90.0}, /* RIGHTY */
{91, 0, 90.0}, /* TRIGGERLEFT */
{375, 0, 90.0}, /* TRIGGERRIGHT */
};
SDL_Renderer *screen = NULL;
SDL_bool retval = SDL_FALSE;
SDL_bool done = SDL_FALSE;
SDL_Texture *background, *button, *axis;
static SDL_Texture *
LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
{
SDL_Surface *temp = NULL;
SDL_Texture *texture = NULL;
temp = SDL_LoadBMP(file);
if (temp == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
} else {
/* Set transparent pixel as the pixel at (0,0) */
if (transparent) {
if (temp->format->BytesPerPixel == 1) {
SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *)temp->pixels);
} else {
SDL_assert(!temp->format->palette);
SDL_assert(temp->format->BitsPerPixel == 24);
SDL_SetColorKey(temp, SDL_TRUE, (*(Uint32 *)temp->pixels) & 0x00FFFFFF);
}
}
texture = SDL_CreateTextureFromSurface(renderer, temp);
if (!texture) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
}
}
if (temp) {
SDL_FreeSurface(temp);
}
return texture;
}
void
loop(void *arg)
{
SDL_Event event;
int i;
SDL_GameController *gamecontroller = (SDL_GameController *)arg;
/* blank screen, set up for drawing this frame. */
SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
SDL_RenderClear(screen);
SDL_RenderCopy(screen, background, NULL, NULL);
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
if (event.key.keysym.sym != SDLK_ESCAPE) {
break;
}
/* Fall through to signal quit */
case SDL_QUIT:
done = SDL_TRUE;
break;
default:
break;
}
}
/* Update visual controller state */
for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) {
if (SDL_GameControllerGetButton(gamecontroller, (SDL_GameControllerButton)i) == SDL_PRESSED) {
const SDL_Rect dst = { button_positions[i].x, button_positions[i].y, 50, 50 };
SDL_RenderCopyEx(screen, button, NULL, &dst, 0, NULL, 0);
}
}
for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i) {
const Sint16 deadzone = 8000; /* !!! FIXME: real deadzone */
const Sint16 value = SDL_GameControllerGetAxis(gamecontroller, (SDL_GameControllerAxis)(i));
if (value < -deadzone) {
const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 };
const double angle = axis_positions[i].angle;
SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0);
} else if (value > deadzone) {
const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 };
const double angle = axis_positions[i].angle + 180.0;
SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0);
}
}
SDL_RenderPresent(screen);
if (!SDL_GameControllerGetAttached(gamecontroller)) {
done = SDL_TRUE;
retval = SDL_TRUE; /* keep going, wait for reattach. */
}
#ifdef __EMSCRIPTEN__
if (done) {
emscripten_cancel_main_loop();
}
#endif
}
SDL_bool
WatchGameController(SDL_GameController * gamecontroller)
{
const char *name = SDL_GameControllerName(gamecontroller);
const char *basetitle = "Game Controller Test: ";
const size_t titlelen = SDL_strlen(basetitle) + SDL_strlen(name) + 1;
char *title = (char *)SDL_malloc(titlelen);
SDL_Window *window = NULL;
retval = SDL_FALSE;
done = SDL_FALSE;
if (title) {
SDL_snprintf(title, titlelen, "%s%s", basetitle, name);
}
/* Create a window to display controller state */
window = SDL_CreateWindow(title, 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;
}
SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
SDL_RenderClear(screen);
SDL_RenderPresent(screen);
SDL_RaiseWindow(window);
/* scale for platforms that don't give you the window size you asked for. */
SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
button = LoadTexture(screen, "button.bmp", SDL_TRUE);
axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
if (!background || !button || !axis) {
SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window);
return SDL_FALSE;
}
SDL_SetTextureColorMod(button, 10, 255, 21);
SDL_SetTextureColorMod(axis, 10, 255, 21);
/* !!! FIXME: */
/*SDL_RenderSetLogicalSize(screen, background->w, background->h);*/
/* Print info about the controller we are watching */
SDL_Log("Watching controller %s\n", name ? name : "Unknown Controller");
/* Loop, getting controller events! */
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_arg(loop, gamecontroller, 0, 1);
#else
while (!done) {
loop(gamecontroller);
}
#endif
SDL_DestroyRenderer(screen);
screen = NULL;
background = NULL;
button = NULL;
axis = NULL;
SDL_DestroyWindow(window);
return retval;
}
int
main(int argc, char *argv[])
{
int i;
int nController = 0;
int retcode = 0;
char guid[64];
SDL_GameController *gamecontroller;
/* 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 | SDL_INIT_GAMECONTROLLER ) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
return 1;
}
SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
/* Print information about the controller */
for (i = 0; i < SDL_NumJoysticks(); ++i) {
const char *name;
const char *description;
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i),
guid, sizeof (guid));
if ( SDL_IsGameController(i) )
{
nController++;
name = SDL_GameControllerNameForIndex(i);
description = "Controller";
} else {
name = SDL_JoystickNameForIndex(i);
description = "Joystick";
}
SDL_Log("%s %d: %s (guid %s)\n", description, i, name ? name : "Unknown", guid);
}
SDL_Log("There are %d game controller(s) attached (%d joystick(s))\n", nController, SDL_NumJoysticks());
if (argv[1]) {
SDL_bool reportederror = SDL_FALSE;
SDL_bool keepGoing = SDL_TRUE;
SDL_Event event;
int device = atoi(argv[1]);
if (device >= SDL_NumJoysticks()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%i is an invalid joystick index.\n", device);
retcode = 1;
} else {
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(device),
guid, sizeof (guid));
SDL_Log("Attempting to open device %i, guid %s\n", device, guid);
gamecontroller = SDL_GameControllerOpen(device);
if (gamecontroller != NULL) {
SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller);
}
while (keepGoing) {
if (gamecontroller == NULL) {
if (!reportederror) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open gamecontroller %d: %s\n", device, SDL_GetError());
retcode = 1;
keepGoing = SDL_FALSE;
reportederror = SDL_TRUE;
}
} else {
reportederror = SDL_FALSE;
keepGoing = WatchGameController(gamecontroller);
SDL_GameControllerClose(gamecontroller);
}
gamecontroller = 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_CONTROLLERDEVICEADDED) {
gamecontroller = SDL_GameControllerOpen(event.cdevice.which);
if (gamecontroller != NULL) {
SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller);
}
break;
}
}
}
}
}
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
return retcode;
}
#else
int
main(int argc, char *argv[])
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
exit(1);
}
#endif
done
SDL_bool done
Definition: testgamecontroller.c:66
dst
GLenum GLenum dst
Definition: SDL_opengl_glext.h:1737
SDL_WINDOWPOS_CENTERED
#define SDL_WINDOWPOS_CENTERED
Definition: SDL_video.h:129
SDL_PollEvent
#define SDL_PollEvent
Definition: SDL_dynapi_overrides.h:128
SDL_KEYDOWN
Definition: SDL_events.h:93
SDL_GetError
#define SDL_GetError
Definition: SDL_dynapi_overrides.h:119
WatchGameController
SDL_bool WatchGameController(SDL_GameController *gamecontroller)
Definition: testgamecontroller.c:165
button
SDL_Texture * button
Definition: testgamecontroller.c:67
Uint32
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:157
SDL_Event::cdevice
SDL_ControllerDeviceEvent cdevice
Definition: SDL_events.h:539
SDL_LoadBMP
#define SDL_LoadBMP(file)
Definition: SDL_surface.h:182
SDL_INIT_JOYSTICK
#define SDL_INIT_JOYSTICK
Definition: SDL.h:78
SDL_IsGameController
#define SDL_IsGameController
Definition: SDL_dynapi_overrides.h:144
SDL_GameControllerGetAttached
#define SDL_GameControllerGetAttached
Definition: SDL_dynapi_overrides.h:148
SDL_PixelFormat::BytesPerPixel
Uint8 BytesPerPixel
Definition: SDL_pixels.h:304
SDL_GameControllerOpen
#define SDL_GameControllerOpen
Definition: SDL_dynapi_overrides.h:146
window
SDL_Window * window
Definition: testautomation_render.c:26
texture
GLenum GLenum GLuint texture
Definition: SDL_opengl_glext.h:1178
SDL_QuitSubSystem
#define SDL_QuitSubSystem
Definition: SDL_dynapi_overrides.h:62
SDL_JoystickNameForIndex
#define SDL_JoystickNameForIndex
Definition: SDL_dynapi_overrides.h:202
SDL_MOUSEBUTTONDOWN
Definition: SDL_events.h:103
SDL_Surface
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
SDL_QUIT
Definition: SDL_events.h:60
SDL_Renderer
Definition: SDL_sysrender.h:76
SCREEN_HEIGHT
#define SCREEN_HEIGHT
Definition: testgamecontroller.c:32
SDL_GameControllerGetJoystick
#define SDL_GameControllerGetJoystick
Definition: SDL_dynapi_overrides.h:149
SDL_GameControllerName
#define SDL_GameControllerName
Definition: SDL_dynapi_overrides.h:147
SDL_NumJoysticks
#define SDL_NumJoysticks
Definition: SDL_dynapi_overrides.h:201
SDL_CreateWindow
#define SDL_CreateWindow
Definition: SDL_dynapi_overrides.h:518
SDL_CONTROLLER_AXIS_MAX
Definition: SDL_gamecontroller.h:227
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:660
axis
SDL_Texture * axis
Definition: testgamecontroller.c:67
background
SDL_Texture * background
Definition: testgamecontroller.c:67
SDL_GameControllerButton
SDL_GameControllerButton
Definition: SDL_gamecontroller.h:262
SDL_CONTROLLERDEVICEADDED
Definition: SDL_events.h:120
SDL_JoystickGetGUIDString
#define SDL_JoystickGetGUIDString
Definition: SDL_dynapi_overrides.h:207
SDL_JoystickInstanceID
#define SDL_JoystickInstanceID
Definition: SDL_dynapi_overrides.h:210
SDL_ControllerDeviceEvent::which
Sint32 which
Definition: SDL_events.h:389
loop
void loop(void *arg)
Definition: testgamecontroller.c:102
SDL_Texture
Definition: SDL_sysrender.h:49
SDL_JoystickGetDeviceGUID
#define SDL_JoystickGetDeviceGUID
Definition: SDL_dynapi_overrides.h:205
SDL_LogError
#define SDL_LogError
Definition: SDL_dynapi_overrides.h:42
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:126
y
int y
Definition: testgamecontroller.c:36
SDL_RenderCopy
#define SDL_RenderCopy
Definition: SDL_dynapi_overrides.h:349
SCREEN_WIDTH
#define SCREEN_WIDTH
Definition: testgamecontroller.c:31
renderer
SDL_Renderer * renderer
Definition: testautomation_render.c:27
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_Log
#define SDL_Log
Definition: SDL_dynapi_overrides.h:37
SDL_FINGERDOWN
Definition: SDL_events.h:125
SDL_CreateTextureFromSurface
#define SDL_CreateTextureFromSurface
Definition: SDL_dynapi_overrides.h:313
SDL_GameControllerFromInstanceID
#define SDL_GameControllerFromInstanceID
Definition: SDL_dynapi_overrides.h:598
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:698
SDL_Surface::pixels
void * pixels
Definition: SDL_surface.h:75
SDL_FreeSurface
#define SDL_FreeSurface
Definition: SDL_dynapi_overrides.h:450
Uint8
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
event
struct _cl_event * event
Definition: SDL_opengl_glext.h:2649
SDL_PixelFormat::BitsPerPixel
Uint8 BitsPerPixel
Definition: SDL_pixels.h:303
SDL_RenderSetLogicalSize
#define SDL_RenderSetLogicalSize
Definition: SDL_dynapi_overrides.h:328
SDL_RaiseWindow
#define SDL_RaiseWindow
Definition: SDL_dynapi_overrides.h:539
SDL_CONTROLLER_BUTTON_MAX
Definition: SDL_gamecontroller.h:280
angle
double angle
Definition: testgamecontroller.c:55
SDL_SetColorKey
#define SDL_SetColorKey
Definition: SDL_dynapi_overrides.h:457
SDL_SetTextureColorMod
#define SDL_SetTextureColorMod
Definition: SDL_dynapi_overrides.h:315
SDL_LOG_PRIORITY_INFO
Definition: SDL_log.h:106
SDL_KeyboardEvent::keysym
SDL_Keysym keysym
Definition: SDL_events.h:196
SDL_TRUE
Definition: SDL_stdinc.h:129
SDL_GameControllerClose
#define SDL_GameControllerClose
Definition: SDL_dynapi_overrides.h:160
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:167
SDL_LogSetPriority
#define SDL_LogSetPriority
Definition: SDL_dynapi_overrides.h:242
NULL
#define NULL
Definition: begin_code.h:143
SDL_GameControllerGetButton
#define SDL_GameControllerGetButton
Definition: SDL_dynapi_overrides.h:159
SDL_Surface::format
SDL_PixelFormat * format
Definition: SDL_surface.h:72
SDL_WaitEvent
#define SDL_WaitEvent
Definition: SDL_dynapi_overrides.h:129
SDL_RenderClear
#define SDL_RenderClear
Definition: SDL_dynapi_overrides.h:340
SDL_Event::key
SDL_KeyboardEvent key
Definition: SDL_events.h:526
button_positions
static const struct @41 button_positions[]
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:399
SDL_Window
The type used to identify a window.
Definition: SDL_sysvideo.h:71
SDL_FALSE
Definition: SDL_stdinc.h:128
SDL_RenderCopyEx
#define SDL_RenderCopyEx
Definition: SDL_dynapi_overrides.h:350
SDL_Keysym::sym
SDL_Keycode sym
Definition: SDL_keyboard.h:50
LoadTexture
static SDL_Texture * LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
Definition: testgamecontroller.c:70
angle
GLfloat angle
Definition: SDL_opengl_glext.h:6097
SDL_GameControllerNameForIndex
#define SDL_GameControllerNameForIndex
Definition: SDL_dynapi_overrides.h:145
SDL_snprintf
#define SDL_snprintf
Definition: SDL_dynapi_overrides.h:46
SDL_Init
#define SDL_Init
Definition: SDL_dynapi_overrides.h:60
SDL_INIT_GAMECONTROLLER
#define SDL_INIT_GAMECONTROLLER
Definition: SDL.h:80
SDL_Event
General event structure.
Definition: SDL_events.h:521
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:380
SDL_SetRenderDrawColor
#define SDL_SetRenderDrawColor
Definition: SDL_dynapi_overrides.h:336
SDL_PixelFormat::palette
SDL_Palette * palette
Definition: SDL_pixels.h:302
SDL_GameControllerGetAxis
#define SDL_GameControllerGetAxis
Definition: SDL_dynapi_overrides.h:155
SDL_GameControllerAddMappingsFromFile
#define SDL_GameControllerAddMappingsFromFile(file)
Definition: SDL_gamecontroller.h:127
SDL_DestroyRenderer
#define SDL_DestroyRenderer
Definition: SDL_dynapi_overrides.h:354
SDL_PRESSED
#define SDL_PRESSED
Definition: SDL_events.h:50
SDLK_ESCAPE
Definition: SDL_keycode.h:52
SDL_ALPHA_OPAQUE
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:45
SDL.h
x
int x
Definition: testgamecontroller.c:36
screen
SDL_Renderer * screen
Definition: testgamecontroller.c:64
SDL_DestroyWindow
#define SDL_DestroyWindow
Definition: SDL_dynapi_overrides.h:553
SDL_LOG_CATEGORY_APPLICATION
Definition: SDL_log.h:66
axis_positions
static const struct @42 axis_positions[]
SDL_GameControllerAxis
SDL_GameControllerAxis
Definition: SDL_gamecontroller.h:218
SDL_INIT_VIDEO
#define SDL_INIT_VIDEO
Definition: SDL.h:77
SDL_CreateRenderer
#define SDL_CreateRenderer
Definition: SDL_dynapi_overrides.h:307
main
int main(int argc, char *argv[])
Definition: testgamecontroller.c:241
SDL_Rect
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
Sint16
int16_t Sint16
A signed 16-bit integer type.
Definition: SDL_stdinc.h:143
SDL_RenderPresent
#define SDL_RenderPresent
Definition: SDL_dynapi_overrides.h:352
SDL_Event::type
Uint32 type
Definition: SDL_events.h:523