diff --git a/src/gba/gba-input.c b/src/gba/gba-input.c new file mode 100644 index 000000000..4641626c6 --- /dev/null +++ b/src/gba/gba-input.c @@ -0,0 +1,84 @@ +#include "gba-input.h" + +struct GBAInputMapImpl { + int* map; + uint32_t type; +}; + +void GBAInputMapInit(struct GBAInputMap* map) { + map->maps = 0; + map->numMaps = 0; +} + +void GBAInputMapDeinit(struct GBAInputMap* map) { + size_t m; + for (m = 0; m < map->numMaps; ++m) { + free(map->maps[m].map); + } + free(map->maps); + map->maps = 0; + map->numMaps = 0; +} + +enum GBAKey GBAInputMapKey(struct GBAInputMap* map, uint32_t type, int key) { + 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; + } + } + if (!impl || !impl->map) { + return GBA_KEY_NONE; + } + + for (m = 0; m < GBA_KEY_MAX; ++m) { + if (impl->map[m] == key) { + return m; + } + } + return GBA_KEY_NONE; +} + +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; + } + impl = &map->maps[m]; + impl->type = type; + impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey)); + } + } + impl->map[input] = key; +} diff --git a/src/gba/gba-input.h b/src/gba/gba-input.h new file mode 100644 index 000000000..684598db2 --- /dev/null +++ b/src/gba/gba-input.h @@ -0,0 +1,17 @@ +#ifndef GBA_INPUT_H +#define GBA_INPUT_H + +#include "gba.h" + +struct GBAInputMap { + struct GBAInputMapImpl* maps; + size_t numMaps; +}; + +void GBAInputMapInit(struct GBAInputMap*); +void GBAInputMapDeinit(struct GBAInputMap*); + +enum GBAKey GBAInputMapKey(struct GBAInputMap*, uint32_t type, int key); +void GBAInputBindKey(struct GBAInputMap*, uint32_t type, int key, enum GBAKey input); + +#endif diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 9f2eefceb..37ccabdf7 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -390,6 +390,8 @@ void GBAThreadJoin(struct GBAThread* threadContext) { } free(threadContext->rewindBuffer); + GBAInputMapDeinit(&threadContext->inputMap); + if (threadContext->rom) { threadContext->rom->close(threadContext->rom); threadContext->rom = 0; diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index d8ea033b0..70468eb10 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -4,6 +4,7 @@ #include "common.h" #include "gba.h" +#include "gba-input.h" #include "util/threading.h" #include "platform/commandline.h" @@ -56,6 +57,7 @@ struct GBAThread { struct VFile* patch; const char* fname; int activeKeys; + struct GBAInputMap inputMap; // Run-time options int frameskip; diff --git a/src/gba/gba.h b/src/gba/gba.h index 3927d35bf..5825f9154 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -57,6 +57,7 @@ enum GBAKey { GBA_KEY_DOWN = 7, GBA_KEY_R = 8, GBA_KEY_L = 9, + GBA_KEY_MAX, GBA_KEY_NONE = -1 }; diff --git a/src/platform/sdl/gl-main.c b/src/platform/sdl/gl-main.c index 65e85c770..f494366ea 100644 --- a/src/platform/sdl/gl-main.c +++ b/src/platform/sdl/gl-main.c @@ -100,6 +100,9 @@ int main(int argc, char** argv) { renderer.audio.samples = context.audioBuffers; GBASDLInitAudio(&renderer.audio); + renderer.events.bindings = &context.inputMap; + GBASDLInitEvents(&renderer.events); + GBAThreadStart(&context); _GBASDLRunloop(&context, &renderer); @@ -118,7 +121,6 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) { return 0; } - GBASDLInitEvents(&renderer->events); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 803f0fbd5..ab1e3a8d9 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -12,6 +12,9 @@ #define GUI_MOD KMOD_CTRL #endif +#define SDL_BINDING_KEY 0x53444C4B +#define SDL_BINDING_BUTTON 0x53444C42 + bool GBASDLInitEvents(struct GBASDLEvents* context) { if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { return false; @@ -21,6 +24,24 @@ bool GBASDLInitEvents(struct GBASDLEvents* context) { #if !SDL_VERSION_ATLEAST(2, 0, 0) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); #endif + + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_z, GBA_KEY_A); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_x, GBA_KEY_B); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_a, GBA_KEY_L); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_s, GBA_KEY_R); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_RETURN, GBA_KEY_START); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_BACKSPACE, GBA_KEY_SELECT); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT); + GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT); + + GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 2, GBA_KEY_A); + GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 1, GBA_KEY_B); + GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 6, GBA_KEY_L); + GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 7, GBA_KEY_R); + GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 8, GBA_KEY_START); + GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 9, GBA_KEY_SELECT); return true; } @@ -29,64 +50,25 @@ void GBASDLDeinitEvents(struct GBASDLEvents* context) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } -enum GBAKey GBASDLMapButtonToKey(int button) { - // Sorry, hardcoded to my gamepad for now - switch (button) { - case 2: - return GBA_KEY_A; - case 1: - return GBA_KEY_B; - case 6: - return GBA_KEY_L; - case 7: - return GBA_KEY_R; - case 8: - return GBA_KEY_START; - case 9: - return GBA_KEY_SELECT; - default: - return GBA_KEY_NONE; - } -} - static void _pauseAfterFrame(struct GBAThread* context) { context->frameCallback = 0; GBAThreadPauseFromThread(context); } static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) { - enum GBAKey key = 0; + enum GBAKey key = GBA_KEY_NONE; + if (!event->keysym.mod) { + key = GBAInputMapKey(&context->inputMap, SDL_BINDING_KEY, event->keysym.sym); + } + if (key != GBA_KEY_NONE) { + if (event->type == SDL_KEYDOWN) { + context->activeKeys |= 1 << key; + } else { + context->activeKeys &= ~(1 << key); + } + return; + } switch (event->keysym.sym) { - case SDLK_z: - key = GBA_KEY_A; - break; - case SDLK_x: - key = GBA_KEY_B; - break; - case SDLK_a: - key = GBA_KEY_L; - break; - case SDLK_s: - key = GBA_KEY_R; - break; - case SDLK_RETURN: - key = GBA_KEY_START; - break; - case SDLK_BACKSPACE: - key = GBA_KEY_SELECT; - break; - case SDLK_UP: - key = GBA_KEY_UP; - break; - case SDLK_DOWN: - key = GBA_KEY_DOWN; - break; - case SDLK_LEFT: - key = GBA_KEY_LEFT; - break; - case SDLK_RIGHT: - key = GBA_KEY_RIGHT; - break; case SDLK_F11: if (event->type == SDL_KEYDOWN && context->debugger) { ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL); @@ -192,17 +174,11 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents } return; } - - if (event->type == SDL_KEYDOWN) { - context->activeKeys |= 1 << key; - } else { - context->activeKeys &= ~(1 << key); - } } static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) { enum GBAKey key = 0; - key = GBASDLMapButtonToKey(event->button); + key = GBAInputMapKey(&context->inputMap, SDL_BINDING_BUTTON, event->button); if (key == GBA_KEY_NONE) { return; } diff --git a/src/platform/sdl/sdl-events.h b/src/platform/sdl/sdl-events.h index d8b9c22bb..1621aa052 100644 --- a/src/platform/sdl/sdl-events.h +++ b/src/platform/sdl/sdl-events.h @@ -8,6 +8,7 @@ #include struct GBASDLEvents { + struct GBAInputMap* bindings; SDL_Joystick* joystick; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Window* window;