SDL: Add gamepad axis support, not currently mappable

This commit is contained in:
Jeffrey Pfau 2014-12-14 00:00:48 -08:00
parent 361237d594
commit a10a84aa89
4 changed files with 243 additions and 61 deletions

View File

@ -6,6 +6,7 @@
#include "gba-input.h" #include "gba-input.h"
#include "util/configuration.h" #include "util/configuration.h"
#include "util/table.h"
#include <inttypes.h> #include <inttypes.h>
@ -16,8 +17,86 @@
struct GBAInputMapImpl { struct GBAInputMapImpl {
int* map; int* map;
uint32_t type; uint32_t type;
struct Table axes;
}; };
static bool _getIntValue(const struct Configuration* config, const char* section, const char* key, int* value) {
const char* strValue = ConfigurationGetValue(config, section, key);
if (!strValue) {
return false;
}
char* end;
long intValue = strtol(strValue, &end, 10);
if (*end) {
return false;
}
*value = intValue;
return true;
}
static struct GBAInputMapImpl* _lookupMap(struct GBAInputMap* map, uint32_t type) {
size_t m;
struct GBAInputMapImpl* impl = 0;
for (m = 0; m < map->numMaps; ++m) {
if (map->maps[m].type == type) {
impl = &map->maps[m];
break;
}
}
return impl;
}
static const struct GBAInputMapImpl* _lookupMapConst(const struct GBAInputMap* map, uint32_t type) {
size_t m;
const struct GBAInputMapImpl* impl = 0;
for (m = 0; m < map->numMaps; ++m) {
if (map->maps[m].type == type) {
impl = &map->maps[m];
break;
}
}
return impl;
}
static struct GBAInputMapImpl* _guaranteeMap(struct GBAInputMap* map, uint32_t type) {
struct GBAInputMapImpl* impl = 0;
if (map->numMaps == 0) {
map->maps = malloc(sizeof(*map->maps));
map->numMaps = 1;
impl = &map->maps[0];
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
} else {
impl = _lookupMap(map, type);
}
if (!impl) {
size_t m;
for (m = 0; m < map->numMaps; ++m) {
if (!map->maps[m].type) {
impl = &map->maps[m];
break;
}
}
if (impl) {
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
} else {
map->maps = realloc(map->maps, sizeof(*map->maps) * map->numMaps * 2);
for (m = map->numMaps * 2 - 1; m > map->numMaps; --m) {
map->maps[m].type = 0;
map->maps[m].map = 0;
}
map->numMaps *= 2;
impl = &map->maps[m];
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
}
}
TableInit(&impl->axes, 2, free);
return impl;
}
static void _loadKey(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, enum GBAKey key, const char* keyName) { static void _loadKey(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, enum GBAKey key, const char* keyName) {
char sectionName[SECTION_NAME_MAX]; char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type); snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
@ -27,16 +106,48 @@ static void _loadKey(struct GBAInputMap* map, uint32_t type, const struct Config
snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName); snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
keyKey[KEY_NAME_MAX - 1] = '\0'; keyKey[KEY_NAME_MAX - 1] = '\0';
const char* value = ConfigurationGetValue(config, sectionName, keyKey); int value;
if (!value) { if (!_getIntValue(config, sectionName, keyKey, &value)) {
return; return;
} }
char* end; GBAInputBindKey(map, type, value, key);
long intValue = strtol(value, &end, 10); }
if (*end) {
static void _loadAxis(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, enum GBAKey direction, const char* axisName) {
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
sectionName[SECTION_NAME_MAX - 1] = '\0';
char axisKey[KEY_NAME_MAX];
snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName);
axisKey[KEY_NAME_MAX - 1] = '\0';
int value;
if (!_getIntValue(config, sectionName, axisKey, &value)) {
return; return;
} }
GBAInputBindKey(map, type, intValue, key);
snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", axisName);
axisKey[KEY_NAME_MAX - 1] = '\0';
int axis;
if (!_getIntValue(config, sectionName, axisKey, &axis)) {
return;
}
const struct GBAAxis* description = GBAInputQueryAxis(map, type, axis);
struct GBAAxis realDescription;
if (!description) {
realDescription = (struct GBAAxis) { direction, GBA_KEY_NONE, value, 0 };
} else {
realDescription = *description;
if (value >= realDescription.lowDirection) {
realDescription.deadHigh = value;
realDescription.highDirection = direction;
} else if (value <= realDescription.highDirection) {
realDescription.deadLow = value;
realDescription.lowDirection = direction;
}
}
GBAInputBindAxis(map, type, axis, &realDescription);
} }
static void _saveKey(const struct GBAInputMap* map, uint32_t type, struct Configuration* config, enum GBAKey key, const char* keyName) { static void _saveKey(const struct GBAInputMap* map, uint32_t type, struct Configuration* config, enum GBAKey key, const char* keyName) {
@ -63,7 +174,10 @@ void GBAInputMapInit(struct GBAInputMap* map) {
void GBAInputMapDeinit(struct GBAInputMap* map) { void GBAInputMapDeinit(struct GBAInputMap* map) {
size_t m; size_t m;
for (m = 0; m < map->numMaps; ++m) { for (m = 0; m < map->numMaps; ++m) {
free(map->maps[m].map); if (map->maps[m].type) {
free(map->maps[m].map);
TableDeinit(&map->maps[m].axes);
}
} }
free(map->maps); free(map->maps);
map->maps = 0; map->maps = 0;
@ -72,13 +186,7 @@ void GBAInputMapDeinit(struct GBAInputMap* map) {
enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key) { enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key) {
size_t m; size_t m;
const struct GBAInputMapImpl* impl = 0; const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
for (m = 0; m < map->numMaps; ++m) {
if (map->maps[m].type == type) {
impl = &map->maps[m];
break;
}
}
if (!impl || !impl->map) { if (!impl || !impl->map) {
return GBA_KEY_NONE; return GBA_KEY_NONE;
} }
@ -92,61 +200,23 @@ enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key
} }
void GBAInputBindKey(struct GBAInputMap* map, uint32_t type, int key, enum GBAKey input) { void GBAInputBindKey(struct GBAInputMap* map, uint32_t type, int key, enum GBAKey input) {
struct GBAInputMapImpl* impl = 0; struct GBAInputMapImpl* impl = _guaranteeMap(map, type);
if (map->numMaps == 0) {
map->maps = malloc(sizeof(*map->maps));
map->numMaps = 1;
impl = &map->maps[0];
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
} else {
size_t m;
for (m = 0; m < map->numMaps; ++m) {
if (map->maps[m].type == type) {
impl = &map->maps[m];
break;
}
}
}
if (!impl) {
size_t m;
for (m = 0; m < map->numMaps; ++m) {
if (!map->maps[m].type) {
impl = &map->maps[m];
break;
}
}
if (impl) {
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
} else {
map->maps = realloc(map->maps, sizeof(*map->maps) * map->numMaps * 2);
for (m = map->numMaps * 2 - 1; m > map->numMaps; --m) {
map->maps[m].type = 0;
map->maps[m].map = 0;
}
map->numMaps *= 2;
impl = &map->maps[m];
impl->type = type;
impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
}
}
impl->map[input] = key; impl->map[input] = key;
} }
void GBAInputUnbindKey(struct GBAInputMap* map, uint32_t type, enum GBAKey input) {
struct GBAInputMapImpl* impl = _lookupMap(map, type);
if (impl) {
impl->map[input] = -1;
}
}
int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAKey input) { int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAKey input) {
if (input >= GBA_KEY_MAX) { if (input >= GBA_KEY_MAX) {
return 0; return 0;
} }
size_t m; const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
const struct GBAInputMapImpl* impl = 0;
for (m = 0; m < map->numMaps; ++m) {
if (map->maps[m].type == type) {
impl = &map->maps[m];
break;
}
}
if (!impl || !impl->map) { if (!impl || !impl->map) {
return 0; return 0;
} }
@ -154,6 +224,71 @@ int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAK
return impl->map[input]; return impl->map[input];
} }
enum GBAKey GBAInputMapAxis(const struct GBAInputMap* map, uint32_t type, int axis, int value) {
const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
if (!impl) {
return GBA_KEY_NONE;
}
struct GBAAxis* description = TableLookup(&impl->axes, axis);
if (!description) {
return GBA_KEY_NONE;
}
int state = 0;
if (value < description->deadLow) {
state = -1;
} else if (value > description->deadHigh) {
state = 1;
}
if (state > 0) {
return description->highDirection;
}
if (state < 0) {
return description->lowDirection;
}
return GBA_KEY_NONE;
}
int GBAInputClearAxis(const struct GBAInputMap* map, uint32_t type, int axis, int keys) {
const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
if (!impl) {
return keys;
}
struct GBAAxis* description = TableLookup(&impl->axes, axis);
if (!description) {
return keys;
}
return keys &= ~((1 << description->highDirection) | (1 << description->lowDirection));
}
void GBAInputBindAxis(struct GBAInputMap* map, uint32_t type, int axis, const struct GBAAxis* description) {
struct GBAInputMapImpl* impl = _guaranteeMap(map, type);
struct GBAAxis* dup = malloc(sizeof(struct GBAAxis));
*dup = *description;
TableInsert(&impl->axes, axis, dup);
}
void GBAInputUnbindAxis(struct GBAInputMap* map, uint32_t type, int axis) {
struct GBAInputMapImpl* impl = _lookupMap(map, type);
if (impl) {
TableRemove(&impl->axes, axis);
}
}
void GBAInputUnbindAllAxes(struct GBAInputMap* map, uint32_t type) {
struct GBAInputMapImpl* impl = _lookupMap(map, type);
if (impl) {
TableClear(&impl->axes);
}
}
const struct GBAAxis* GBAInputQueryAxis(const struct GBAInputMap* map, uint32_t type, int axis) {
const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
if (!impl) {
return 0;
}
return TableLookup(&impl->axes, axis);
}
void GBAInputMapLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config) { void GBAInputMapLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config) {
_loadKey(map, type, config, GBA_KEY_A, "A"); _loadKey(map, type, config, GBA_KEY_A, "A");
_loadKey(map, type, config, GBA_KEY_B, "B"); _loadKey(map, type, config, GBA_KEY_B, "B");

View File

@ -15,13 +15,28 @@ struct GBAInputMap {
size_t numMaps; size_t numMaps;
}; };
struct GBAAxis {
enum GBAKey highDirection;
enum GBAKey lowDirection;
int32_t deadHigh;
int32_t deadLow;
};
void GBAInputMapInit(struct GBAInputMap*); void GBAInputMapInit(struct GBAInputMap*);
void GBAInputMapDeinit(struct GBAInputMap*); void GBAInputMapDeinit(struct GBAInputMap*);
enum GBAKey GBAInputMapKey(const struct GBAInputMap*, uint32_t type, int key); enum GBAKey GBAInputMapKey(const struct GBAInputMap*, uint32_t type, int key);
void GBAInputBindKey(struct GBAInputMap*, uint32_t type, int key, enum GBAKey input); void GBAInputBindKey(struct GBAInputMap*, uint32_t type, int key, enum GBAKey input);
void GBAInputUnbindKey(struct GBAInputMap*, uint32_t type, int key);
int GBAInputQueryBinding(const struct GBAInputMap*, uint32_t type, enum GBAKey input); int GBAInputQueryBinding(const struct GBAInputMap*, uint32_t type, enum GBAKey input);
enum GBAKey GBAInputMapAxis(const struct GBAInputMap*, uint32_t type, int axis, int value);
int GBAInputClearAxis(const struct GBAInputMap*, uint32_t type, int axis, int keys);
void GBAInputBindAxis(struct GBAInputMap*, uint32_t type, int axis, const struct GBAAxis* description);
void GBAInputUnbindAxis(struct GBAInputMap*, uint32_t type, int axis);
void GBAInputUnbindAllAxes(struct GBAInputMap*, uint32_t type);
const struct GBAAxis* GBAInputQueryAxis(const struct GBAInputMap*, uint32_t type, int axis);
void GBAInputMapLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*); void GBAInputMapLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*);
void GBAInputMapSave(const struct GBAInputMap*, uint32_t type, struct Configuration*); void GBAInputMapSave(const struct GBAInputMap*, uint32_t type, struct Configuration*);

