mirror of https://github.com/mgba-emu/mgba.git
SDL: Add gamepad axis support, not currently mappable
This commit is contained in:
parent
361237d594
commit
a10a84aa89
|
@ -6,6 +6,7 @@
|
|||
#include "gba-input.h"
|
||||
|
||||
#include "util/configuration.h"
|
||||
#include "util/table.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
|
@ -16,8 +17,86 @@
|
|||
struct GBAInputMapImpl {
|
||||
int* map;
|
||||
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) {
|
||||
char sectionName[SECTION_NAME_MAX];
|
||||
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);
|
||||
keyKey[KEY_NAME_MAX - 1] = '\0';
|
||||
|
||||
const char* value = ConfigurationGetValue(config, sectionName, keyKey);
|
||||
if (!value) {
|
||||
int value;
|
||||
if (!_getIntValue(config, sectionName, keyKey, &value)) {
|
||||
return;
|
||||
}
|
||||
char* end;
|
||||
long intValue = strtol(value, &end, 10);
|
||||
if (*end) {
|
||||
GBAInputBindKey(map, type, value, key);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
|
@ -63,7 +174,10 @@ void GBAInputMapInit(struct GBAInputMap* map) {
|
|||
void GBAInputMapDeinit(struct GBAInputMap* map) {
|
||||
size_t 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);
|
||||
map->maps = 0;
|
||||
|
@ -72,13 +186,7 @@ void GBAInputMapDeinit(struct GBAInputMap* map) {
|
|||
|
||||
enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
|
||||
if (!impl || !impl->map) {
|
||||
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) {
|
||||
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 {
|
||||
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));
|
||||
}
|
||||
}
|
||||
struct GBAInputMapImpl* impl = _guaranteeMap(map, type);
|
||||
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) {
|
||||
if (input >= GBA_KEY_MAX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
|
||||
if (!impl || !impl->map) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -154,6 +224,71 @@ int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAK
|
|||
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) {
|
||||
_loadKey(map, type, config, GBA_KEY_A, "A");
|
||||
_loadKey(map, type, config, GBA_KEY_B, "B");
|
||||
|
|
|
@ -15,13 +15,28 @@ struct GBAInputMap {
|
|||
size_t numMaps;
|
||||
};
|
||||
|
||||
struct GBAAxis {
|
||||
enum GBAKey highDirection;
|
||||
enum GBAKey lowDirection;
|
||||
int32_t deadHigh;
|
||||
int32_t deadLow;
|
||||
};
|
||||
|
||||
void GBAInputMapInit(struct GBAInputMap*);
|
||||
void GBAInputMapDeinit(struct GBAInputMap*);
|
||||
|
||||
enum GBAKey GBAInputMapKey(const struct GBAInputMap*, uint32_t type, int key);
|
||||
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);
|
||||
|
||||
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 GBAInputMapSave(const struct GBAInputMap*, uint32_t type, struct Configuration*);
|
||||
|
||||
|
|
|
@ -100,6 +100,17 @@ int InputController::testSDLEvents() {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,11 @@ void GBASDLInitBindings(struct GBAInputMap* inputMap) {
|
|||
GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN);
|
||||
GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT);
|
||||
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) {
|
||||
|
@ -272,6 +277,18 @@ static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyH
|
|||
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)
|
||||
static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
|
||||
UNUSED(context);
|
||||
|
@ -303,5 +320,9 @@ void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContex
|
|||
break;
|
||||
case SDL_JOYHATMOTION:
|
||||
_GBASDLHandleJoyHat(context, &event->jhat);
|
||||
break;
|
||||
case SDL_JOYAXISMOTION:
|
||||
_GBASDLHandleJoyAxis(context, sdlContext, &event->jaxis);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue