SDL: Add support for configuring hats

This commit is contained in:
Vicki Pfau 2017-01-23 00:03:59 -08:00
parent 6a188289c2
commit 78526ae71a
6 changed files with 155 additions and 14 deletions

View File

@ -7,6 +7,7 @@ Features:
- Debugging console
- Improved memory viewer
- GB: LR35902/GB-Z80 disassembler
- Configuration of gamepad hats
Bugfixes:
- LR35902: Fix core never exiting with certain event patterns
- GB Timer: Improve DIV reset behavior

View File

@ -12,10 +12,26 @@ CXX_GUARD_START
struct Configuration;
enum mInputHat {
M_INPUT_HAT_NEUTRAL = 0,
M_INPUT_HAT_UP = 1,
M_INPUT_HAT_RIGHT = 2,
M_INPUT_HAT_DOWN = 4,
M_INPUT_HAT_LEFT = 8
};
struct mInputHatBindings {
int up;
int right;
int down;
int left;
};
struct mInputPlatformInfo {
const char* platformName;
const char** keyId;
size_t nKeys;
struct mInputHatBindings hat;
};
struct mInputMap {
@ -48,6 +64,11 @@ void mInputUnbindAllAxes(struct mInputMap*, uint32_t type);
const struct mInputAxis* mInputQueryAxis(const struct mInputMap*, uint32_t type, int axis);
void mInputEnumerateAxes(const struct mInputMap*, uint32_t type, void (handler(int axis, const struct mInputAxis* description, void* user)), void* user);
int mInputMapHat(const struct mInputMap*, uint32_t type, int id, int direction);
void mInputBindHat(struct mInputMap*, uint32_t type, int id, const struct mInputHatBindings* bindings);
void mInputUnbindHat(struct mInputMap*, uint32_t type, int id);
void mInputUnbindAllHats(struct mInputMap*, uint32_t type);
void mInputMapLoad(struct mInputMap*, uint32_t type, const struct Configuration*);
void mInputMapSave(const struct mInputMap*, uint32_t type, struct Configuration*);

View File

@ -7,6 +7,7 @@
#include <mgba-util/configuration.h>
#include <mgba-util/table.h>
#include <mgba-util/vector.h>
#include <inttypes.h>
@ -15,11 +16,15 @@
#define KEY_VALUE_MAX 16
#define AXIS_INFO_MAX 12
DECLARE_VECTOR(mInputHatList, struct mInputHatBindings);
DEFINE_VECTOR(mInputHatList, struct mInputHatBindings);
struct mInputMapImpl {
int* map;
uint32_t type;
struct Table axes;
struct mInputHatList hats;
};
struct mInputAxisSave {
@ -89,6 +94,7 @@ static struct mInputMapImpl* _guaranteeMap(struct mInputMap* map, uint32_t type)
impl->map[i] = -1;
}
TableInit(&impl->axes, 2, free);
mInputHatListInit(&impl->hats, 1);
} else {
impl = _lookupMap(map, type);
}
@ -123,6 +129,7 @@ static struct mInputMapImpl* _guaranteeMap(struct mInputMap* map, uint32_t type)
}
}
TableInit(&impl->axes, 2, free);
mInputHatListInit(&impl->hats, 1);
}
return impl;
}
@ -176,6 +183,28 @@ static void _loadAxis(struct mInputMap* map, uint32_t type, const char* sectionN
mInputBindAxis(map, type, axis, &realDescription);
}
static bool _loadHat(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, int hatId) {
char hatKey[KEY_NAME_MAX];
struct mInputHatBindings hatBindings = { -1, -1, -1, -1 };
bool found = false;
snprintf(hatKey, KEY_NAME_MAX, "hat%iUp", hatId);
found = _getIntValue(config, sectionName, hatKey, &hatBindings.up) || found;
snprintf(hatKey, KEY_NAME_MAX, "hat%iRight", hatId);
found = _getIntValue(config, sectionName, hatKey, &hatBindings.right) || found;
snprintf(hatKey, KEY_NAME_MAX, "hat%iDown", hatId);
found = _getIntValue(config, sectionName, hatKey, &hatBindings.down) || found;
snprintf(hatKey, KEY_NAME_MAX, "hat%iLeft", hatId);
found = _getIntValue(config, sectionName, hatKey, &hatBindings.left) || found;
if (!found) {
return false;
}
mInputBindHat(map, type, hatId, &hatBindings);
return true;
}
static void _saveKey(const struct mInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config, int key, const char* keyName) {
char keyKey[KEY_NAME_MAX];
snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
@ -239,6 +268,24 @@ static void _saveAxis(uint32_t axis, void* dp, void* up) {
}
}
static void _saveHat(const char* sectionName, struct Configuration* config, int hatId, const struct mInputHatBindings* hat) {
char hatKey[KEY_NAME_MAX];
char hatValue[KEY_VALUE_MAX];
snprintf(hatKey, KEY_NAME_MAX, "hat%iUp", hatId);
snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->up);
ConfigurationSetValue(config, sectionName, hatKey, hatValue);
snprintf(hatKey, KEY_NAME_MAX, "hat%iRight", hatId);
snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->right);
ConfigurationSetValue(config, sectionName, hatKey, hatValue);
snprintf(hatKey, KEY_NAME_MAX, "hat%iDown", hatId);
snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->down);
ConfigurationSetValue(config, sectionName, hatKey, hatValue);
snprintf(hatKey, KEY_NAME_MAX, "hat%iLeft", hatId);
snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->left);
ConfigurationSetValue(config, sectionName, hatKey, hatValue);
}
void _enumerateAxis(uint32_t axis, void* dp, void* ep) {
struct mInputAxisEnumerate* enumUser = ep;
const struct mInputAxis* description = dp;
@ -266,6 +313,10 @@ static bool _loadAll(struct mInputMap* map, uint32_t type, const char* sectionNa
_loadKey(map, type, sectionName, config, i, map->info->keyId[i]);
_loadAxis(map, type, sectionName, config, i, map->info->keyId[i]);
}
i = 0;
while (_loadHat(map, type, sectionName, config, i)) {
++i;
}
return true;
}
@ -289,6 +340,11 @@ static void _saveAll(const struct mInputMap* map, uint32_t type, const char* sec
map->info
};
TableEnumerate(&impl->axes, _saveAxis, &save);
for (i = 0; i < mInputHatListSize(&impl->hats); ++i) {
const struct mInputHatBindings* hat = mInputHatListGetConstPointer(&impl->hats, i);
_saveHat(sectionName, config, i, hat);
}
}
void mInputMapInit(struct mInputMap* map, const struct mInputPlatformInfo* info) {
@ -303,6 +359,7 @@ void mInputMapDeinit(struct mInputMap* map) {
if (map->maps[m].type) {
free(map->maps[m].map);
TableDeinit(&map->maps[m].axes);
mInputHatListDeinit(&map->maps[m].hats);
}
}
free(map->maps);
@ -451,6 +508,59 @@ void mInputEnumerateAxes(const struct mInputMap* map, uint32_t type, void (handl
TableEnumerate(&impl->axes, _enumerateAxis, &enumUser);
}
int mInputMapHat(const struct mInputMap* map, uint32_t type, int id, int direction) {
const struct mInputMapImpl* impl = _lookupMapConst(map, type);
if (!impl) {
return 0;
}
if (id >= (ssize_t) mInputHatListSize(&impl->hats)) {
return 0;
}
const struct mInputHatBindings* description = mInputHatListGetConstPointer(&impl->hats, id);
int mapping = 0;
if (direction & M_INPUT_HAT_UP && description->up >= 0) {
mapping |= 1 << description->up;
}
if (direction & M_INPUT_HAT_RIGHT && description->right >= 0) {
mapping |= 1 << description->right;
}
if (direction & M_INPUT_HAT_DOWN && description->down >= 0) {
mapping |= 1 << description->down;
}
if (direction & M_INPUT_HAT_LEFT && description->left >= 0) {
mapping |= 1 << description->left;
}
return mapping;
}
void mInputBindHat(struct mInputMap* map, uint32_t type, int id, const struct mInputHatBindings* bindings) {
struct mInputMapImpl* impl = _guaranteeMap(map, type);
while (id >= (ssize_t) mInputHatListSize(&impl->hats)) {
*mInputHatListAppend(&impl->hats) = (struct mInputHatBindings) { -1, -1, -1, -1 };
}
*mInputHatListGetPointer(&impl->hats, id) = *bindings;
}
void mInputUnbindHat(struct mInputMap* map, uint32_t type, int id) {
struct mInputMapImpl* impl = _lookupMap(map, type);
if (!impl) {
return;
}
if (mInputHatListSize(&impl->hats) && id + 1 == (ssize_t) mInputHatListSize(&impl->hats)) {
mInputHatListResize(&impl->hats, -1);
} else {
struct mInputHatBindings* description = mInputHatListGetPointer(&impl->hats, id);
memset(description, -1, sizeof(&description));
}
}
void mInputUnbindAllHats(struct mInputMap* map, uint32_t type) {
struct mInputMapImpl* impl = _lookupMap(map, type);
if (impl) {
mInputHatListClear(&impl->hats);
}
}
void mInputMapLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config) {
char sectionName[SECTION_NAME_MAX];
_makeSectionName(map->info->platformName, sectionName, SECTION_NAME_MAX, type);

View File

@ -21,5 +21,11 @@ const struct mInputPlatformInfo GBAInputInfo = {
"R",
"L"
},
.nKeys = GBA_KEY_MAX
.nKeys = GBA_KEY_MAX,
.hat = {
.up = GBA_KEY_UP,
.left = GBA_KEY_LEFT,
.down = GBA_KEY_DOWN,
.right = GBA_KEY_RIGHT
}
};

View File

@ -311,18 +311,7 @@ int InputController::pollEvents() {
int numHats = SDL_JoystickNumHats(joystick);
for (i = 0; i < numHats; ++i) {
int hat = SDL_JoystickGetHat(joystick, i);
if (hat & SDL_HAT_UP) {
activeButtons |= 1 << GBA_KEY_UP;
}
if (hat & SDL_HAT_LEFT) {
activeButtons |= 1 << GBA_KEY_LEFT;
}
if (hat & SDL_HAT_DOWN) {
activeButtons |= 1 << GBA_KEY_DOWN;
}
if (hat & SDL_HAT_RIGHT) {
activeButtons |= 1 << GBA_KEY_RIGHT;
}
activeButtons |= mInputMapHat(&m_inputMap, SDL_BINDING_BUTTON, i, hat);
}
int numAxes = SDL_JoystickNumAxes(joystick);

View File

@ -141,6 +141,8 @@ void mSDLInitBindingsGBA(struct mInputMap* inputMap) {
mInputBindAxis(inputMap, SDL_BINDING_BUTTON, 0, &description);
description = (struct mInputAxis) { GBA_KEY_DOWN, GBA_KEY_UP, 0x4000, -0x4000 };
mInputBindAxis(inputMap, SDL_BINDING_BUTTON, 1, &description);
mInputBindHat(inputMap, SDL_BINDING_BUTTON, 0, &GBAInputInfo.hat);
}
bool mSDLAttachPlayer(struct mSDLEvents* events, struct mSDLPlayer* player) {
@ -498,6 +500,18 @@ static void _mSDLHandleJoyButton(struct mCore* core, struct mSDLPlayer* sdlConte
}
}
static void _mSDLHandleJoyHat(struct mCore* core, struct mSDLPlayer* sdlContext, const struct SDL_JoyHatEvent* event) {
int allKeys = mInputMapHat(sdlContext->bindings, SDL_BINDING_BUTTON, event->hat, -1);
if (allKeys == 0) {
return;
}
int keys = mInputMapHat(sdlContext->bindings, SDL_BINDING_BUTTON, event->hat, event->value);
core->clearKeys(core, allKeys ^ keys);
core->addKeys(core, keys);
}
static void _mSDLHandleJoyAxis(struct mCore* core, struct mSDLPlayer* sdlContext, const struct SDL_JoyAxisEvent* event) {
int clearKeys = ~mInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, -1);
int newKeys = 0;
@ -540,7 +554,7 @@ void mSDLHandleEvent(struct mCoreThread* context, struct mSDLPlayer* sdlContext,
_mSDLHandleJoyButton(context->core, sdlContext, &event->jbutton);
break;
case SDL_JOYHATMOTION:
// TODO
_mSDLHandleJoyHat(context->core, sdlContext, &event->jhat);
break;
case SDL_JOYAXISMOTION:
_mSDLHandleJoyAxis(context->core, sdlContext, &event->jaxis);