View File

@ -100,6 +100,17 @@ int InputController::testSDLEvents() {
activeButtons |= 1 << GBA_KEY_RIGHT; activeButtons |= 1 << GBA_KEY_RIGHT;
} }
} }
int numAxes = SDL_JoystickNumAxes(joystick);
for (i = 0; i < numAxes; ++i) {
int value = SDL_JoystickGetAxis(joystick, i);
activeButtons = GBAInputClearAxis(&m_inputMap, SDL_BINDING_BUTTON, i, activeButtons);
enum GBAKey key = GBAInputMapAxis(&m_inputMap, SDL_BINDING_BUTTON, i, value);
if (key != GBA_KEY_NONE) {
activeButtons |= 1 << key;
}
}
return activeButtons; return activeButtons;
} }

View File

@ -69,6 +69,11 @@ void GBASDLInitBindings(struct GBAInputMap* inputMap) {
GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN); GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN);
GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT); GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT);
GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 5, GBA_KEY_RIGHT); GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 5, GBA_KEY_RIGHT);
struct GBAAxis description = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x4000, -0x4000 };
GBAInputBindAxis(inputMap, SDL_BINDING_BUTTON, 0, &description);
description = (struct GBAAxis) { GBA_KEY_DOWN, GBA_KEY_UP, 0x4000, -0x4000 };
GBAInputBindAxis(inputMap, SDL_BINDING_BUTTON, 1, &description);
} }
void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) { void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) {
@ -272,6 +277,18 @@ static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyH
context->activeKeys |= key; context->activeKeys |= key;
} }
static void _GBASDLHandleJoyAxis(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_JoyAxisEvent* event) {
int keys = context->activeKeys;
keys = GBAInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, keys);
enum GBAKey key = GBAInputMapAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, event->value);
if (key != GBA_KEY_NONE) {
keys |= 1 << key;
}
context->activeKeys = keys;
}
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) { static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
UNUSED(context); UNUSED(context);
@ -303,5 +320,9 @@ void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContex
break; break;
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION:
_GBASDLHandleJoyHat(context, &event->jhat); _GBASDLHandleJoyHat(context, &event->jhat);
break;
case SDL_JOYAXISMOTION:
_GBASDLHandleJoyAxis(context, sdlContext, &event->jaxis);
break;
} }
} }