all repos — mgba @ 78526ae71a7776c57b3a63a74c46031bf7a9a4f8

mGBA Game Boy Advance Emulator

SDL: Add support for configuring hats
Vicki Pfau vi@endrift.com
Mon, 23 Jan 2017 00:03:59 -0800
commit

78526ae71a7776c57b3a63a74c46031bf7a9a4f8

parent

6a188289c209a3c905dc5209640904a91165c879

M CHANGESCHANGES

@@ -7,6 +7,7 @@ - Sprite viewer

- 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
M include/mgba/core/input.hinclude/mgba/core/input.h

@@ -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 {

@@ -47,6 +63,11 @@ void mInputUnbindAxis(struct mInputMap*, uint32_t type, int axis);

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*);
M src/core/input.csrc/core/input.c

@@ -7,6 +7,7 @@ #include <mgba/core/input.h>

#include <mgba-util/configuration.h> #include <mgba-util/table.h> +#include <mgba-util/vector.h> #include <inttypes.h>

@@ -15,11 +16,15 @@ #define KEY_NAME_MAX 32

#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 @@ for (i = 0; i < map->info->nKeys; ++i) {

impl->map[i] = -1; } TableInit(&impl->axes, 2, free); + mInputHatListInit(&impl->hats, 1); } else { impl = _lookupMap(map, type); }

@@ -123,6 +129,7 @@ impl->map[i] = -1;

} } TableInit(&impl->axes, 2, free); + mInputHatListInit(&impl->hats, 1); } return impl; }

@@ -176,6 +183,28 @@ }

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 @@ ConfigurationSetValue(user->config, sectionName, axisKey, axisInfo);

} } +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 @@ for (i = 0; i < map->info->nKeys; ++i) {

_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 @@ sectionName,

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 @@ for (m = 0; m < map->numMaps; ++m) {

if (map->maps[m].type) { free(map->maps[m].map); TableDeinit(&map->maps[m].axes); + mInputHatListDeinit(&map->maps[m].hats); } } free(map->maps);

@@ -449,6 +506,59 @@ handler,

user }; 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) {
M src/gba/input.csrc/gba/input.c

@@ -21,5 +21,11 @@ "Down",

"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 + } };
M src/platform/qt/InputController.cppsrc/platform/qt/InputController.cpp

@@ -311,18 +311,7 @@ }

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);
M src/platform/sdl/sdl-events.csrc/platform/sdl/sdl-events.c

@@ -141,6 +141,8 @@ struct mInputAxis description = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x4000, -0x4000 };

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 @@ core->clearKeys(core, 1 << key);

} } +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 @@ case SDL_JOYBUTTONUP:

_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);