Split controller axes into positive and negative sides so each can be bound independently.

Using this a D-Pad can be mapped to a thumbstick and vice versa.
Also added support for inverted axes, improving trigger binding support
This commit is contained in:
Sam Lantinga 2016-12-27 01:39:07 -08:00
parent 7c31636666
commit 6d7da0887d
7 changed files with 609 additions and 340 deletions

View File

@ -232,6 +232,8 @@ extern DECLSPEC void SDLCALL SDL_JoystickUpdate(void);
*/ */
extern DECLSPEC int SDLCALL SDL_JoystickEventState(int state); extern DECLSPEC int SDLCALL SDL_JoystickEventState(int state);
#define SDL_JOYSTICK_AXIS_MAX 32767
#define SDL_JOYSTICK_AXIS_MIN -32768
/** /**
* Get the current state of an axis control on a joystick. * Get the current state of an axis control on a joystick.
* *

View File

@ -32,53 +32,46 @@
#if !SDL_EVENTS_DISABLED #if !SDL_EVENTS_DISABLED
#include "../events/SDL_events_c.h" #include "../events/SDL_events_c.h"
#endif #endif
#define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
#define SDL_CONTROLLER_PLATFORM_FIELD "platform:" #define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
/* a list of currently opened game controllers */ /* a list of currently opened game controllers */
static SDL_GameController *SDL_gamecontrollers = NULL; static SDL_GameController *SDL_gamecontrollers = NULL;
/* keep track of the hat and mask value that transforms this hat movement into a button/axis press */ typedef struct
struct _SDL_HatMapping
{ {
int hat; SDL_GameControllerBindType inputType;
Uint8 mask; union
}; {
int button;
/* We need 36 entries for Android (as of SDL v2.0.4) */ struct {
#define k_nMaxReverseEntries 48 int axis;
int axis_min;
int axis_max;
} axis;
/** struct {
* We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask int hat;
* MAX 4 hats supported int hat_mask;
*/ } hat;
#define k_nMaxHatEntries 0x3f + 1
/* our in memory mapping db between joystick objects and controller mappings */ } input;
struct _SDL_ControllerMapping
{
SDL_JoystickGUID guid;
const char *name;
/* mapping of axis/button id to controller version */ SDL_GameControllerBindType outputType;
int axes[SDL_CONTROLLER_AXIS_MAX]; union
int buttonasaxis[SDL_CONTROLLER_AXIS_MAX]; {
SDL_GameControllerButton button;
int buttons[SDL_CONTROLLER_BUTTON_MAX]; struct {
int axesasbutton[SDL_CONTROLLER_BUTTON_MAX]; SDL_GameControllerAxis axis;
struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX]; int axis_min;
int axis_max;
} axis;
/* reverse mapping, joystick indices to buttons */ } output;
SDL_GameControllerAxis raxes[k_nMaxReverseEntries];
SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries];
SDL_GameControllerButton rbuttons[k_nMaxReverseEntries];
SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries];
SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries];
};
} SDL_ExtendedGameControllerBind;
/* our hard coded list of mapping support */ /* our hard coded list of mapping support */
typedef enum typedef enum
@ -107,14 +100,20 @@ struct _SDL_GameController
{ {
SDL_Joystick *joystick; /* underlying joystick device */ SDL_Joystick *joystick; /* underlying joystick device */
int ref_count; int ref_count;
Uint8 hatState[4]; /* the current hat state for this controller */
struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */ SDL_JoystickGUID guid;
const char *name;
int num_bindings;
SDL_ExtendedGameControllerBind *bindings;
SDL_ExtendedGameControllerBind **last_match_axis;
Uint8 *last_hat_mask;
struct _SDL_GameController *next; /* pointer to next game controller we have allocated */ struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
}; };
int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value); static int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state); static int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
/* /*
* If there is an existing add event in the queue, it needs to be modified * If there is an existing add event in the queue, it needs to be modified
@ -145,6 +144,124 @@ static void UpdateEventsForDeviceRemoval()
SDL_stack_free(events); SDL_stack_free(events);
} }
static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
{
if (a->outputType != b->outputType) {
return SDL_FALSE;
}
if (a->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
return (a->output.axis.axis == b->output.axis.axis);
} else {
return (a->output.button == b->output.button);
}
}
static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind)
{
if (bind->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
SDL_PrivateGameControllerAxis(gamecontroller, bind->output.axis.axis, 0);
} else {
SDL_PrivateGameControllerButton(gamecontroller, bind->output.button, SDL_RELEASED);
}
}
static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value)
{
int i;
SDL_ExtendedGameControllerBind *last_match = gamecontroller->last_match_axis[axis];
SDL_ExtendedGameControllerBind *match = NULL;
for (i = 0; i < gamecontroller->num_bindings; ++i) {
SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
axis == binding->input.axis.axis) {
if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
if (value >= binding->input.axis.axis_min &&
value <= binding->input.axis.axis_max) {
match = binding;
break;
}
} else {
if (value >= binding->input.axis.axis_max &&
value <= binding->input.axis.axis_min) {
match = binding;
break;
}
}
}
}
if (last_match && (!match || !HasSameOutput(last_match, match))) {
/* Clear the last input that this axis generated */
ResetOutput(gamecontroller, last_match);
}
if (match) {
if (match->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
if (match->input.axis.axis_min != match->output.axis.axis_min || match->input.axis.axis_max != match->output.axis.axis_max) {
float normalized_value = (float)(value - match->input.axis.axis_min) / (match->input.axis.axis_max - match->input.axis.axis_min);
value = match->output.axis.axis_min + (int)(normalized_value * (match->output.axis.axis_max - match->output.axis.axis_min));
}
SDL_PrivateGameControllerAxis(gamecontroller, match->output.axis.axis, (Sint16)value);
} else {
Uint8 state;
int threshold = match->input.axis.axis_min + (match->input.axis.axis_max - match->input.axis.axis_min) / 2;
if (match->input.axis.axis_max < match->input.axis.axis_min) {
state = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
} else {
state = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
}
SDL_PrivateGameControllerButton(gamecontroller, match->output.button, state);
}
}
gamecontroller->last_match_axis[axis] = match;
}
static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state)
{
int i;
for (i = 0; i < gamecontroller->num_bindings; ++i) {
SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON &&
button == binding->input.button) {
if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
int value = state ? binding->output.axis.axis_max : binding->output.axis.axis_min;
SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)value);
} else {
SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, state);
}
break;
}
}
}
static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value)
{
int i;
Uint8 last_mask = gamecontroller->last_hat_mask[hat];
Uint8 changed_mask = (last_mask ^ value);
for (i = 0; i < gamecontroller->num_bindings; ++i) {
SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT && hat == binding->input.hat.hat) {
if ((changed_mask & binding->input.hat.hat_mask) != 0) {
if (value & binding->input.hat.hat_mask) {
if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)binding->output.axis.axis_max);
} else {
SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, SDL_PRESSED);
}
} else {
ResetOutput(gamecontroller, binding);
}
}
}
}
gamecontroller->last_hat_mask[hat] = value;
}
/* /*
* Event filter to fire controller events from joystick ones * Event filter to fire controller events from joystick ones
*/ */
@ -153,32 +270,10 @@ static int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
switch(event->type) { switch(event->type) {
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
{ {
SDL_GameController *controllerlist; SDL_GameController *controllerlist = SDL_gamecontrollers;
if (event->jaxis.axis >= k_nMaxReverseEntries)
{
SDL_SetError("SDL_GameControllerEventWatcher: Axis index %d too large, ignoring motion", (int)event->jaxis.axis);
break;
}
controllerlist = SDL_gamecontrollers;
while (controllerlist) { while (controllerlist) {
if (controllerlist->joystick->instance_id == event->jaxis.which) { if (controllerlist->joystick->instance_id == event->jaxis.which) {
if (controllerlist->mapping.raxes[event->jaxis.axis] >= 0) /* simple axis to axis, send it through */ { HandleJoystickAxis(controllerlist, event->jaxis.axis, event->jaxis.value);
SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis];
Sint16 value = event->jaxis.value;
switch (axis) {
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
value = value / 2 + 16384;
break;
default:
break;
}
SDL_PrivateGameControllerAxis(controllerlist, axis, value);
} else if (controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0) { /* simulate an axis as a button */
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED);
}
break; break;
} }
controllerlist = controllerlist->next; controllerlist = controllerlist->next;
@ -188,22 +283,10 @@ static int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
{ {
SDL_GameController *controllerlist; SDL_GameController *controllerlist = SDL_gamecontrollers;
if (event->jbutton.button >= k_nMaxReverseEntries)
{
SDL_SetError("SDL_GameControllerEventWatcher: Button index %d too large, ignoring update", (int)event->jbutton.button);
break;
}
controllerlist = SDL_gamecontrollers;
while (controllerlist) { while (controllerlist) {
if (controllerlist->joystick->instance_id == event->jbutton.which) { if (controllerlist->joystick->instance_id == event->jbutton.which) {
if (controllerlist->mapping.rbuttons[event->jbutton.button] >= 0) { /* simple button as button */ HandleJoystickButton(controllerlist, event->jbutton.button, event->jbutton.state);
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state);
} else if (controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0) { /* an button pretending to be an axis */
SDL_PrivateGameControllerAxis(controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0);
}
break; break;
} }
controllerlist = controllerlist->next; controllerlist = controllerlist->next;
@ -212,43 +295,10 @@ static int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
break; break;
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION:
{ {
SDL_GameController *controllerlist; SDL_GameController *controllerlist = SDL_gamecontrollers;
if (event->jhat.hat >= 4) break;
controllerlist = SDL_gamecontrollers;
while (controllerlist) { while (controllerlist) {
if (controllerlist->joystick->instance_id == event->jhat.which) { if (controllerlist->joystick->instance_id == event->jhat.which) {
Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value; HandleJoystickHat(controllerlist, event->jhat.hat, event->jhat.value);
/* Get list of removed bits (button release) */
Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame;
/* the hat idx in the high nibble */
int bHighHat = event->jhat.hat << 4;
if (bChanged & SDL_HAT_DOWN)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED);
if (bChanged & SDL_HAT_UP)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED);
if (bChanged & SDL_HAT_LEFT)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED);
if (bChanged & SDL_HAT_RIGHT)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED);
/* Get list of added bits (button press) */
bChanged = event->jhat.value ^ bSame;
if (bChanged & SDL_HAT_DOWN)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED);
if (bChanged & SDL_HAT_UP)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED);
if (bChanged & SDL_HAT_LEFT)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED);
if (bChanged & SDL_HAT_RIGHT)
SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED);
/* update our state cache */
controllerlist->hatState[event->jhat.hat] = event->jhat.value;
break; break;
} }
controllerlist = controllerlist->next; controllerlist = controllerlist->next;
@ -321,8 +371,14 @@ static const char* map_StringForControllerAxis[] = {
SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString) SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
{ {
int entry; int entry;
if (!pchString || !pchString[0])
if (pchString && (*pchString == '+' || *pchString == '-')) {
++pchString;
}
if (!pchString || !pchString[0]) {
return SDL_CONTROLLER_AXIS_INVALID; return SDL_CONTROLLER_AXIS_INVALID;
}
for (entry = 0; map_StringForControllerAxis[entry]; ++entry) { for (entry = 0; map_StringForControllerAxis[entry]; ++entry) {
if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry])) if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry]))
@ -391,63 +447,95 @@ const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
/* /*
* given a controller button name and a joystick name update our mapping structure with it * given a controller button name and a joystick name update our mapping structure with it
*/ */
static void SDL_PrivateGameControllerParseButton(const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping) static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton)
{ {
int iSDLButton = 0; SDL_ExtendedGameControllerBind bind;
SDL_GameControllerButton button; SDL_GameControllerButton button;
SDL_GameControllerAxis axis; SDL_GameControllerAxis axis;
button = SDL_GameControllerGetButtonFromString(szGameButton); SDL_bool invert_input = SDL_FALSE;
char half_axis_input = 0;
char half_axis_output = 0;
if (*szGameButton == '+' || *szGameButton == '-') {
half_axis_output = *szGameButton++;
}
axis = SDL_GameControllerGetAxisFromString(szGameButton); axis = SDL_GameControllerGetAxisFromString(szGameButton);
iSDLButton = SDL_atoi(&szJoystickButton[1]); button = SDL_GameControllerGetButtonFromString(szGameButton);
if (axis != SDL_CONTROLLER_AXIS_INVALID) {
if (szJoystickButton[0] == 'a') { bind.outputType = SDL_CONTROLLER_BINDTYPE_AXIS;
if (iSDLButton >= k_nMaxReverseEntries) { bind.output.axis.axis = axis;
SDL_SetError("Axis index too large: %d", iSDLButton); if (axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
return; bind.output.axis.axis_min = 0;
} bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
if (axis != SDL_CONTROLLER_AXIS_INVALID) {
pMapping->axes[axis] = iSDLButton;
pMapping->raxes[iSDLButton] = axis;
} else if (button != SDL_CONTROLLER_BUTTON_INVALID) {
pMapping->axesasbutton[button] = iSDLButton;
pMapping->raxesasbutton[iSDLButton] = button;
} else { } else {
SDL_assert(!"How did we get here?"); if (half_axis_output == '+') {
bind.output.axis.axis_min = 0;
bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
} else if (half_axis_output == '-') {
bind.output.axis.axis_min = 0;
bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
} else {
bind.output.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
}
} }
} else if (button != SDL_CONTROLLER_BUTTON_INVALID) {
bind.outputType = SDL_CONTROLLER_BINDTYPE_BUTTON;
bind.output.button = button;
} else {
SDL_SetError("Unexpected controller element %s", szGameButton);
return;
}
} else if (szJoystickButton[0] == 'b') { if (*szJoystickButton == '+' || *szJoystickButton == '-') {
if (iSDLButton >= k_nMaxReverseEntries) { half_axis_input = *szJoystickButton++;
SDL_SetError("Button index too large: %d", iSDLButton); }
return; if (szJoystickButton[SDL_strlen(szJoystickButton) - 1] == '~') {
} invert_input = SDL_TRUE;
if (button != SDL_CONTROLLER_BUTTON_INVALID) { }
pMapping->buttons[button] = iSDLButton;
pMapping->rbuttons[iSDLButton] = button; if (szJoystickButton[0] == 'a' && SDL_isdigit(szJoystickButton[1])) {
} else if (axis != SDL_CONTROLLER_AXIS_INVALID) { bind.inputType = SDL_CONTROLLER_BINDTYPE_AXIS;
pMapping->buttonasaxis[axis] = iSDLButton; bind.input.axis.axis = SDL_atoi(&szJoystickButton[1]);
pMapping->rbuttonasaxis[iSDLButton] = axis; if (half_axis_input == '+') {
bind.input.axis.axis_min = 0;
bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
} else if (half_axis_input == '-') {
bind.input.axis.axis_min = 0;
bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MIN;
} else { } else {
SDL_assert(!"How did we get here?"); bind.input.axis.axis_min = SDL_JOYSTICK_AXIS_MIN;
bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX;
} }
} else if (szJoystickButton[0] == 'h') { if (invert_input) {
int tmp = bind.input.axis.axis_min;
bind.input.axis.axis_min = bind.input.axis.axis_max;
bind.input.axis.axis_max = tmp;
}
} else if (szJoystickButton[0] == 'b' && SDL_isdigit(szJoystickButton[1])) {
bind.inputType = SDL_CONTROLLER_BINDTYPE_BUTTON;
bind.input.button = SDL_atoi(&szJoystickButton[1]);
} else if (szJoystickButton[0] == 'h' && SDL_isdigit(szJoystickButton[1]) &&
szJoystickButton[2] == '.' && SDL_isdigit(szJoystickButton[3])) {
int hat = SDL_atoi(&szJoystickButton[1]); int hat = SDL_atoi(&szJoystickButton[1]);
int mask = SDL_atoi(&szJoystickButton[3]); int mask = SDL_atoi(&szJoystickButton[3]);
if (hat >= 4) { bind.inputType = SDL_CONTROLLER_BINDTYPE_HAT;
SDL_SetError("Hat index too large: %d", iSDLButton); bind.input.hat.hat = hat;
} bind.input.hat.hat_mask = mask;
} else {
if (button != SDL_CONTROLLER_BUTTON_INVALID) { SDL_SetError("Unexpected joystick element: %s", szJoystickButton);
int ridx; return;
pMapping->hatasbutton[button].hat = hat;
pMapping->hatasbutton[button].mask = mask;
ridx = (hat << 4) | mask;
pMapping->rhatasbutton[ridx] = button;
} else if (axis != SDL_CONTROLLER_AXIS_INVALID) {
SDL_assert(!"Support hat as axis");
} else {
SDL_assert(!"How did we get here?");
}
} }
++gamecontroller->num_bindings;
gamecontroller->bindings = (SDL_ExtendedGameControllerBind *)SDL_realloc(gamecontroller->bindings, gamecontroller->num_bindings * sizeof(*gamecontroller->bindings));
if (!gamecontroller->bindings) {
gamecontroller->num_bindings = 0;
SDL_OutOfMemory();
return;
}
gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind;
} }
@ -455,7 +543,7 @@ static void SDL_PrivateGameControllerParseButton(const char *szGameButton, const
* given a controller mapping string update our mapping object * given a controller mapping string update our mapping object
*/ */
static void static void
SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMapping *pMapping, const char *pchString) SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString)
{ {
char szGameButton[20]; char szGameButton[20];
char szJoystickButton[20]; char szJoystickButton[20];
@ -463,8 +551,8 @@ SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMappi
int i = 0; int i = 0;
const char *pchPos = pchString; const char *pchPos = pchString;
SDL_memset(szGameButton, 0x0, sizeof(szGameButton)); SDL_zero(szGameButton);
SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton)); SDL_zero(szJoystickButton);
while (pchPos && *pchPos) { while (pchPos && *pchPos) {
if (*pchPos == ':') { if (*pchPos == ':') {
@ -475,9 +563,9 @@ SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMappi
} else if (*pchPos == ',') { } else if (*pchPos == ',') {
i = 0; i = 0;
bGameButton = SDL_TRUE; bGameButton = SDL_TRUE;
SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping); SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
SDL_memset(szGameButton, 0x0, sizeof(szGameButton)); SDL_zero(szGameButton);
SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton)); SDL_zero(szJoystickButton);
} else if (bGameButton) { } else if (bGameButton) {
if (i >= sizeof(szGameButton)) { if (i >= sizeof(szGameButton)) {
@ -497,43 +585,37 @@ SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMappi
pchPos++; pchPos++;
} }
SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping); SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton);
} }
/* /*
* Make a new button mapping struct * Make a new button mapping struct
*/ */
static void SDL_PrivateLoadButtonMapping(struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping) static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
{ {
int j; int i;
pMapping->guid = guid; gamecontroller->guid = guid;
pMapping->name = pchName; gamecontroller->name = pchName;
gamecontroller->num_bindings = 0;
SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes * sizeof(*gamecontroller->last_match_axis));
/* set all the button mappings to non defaults */ SDL_PrivateGameControllerParseControllerConfigString(gamecontroller, pchMapping);
for (j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++) {
pMapping->axes[j] = -1; /* Set the zero point for triggers */
pMapping->buttonasaxis[j] = -1; for (i = 0; i < gamecontroller->num_bindings; ++i) {
SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS &&
(binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
if (binding->input.axis.axis < gamecontroller->joystick->naxes) {
gamecontroller->joystick->axes[binding->input.axis.axis].value =
gamecontroller->joystick->axes[binding->input.axis.axis].zero = (Sint16)binding->input.axis.axis_min;
}
}
} }
for (j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++) {
pMapping->buttons[j] = -1;
pMapping->axesasbutton[j] = -1;
pMapping->hatasbutton[j].hat = -1;
}
for (j = 0; j < k_nMaxReverseEntries; j++) {
pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
}
for (j = 0; j < k_nMaxHatEntries; j++) {
pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
}
SDL_PrivateGameControllerParseControllerConfigString(pMapping, pchMapping);
} }
@ -628,14 +710,14 @@ static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pContro
{ {
SDL_GameController *gamecontrollerlist = SDL_gamecontrollers; SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
while (gamecontrollerlist) { while (gamecontrollerlist) {
if (!SDL_memcmp(&gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) { if (!SDL_memcmp(&gamecontrollerlist->guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) {
SDL_Event event; SDL_Event event;
event.type = SDL_CONTROLLERDEVICEREMAPPED; event.type = SDL_CONTROLLERDEVICEREMAPPED;
event.cdevice.which = gamecontrollerlist->joystick->instance_id; event.cdevice.which = gamecontrollerlist->joystick->instance_id;
SDL_PushEvent(&event); SDL_PushEvent(&event);
/* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */ /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping); SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
} }
gamecontrollerlist = gamecontrollerlist->next; gamecontrollerlist = gamecontrollerlist->next;
@ -972,7 +1054,7 @@ SDL_GameControllerMapping(SDL_GameController * gamecontroller)
return NULL; return NULL;
} }
return SDL_GameControllerMappingForGUID(gamecontroller->mapping.guid); return SDL_GameControllerMappingForGUID(gamecontroller->guid);
} }
static void static void
@ -1046,7 +1128,7 @@ SDL_GameControllerInit(void)
const char * const char *
SDL_GameControllerNameForIndex(int device_index) SDL_GameControllerNameForIndex(int device_index)
{ {
ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
if (pSupportedController) { if (pSupportedController) {
return pSupportedController->name; return pSupportedController->name;
} }
@ -1060,11 +1142,10 @@ SDL_GameControllerNameForIndex(int device_index)
SDL_bool SDL_bool
SDL_IsGameController(int device_index) SDL_IsGameController(int device_index)
{ {
ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
if (pSupportedController) { if (pSupportedController) {
return SDL_TRUE; return SDL_TRUE;
} }
return SDL_FALSE; return SDL_FALSE;
} }
@ -1110,14 +1191,13 @@ SDL_GameControllerOpen(int device_index)
} }
/* Create and initialize the joystick */ /* Create and initialize the joystick */
gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller)); gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
if (gamecontroller == NULL) { if (gamecontroller == NULL) {
SDL_OutOfMemory(); SDL_OutOfMemory();
SDL_UnlockJoystickList(); SDL_UnlockJoystickList();
return NULL; return NULL;
} }
SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
gamecontroller->joystick = SDL_JoystickOpen(device_index); gamecontroller->joystick = SDL_JoystickOpen(device_index);
if (!gamecontroller->joystick) { if (!gamecontroller->joystick) {
SDL_free(gamecontroller); SDL_free(gamecontroller);
@ -1125,21 +1205,10 @@ SDL_GameControllerOpen(int device_index)
return NULL; return NULL;
} }
SDL_PrivateLoadButtonMapping(&gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping); gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis));
gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask));
/* The triggers are mapped from -32768 to 32767, where -32768 is the 'unpressed' value */ SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
{
int leftTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT];
int rightTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT];
if (leftTriggerMapping >= 0) {
gamecontroller->joystick->axes[leftTriggerMapping].value =
gamecontroller->joystick->axes[leftTriggerMapping].zero = (Sint16)-32768;
}
if (rightTriggerMapping >= 0) {
gamecontroller->joystick->axes[rightTriggerMapping].value =
gamecontroller->joystick->axes[rightTriggerMapping].zero = (Sint16)-32768;
}
}
/* Add joystick to list */ /* Add joystick to list */
++gamecontroller->ref_count; ++gamecontroller->ref_count;
@ -1162,65 +1231,102 @@ SDL_GameControllerUpdate(void)
SDL_JoystickUpdate(); SDL_JoystickUpdate();
} }
/* /*
* Get the current state of an axis control on a controller * Get the current state of an axis control on a controller
*/ */
Sint16 Sint16
SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
{ {
int i;
if (!gamecontroller) if (!gamecontroller)
return 0; return 0;
if (gamecontroller->mapping.axes[axis] >= 0) { for (i = 0; i < gamecontroller->num_bindings; ++i) {
Sint16 value = (SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axes[axis])); SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
switch (axis) { if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: int value = 0;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: SDL_bool valid_input_range;
/* Shift it to be 0 - 32767 */ SDL_bool valid_output_range;
value = value / 2 + 16384;
default: if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
break; value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
} else {
valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
}
if (valid_input_range) {
if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
}
}
} else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
if (value == SDL_PRESSED) {
value = binding->output.axis.axis_max;
}
} else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
if (hat_mask & binding->input.hat.hat_mask) {
value = binding->output.axis.axis_max;
}
}
if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
} else {
valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
}
// If the value is zero, there might be another binding that makes it non-zero
if (value != 0 && valid_output_range) {
return (Sint16)value;
}
} }
return value;
} else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) {
Uint8 value;
value = SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis]);
if (value > 0)
return 32767;
return 0;
} }
return 0; return 0;
} }
/* /*
* Get the current state of a button on a controller * Get the current state of a button on a controller
*/ */
Uint8 Uint8
SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
{ {
int i;
if (!gamecontroller) if (!gamecontroller)
return 0; return 0;
if (gamecontroller->mapping.buttons[button] >= 0) { for (i = 0; i < gamecontroller->num_bindings; ++i) {
return (SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttons[button])); SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
} else if (gamecontroller->mapping.axesasbutton[button] >= 0) { if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
Sint16 value; if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
value = SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button]); SDL_bool valid_input_range;
if (ABS(value) > 32768/2)
return 1;
return 0;
} else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) {
Uint8 value;
value = SDL_JoystickGetHat(gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat);
if (value & gamecontroller->mapping.hatasbutton[button].mask) int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
return 1; int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
return 0; if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
if (valid_input_range) {
return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
}
} else {
valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
if (valid_input_range) {
return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
}
}
} else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
} else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
}
}
} }
return SDL_RELEASED;
return 0;
} }
const char * const char *
@ -1229,7 +1335,7 @@ SDL_GameControllerName(SDL_GameController * gamecontroller)
if (!gamecontroller) if (!gamecontroller)
return NULL; return NULL;
return gamecontroller->mapping.name; return gamecontroller->name;
} }
Uint16 Uint16
@ -1302,20 +1408,29 @@ SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
*/ */
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
{ {
int i;
SDL_GameControllerButtonBind bind; SDL_GameControllerButtonBind bind;
SDL_memset(&bind, 0x0, sizeof(bind)); SDL_zero(bind);
if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID) if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
return bind; return bind;
if (gamecontroller->mapping.axes[axis] >= 0) { for (i = 0; i < gamecontroller->num_bindings; ++i) {
bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
bind.value.button = gamecontroller->mapping.axes[axis]; if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
} else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) { bind.bindType = binding->inputType;
bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
bind.value.button = gamecontroller->mapping.buttonasaxis[axis]; /* FIXME: There might be multiple axes bound now that we have axis ranges... */
bind.value.axis = binding->input.axis.axis;
} else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
bind.value.button = binding->input.button;
} else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
bind.value.hat.hat = binding->input.hat.hat;
bind.value.hat.hat_mask = binding->input.hat.hat_mask;
}
break;
}
} }
return bind; return bind;
} }
@ -1325,24 +1440,28 @@ SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController
*/ */
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
{ {
int i;
SDL_GameControllerButtonBind bind; SDL_GameControllerButtonBind bind;
SDL_memset(&bind, 0x0, sizeof(bind)); SDL_zero(bind);
if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID) if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
return bind; return bind;
if (gamecontroller->mapping.buttons[button] >= 0) { for (i = 0; i < gamecontroller->num_bindings; ++i) {
bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
bind.value.button = gamecontroller->mapping.buttons[button]; if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
} else if (gamecontroller->mapping.axesasbutton[button] >= 0) { bind.bindType = binding->inputType;
bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
bind.value.axis = gamecontroller->mapping.axesasbutton[button]; bind.value.axis = binding->input.axis.axis;
} else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) { } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT; bind.value.button = binding->input.button;
bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat; } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask; bind.value.hat.hat = binding->input.hat.hat;
bind.value.hat.hat_mask = binding->input.hat.hat_mask;
}
break;
}
} }
return bind; return bind;
} }
@ -1381,6 +1500,9 @@ SDL_GameControllerClose(SDL_GameController * gamecontroller)
gamecontrollerlist = gamecontrollerlist->next; gamecontrollerlist = gamecontrollerlist->next;
} }
SDL_free(gamecontroller->bindings);
SDL_free(gamecontroller->last_match_axis);
SDL_free(gamecontroller->last_hat_mask);
SDL_free(gamecontroller); SDL_free(gamecontroller);
SDL_UnlockJoystickList(); SDL_UnlockJoystickList();
@ -1417,7 +1539,7 @@ SDL_GameControllerQuit(void)
/* /*
* Event filter to transform joystick events into appropriate game controller ones * Event filter to transform joystick events into appropriate game controller ones
*/ */
int static int
SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value) SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
{ {
int posted; int posted;
@ -1441,7 +1563,7 @@ SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameContr
/* /*
* Event filter to transform joystick events into appropriate game controller ones * Event filter to transform joystick events into appropriate game controller ones
*/ */
int static int
SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state) SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
{ {
int posted; int posted;

View File

@ -33,9 +33,7 @@
#endif #endif
#define INPUT_QSIZE 32 /* Buffer up to 32 input messages */ #define INPUT_QSIZE 32 /* Buffer up to 32 input messages */
#define AXIS_MIN -32768 /* minimum value for axis coordinate */ #define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100) /* 1% motion */
#define AXIS_MAX 32767 /* maximum value for axis coordinate */
#define JOY_AXIS_THRESHOLD (((AXIS_MAX)-(AXIS_MIN))/100) /* 1% motion */
/* external variables referenced. */ /* external variables referenced. */
extern HWND SDL_HelperWindow; extern HWND SDL_HelperWindow;
@ -481,8 +479,8 @@ EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
diprg.diph.dwHeaderSize = sizeof(diprg.diph); diprg.diph.dwHeaderSize = sizeof(diprg.diph);
diprg.diph.dwObj = dev->dwType; diprg.diph.dwObj = dev->dwType;
diprg.diph.dwHow = DIPH_BYID; diprg.diph.dwHow = DIPH_BYID;
diprg.lMin = AXIS_MIN; diprg.lMin = SDL_JOYSTICK_AXIS_MIN;
diprg.lMax = AXIS_MAX; diprg.lMax = SDL_JOYSTICK_AXIS_MAX;
result = result =
IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,

View File

@ -41,10 +41,8 @@
#define MAX_JOYSTICKS 16 #define MAX_JOYSTICKS 16
#define MAX_AXES 6 /* each joystick can have up to 6 axes */ #define MAX_AXES 6 /* each joystick can have up to 6 axes */
#define MAX_BUTTONS 32 /* and 32 buttons */ #define MAX_BUTTONS 32 /* and 32 buttons */
#define AXIS_MIN -32768 /* minimum value for axis coordinate */
#define AXIS_MAX 32767 /* maximum value for axis coordinate */
/* limit axis to 256 possible positions to filter out noise */ /* limit axis to 256 possible positions to filter out noise */
#define JOY_AXIS_THRESHOLD (((AXIS_MAX)-(AXIS_MIN))/256) #define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/256)
#define JOY_BUTTON_FLAG(n) (1<<n) #define JOY_BUTTON_FLAG(n) (1<<n)
@ -253,9 +251,9 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
joystick->hwdata->id = SYS_JoystickID[index]; joystick->hwdata->id = SYS_JoystickID[index];
for (i = 0; i < MAX_AXES; ++i) { for (i = 0; i < MAX_AXES; ++i) {
if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) { if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
joystick->hwdata->transaxis[i].offset = AXIS_MIN - axis_min[i]; joystick->hwdata->transaxis[i].offset = SDL_JOYSTICK_AXIS_MIN - axis_min[i];
joystick->hwdata->transaxis[i].scale = joystick->hwdata->transaxis[i].scale =
(float) (AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]); (float) (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) / (axis_max[i] - axis_min[i]);
} else { } else {
joystick->hwdata->transaxis[i].offset = 0; joystick->hwdata->transaxis[i].offset = 0;
joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */ joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -32,7 +32,22 @@
#define MARKER_BUTTON 1 #define MARKER_BUTTON 1
#define MARKER_AXIS 2 #define MARKER_AXIS 2
#define BINDING_COUNT (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_MAX) enum
{
SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
SDL_CONTROLLER_BINDING_AXIS_MAX,
};
#define BINDING_COUNT (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_MAX)
static struct static struct
{ {
@ -56,12 +71,16 @@ static struct
{ 154, 249, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_DOWN */ { 154, 249, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_DOWN */
{ 116, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_LEFT */ { 116, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_LEFT */
{ 186, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_RIGHT */ { 186, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_RIGHT */
{ 75, 154, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_AXIS_LEFTX */ { 74, 153, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE */
{ 75, 154, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_AXIS_LEFTY */ { 74, 153, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE */
{ 305, 230, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_AXIS_RIGHTX */ { 74, 153, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE */
{ 305, 230, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_AXIS_RIGHTY */ { 74, 153, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE */
{ 91, 0, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_AXIS_TRIGGERLEFT */ { 306, 231, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE */
{ 375, 0, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_AXIS_TRIGGERRIGHT */ { 306, 231, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE */
{ 306, 231, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE */
{ 306, 231, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE */
{ 91, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT */
{ 375, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT */
}; };
static int s_arrBindingOrder[BINDING_COUNT] = { static int s_arrBindingOrder[BINDING_COUNT] = {
@ -69,16 +88,20 @@ static int s_arrBindingOrder[BINDING_COUNT] = {
SDL_CONTROLLER_BUTTON_B, SDL_CONTROLLER_BUTTON_B,
SDL_CONTROLLER_BUTTON_Y, SDL_CONTROLLER_BUTTON_Y,
SDL_CONTROLLER_BUTTON_X, SDL_CONTROLLER_BUTTON_X,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_LEFTY, SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
SDL_CONTROLLER_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_LEFTSTICK,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_RIGHTY, SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
SDL_CONTROLLER_BUTTON_RIGHTSTICK, SDL_CONTROLLER_BUTTON_RIGHTSTICK,
SDL_CONTROLLER_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
SDL_CONTROLLER_BUTTON_DPAD_UP, SDL_CONTROLLER_BUTTON_DPAD_UP,
SDL_CONTROLLER_BUTTON_DPAD_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
SDL_CONTROLLER_BUTTON_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN,
@ -88,7 +111,40 @@ static int s_arrBindingOrder[BINDING_COUNT] = {
SDL_CONTROLLER_BUTTON_START, SDL_CONTROLLER_BUTTON_START,
}; };
static SDL_GameControllerButtonBind s_arrBindings[BINDING_COUNT]; typedef struct
{
SDL_GameControllerBindType bindType;
union
{
int button;
struct {
int axis;
int axis_min;
int axis_max;
} axis;
struct {
int hat;
int hat_mask;
} hat;
} value;
} SDL_GameControllerExtendedBind;
static SDL_GameControllerExtendedBind s_arrBindings[BINDING_COUNT];
typedef struct
{
SDL_bool m_bMoving;
int m_nStartingValue;
int m_nFarthestValue;
} AxisState;
static int s_nNumAxes;
static AxisState *s_arrAxisState;
static int s_iCurrentBinding; static int s_iCurrentBinding;
static Uint32 s_unPendingAdvanceTime; static Uint32 s_unPendingAdvanceTime;
static SDL_bool s_bBindingComplete; static SDL_bool s_bBindingComplete;
@ -110,23 +166,6 @@ LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent)
if (transparent) { if (transparent) {
if (temp->format->palette) { if (temp->format->palette) {
SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels); 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;
}
} }
} }
@ -143,9 +182,22 @@ LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent)
return texture; return texture;
} }
void SetCurrentBinding(int iBinding) static int
StandardizeAxisValue(int nValue)
{ {
SDL_GameControllerButtonBind *pBinding; if (nValue > SDL_JOYSTICK_AXIS_MAX/2) {
return SDL_JOYSTICK_AXIS_MAX;
} else if (nValue < SDL_JOYSTICK_AXIS_MIN/2) {
return SDL_JOYSTICK_AXIS_MIN;
} else {
return 0;
}
}
static void
SetCurrentBinding(int iBinding)
{
SDL_GameControllerExtendedBind *pBinding;
if (iBinding < 0) { if (iBinding < 0) {
return; return;
@ -161,14 +213,15 @@ void SetCurrentBinding(int iBinding)
pBinding = &s_arrBindings[s_arrBindingOrder[s_iCurrentBinding]]; pBinding = &s_arrBindings[s_arrBindingOrder[s_iCurrentBinding]];
SDL_zerop(pBinding); SDL_zerop(pBinding);
SDL_memset(s_arrAxisState, 0, s_nNumAxes*sizeof(*s_arrAxisState));
s_unPendingAdvanceTime = 0; s_unPendingAdvanceTime = 0;
} }
static void static void
ConfigureBinding(const SDL_GameControllerButtonBind *pBinding) ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding)
{ {
SDL_GameControllerButtonBind *pCurrent; SDL_GameControllerExtendedBind *pCurrent;
int iIndex; int iIndex;
int iCurrentElement = s_arrBindingOrder[s_iCurrentBinding]; int iCurrentElement = s_arrBindingOrder[s_iCurrentBinding];
@ -221,6 +274,24 @@ ConfigureBinding(const SDL_GameControllerButtonBind *pBinding)
s_unPendingAdvanceTime = SDL_GetTicks(); s_unPendingAdvanceTime = SDL_GetTicks();
} }
static SDL_bool
BMergeAxisBindings(int iIndex)
{
SDL_GameControllerExtendedBind *pBindingA = &s_arrBindings[iIndex];
SDL_GameControllerExtendedBind *pBindingB = &s_arrBindings[iIndex+1];
if (pBindingA->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
pBindingB->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
pBindingA->value.axis.axis == pBindingB->value.axis.axis) {
if (pBindingA->value.axis.axis_min == pBindingB->value.axis.axis_min) {
pBindingA->value.axis.axis_min = pBindingA->value.axis.axis_max;
pBindingA->value.axis.axis_max = pBindingB->value.axis.axis_max;
pBindingB->bindType = SDL_CONTROLLER_BINDTYPE_NONE;
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static void static void
WatchJoystick(SDL_Joystick * joystick) WatchJoystick(SDL_Joystick * joystick)
{ {
@ -279,6 +350,9 @@ WatchJoystick(SDL_Joystick * joystick)
nJoystickID = SDL_JoystickInstanceID(joystick); nJoystickID = SDL_JoystickInstanceID(joystick);
s_nNumAxes = SDL_JoystickNumAxes(joystick);
s_arrAxisState = SDL_calloc(s_nNumAxes, sizeof(*s_arrAxisState));
/* Loop, getting joystick events! */ /* Loop, getting joystick events! */
while (!done && !s_bBindingComplete) { while (!done && !s_bBindingComplete) {
int iElement = s_arrBindingOrder[s_iCurrentBinding]; int iElement = s_arrBindingOrder[s_iCurrentBinding];
@ -326,26 +400,35 @@ WatchJoystick(SDL_Joystick * joystick)
break; break;
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
if (event.jaxis.which == nJoystickID) { if (event.jaxis.which == nJoystickID) {
uint32_t unAxisMask = (1 << event.jaxis.axis); AxisState *pAxisState = &s_arrAxisState[event.jaxis.axis];
SDL_bool bDeflected = (event.jaxis.value <= -20000 || event.jaxis.value >= 20000); int nValue = event.jaxis.value;
if (bDeflected && !(unDeflectedAxes & unAxisMask)) { int nCurrentDistance, nFarthestDistance;
SDL_GameControllerButtonBind binding; if (!pAxisState->m_bMoving) {
pAxisState->m_bMoving = SDL_TRUE;
pAxisState->m_nStartingValue = nValue;
pAxisState->m_nFarthestValue = nValue;
}
nCurrentDistance = SDL_abs(nValue - pAxisState->m_nStartingValue);
nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
if (nCurrentDistance > nFarthestDistance) {
pAxisState->m_nFarthestValue = nValue;
}
if (nCurrentDistance < 10000 && nFarthestDistance > 20000) {
/* We've gone out and back, let's bind this axis */
SDL_GameControllerExtendedBind binding;
SDL_zero(binding); SDL_zero(binding);
binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
binding.value.axis = event.jaxis.axis; binding.value.axis.axis = event.jaxis.axis;
binding.value.axis.axis_min = StandardizeAxisValue(pAxisState->m_nStartingValue);
binding.value.axis.axis_max = StandardizeAxisValue(pAxisState->m_nFarthestValue);
ConfigureBinding(&binding); ConfigureBinding(&binding);
} }
if (bDeflected) {
unDeflectedAxes |= unAxisMask;
} else {
unDeflectedAxes &= ~unAxisMask;
}
} }
break; break;
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION:
if (event.jhat.which == nJoystickID) { if (event.jhat.which == nJoystickID) {
if (event.jhat.value != SDL_HAT_CENTERED) { if (event.jhat.value != SDL_HAT_CENTERED) {
SDL_GameControllerButtonBind binding; SDL_GameControllerExtendedBind binding;
SDL_zero(binding); SDL_zero(binding);
binding.bindType = SDL_CONTROLLER_BINDTYPE_HAT; binding.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
binding.value.hat.hat = event.jhat.hat; binding.value.hat.hat = event.jhat.hat;
@ -358,7 +441,7 @@ WatchJoystick(SDL_Joystick * joystick)
break; break;
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
if (event.jbutton.which == nJoystickID) { if (event.jbutton.which == nJoystickID) {
SDL_GameControllerButtonBind binding; SDL_GameControllerExtendedBind binding;
SDL_zero(binding); SDL_zero(binding);
binding.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; binding.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
binding.value.button = event.jbutton.button; binding.value.button = event.jbutton.button;
@ -430,7 +513,7 @@ WatchJoystick(SDL_Joystick * joystick)
SDL_strlcat(mapping, ",", SDL_arraysize(mapping)); SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) { for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
SDL_GameControllerButtonBind *pBinding = &s_arrBindings[iIndex]; SDL_GameControllerExtendedBind *pBinding = &s_arrBindings[iIndex];
if (pBinding->bindType == SDL_CONTROLLER_BINDTYPE_NONE) { if (pBinding->bindType == SDL_CONTROLLER_BINDTYPE_NONE) {
continue; continue;
} }
@ -439,8 +522,56 @@ WatchJoystick(SDL_Joystick * joystick)
SDL_GameControllerButton eButton = (SDL_GameControllerButton)iIndex; SDL_GameControllerButton eButton = (SDL_GameControllerButton)iIndex;
SDL_strlcat(mapping, SDL_GameControllerGetStringForButton(eButton), SDL_arraysize(mapping)); SDL_strlcat(mapping, SDL_GameControllerGetStringForButton(eButton), SDL_arraysize(mapping));
} else { } else {
SDL_GameControllerAxis eAxis = (SDL_GameControllerAxis)(iIndex - SDL_CONTROLLER_BUTTON_MAX); const char *pszAxisName;
SDL_strlcat(mapping, SDL_GameControllerGetStringForAxis(eAxis), SDL_arraysize(mapping)); switch (iIndex - SDL_CONTROLLER_BUTTON_MAX) {
case SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT:
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
break;
case SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT:
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
break;
}
SDL_strlcat(mapping, pszAxisName, SDL_arraysize(mapping));
} }
SDL_strlcat(mapping, ":", SDL_arraysize(mapping)); SDL_strlcat(mapping, ":", SDL_arraysize(mapping));
@ -450,7 +581,19 @@ WatchJoystick(SDL_Joystick * joystick)
SDL_snprintf(pszElement, sizeof(pszElement), "b%d", pBinding->value.button); SDL_snprintf(pszElement, sizeof(pszElement), "b%d", pBinding->value.button);
break; break;
case SDL_CONTROLLER_BINDTYPE_AXIS: case SDL_CONTROLLER_BINDTYPE_AXIS:
SDL_snprintf(pszElement, sizeof(pszElement), "a%d", pBinding->value.axis); if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MIN) {
/* The negative half axis */
SDL_snprintf(pszElement, sizeof(pszElement), "-a%d", pBinding->value.axis.axis);
} else if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MAX) {
/* The positive half axis */
SDL_snprintf(pszElement, sizeof(pszElement), "+a%d", pBinding->value.axis.axis);
} else {
SDL_snprintf(pszElement, sizeof(pszElement), "a%d", pBinding->value.axis.axis);
if (pBinding->value.axis.axis_min > pBinding->value.axis.axis_max) {
/* Invert the axis */
SDL_strlcat(pszElement, "~", SDL_arraysize(pszElement));
}
}
break; break;
case SDL_CONTROLLER_BINDTYPE_HAT: case SDL_CONTROLLER_BINDTYPE_HAT:
SDL_snprintf(pszElement, sizeof(pszElement), "h%d.%d", pBinding->value.hat.hat, pBinding->value.hat.hat_mask); SDL_snprintf(pszElement, sizeof(pszElement), "h%d.%d", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
@ -467,6 +610,9 @@ WatchJoystick(SDL_Joystick * joystick)
/* Print to stdout as well so the user can cat the output somewhere */ /* Print to stdout as well so the user can cat the output somewhere */
printf("%s\n", mapping); printf("%s\n", mapping);
} }
SDL_free(s_arrAxisState);
s_arrAxisState = NULL;
SDL_DestroyRenderer(screen); SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);

View File

@ -53,12 +53,12 @@ static const struct { int x; int y; } button_positions[] = {
/* This is indexed by SDL_GameControllerAxis. */ /* This is indexed by SDL_GameControllerAxis. */
static const struct { int x; int y; double angle; } axis_positions[] = { static const struct { int x; int y; double angle; } axis_positions[] = {
{75, 154, 0.0}, /* LEFTX */ {74, 153, 270.0}, /* LEFTX */
{75, 154, 90.0}, /* LEFTY */ {74, 153, 0.0}, /* LEFTY */
{305, 230, 0.0}, /* RIGHTX */ {306, 231, 270.0}, /* RIGHTX */
{305, 230, 90.0}, /* RIGHTY */ {306, 231, 0.0}, /* RIGHTY */
{91, 0, 90.0}, /* TRIGGERLEFT */ {91, -20, 0.0}, /* TRIGGERLEFT */
{375, 0, 90.0}, /* TRIGGERRIGHT */ {375, -20, 0.0}, /* TRIGGERRIGHT */
}; };
SDL_Renderer *screen = NULL; SDL_Renderer *screen = NULL;
@ -80,10 +80,6 @@ LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent)
if (transparent) { if (transparent) {
if (temp->format->BytesPerPixel == 1) { if (temp->format->BytesPerPixel == 1) {
SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *)temp->pixels); 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);
} }
} }
@ -112,6 +108,13 @@ loop(void *arg)
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_CONTROLLERAXISMOTION:
SDL_Log("Controller axis %s changed to %d\n", SDL_GameControllerGetStringForAxis(event.caxis.axis), event.caxis.value);
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
SDL_Log("Controller button %s %s\n", SDL_GameControllerGetStringForButton(event.cbutton.button), event.cbutton.state ? "pressed" : "released");
break;
case SDL_KEYDOWN: case SDL_KEYDOWN:
if (event.key.keysym.sym != SDLK_ESCAPE) { if (event.key.keysym.sym != SDLK_ESCAPE) {
break; break;