all repos — mgba @ 3051143fa3a1a458ac6c15af56ab3cd07ddc5e15

mGBA Game Boy Advance Emulator

First pass at input mapping
Jeffrey Pfau jeffrey@endrift.com
Wed, 23 Jul 2014 00:06:44 -0700
commit

3051143fa3a1a458ac6c15af56ab3cd07ddc5e15

parent

f55d0851628b44ee8fb0a475bba14c27c32f53a0

A 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; +}
A 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
M src/gba/gba-thread.csrc/gba/gba-thread.c

@@ -390,6 +390,8 @@ }

} free(threadContext->rewindBuffer); + GBAInputMapDeinit(&threadContext->inputMap); + if (threadContext->rom) { threadContext->rom->close(threadContext->rom); threadContext->rom = 0;
M src/gba/gba-thread.hsrc/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 VFile* bios;

struct VFile* patch; const char* fname; int activeKeys; + struct GBAInputMap inputMap; // Run-time options int frameskip;
M src/gba/gba.hsrc/gba/gba.h

@@ -57,6 +57,7 @@ GBA_KEY_UP = 6,

GBA_KEY_DOWN = 7, GBA_KEY_R = 8, GBA_KEY_L = 9, + GBA_KEY_MAX, GBA_KEY_NONE = -1 };
M src/platform/sdl/gl-main.csrc/platform/sdl/gl-main.c

@@ -100,6 +100,9 @@

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 @@ if (SDL_Init(SDL_INIT_VIDEO) < 0) {

return 0; } - GBASDLInitEvents(&renderer->events); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
M src/platform/sdl/sdl-events.csrc/platform/sdl/sdl-events.c

@@ -12,6 +12,9 @@ #else

#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 @@ context->joystick = SDL_JoystickOpen(0);

#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 @@ SDL_JoystickClose(context->joystick);

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

} 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; }
M src/platform/sdl/sdl-events.hsrc/platform/sdl/sdl-events.h

@@ -8,6 +8,7 @@

#include <SDL.h> struct GBASDLEvents { + struct GBAInputMap* bindings; SDL_Joystick* joystick; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Window* window;