mirror of https://github.com/mgba-emu/mgba.git
SDL: Add support for configuring hats
This commit is contained in:
parent
6a188289c2
commit
78526ae71a
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
|
@ -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*);
|
||||
|
||||
|
|
110
src/core/input.c
110
src/core/input.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue