GBA Input: Refactor SDL and Qt input code
jump to
@@ -45,9 +45,9 @@ map->maps = 0;
map->numMaps = 0; } -enum GBAKey GBAInputMapKey(struct GBAInputMap* map, uint32_t type, int key) { +enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key) { size_t m; - struct GBAInputMapImpl* impl = 0; + const struct GBAInputMapImpl* impl = 0; for (m = 0; m < map->numMaps; ++m) { if (map->maps[m].type == type) { impl = &map->maps[m];
@@ -13,7 +13,7 @@
void GBAInputMapInit(struct GBAInputMap*); void GBAInputMapDeinit(struct GBAInputMap*); -enum GBAKey GBAInputMapKey(struct GBAInputMap*, uint32_t type, int key); +enum GBAKey GBAInputMapKey(const struct GBAInputMap*, uint32_t type, int key); void GBAInputBindKey(struct GBAInputMap*, uint32_t type, int key, enum GBAKey input); void GBAInputMapLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*);
@@ -390,8 +390,6 @@ }
} free(threadContext->rewindBuffer); - GBAInputMapDeinit(&threadContext->inputMap); - if (threadContext->rom) { threadContext->rom->close(threadContext->rom); threadContext->rom = 0;
@@ -63,7 +63,6 @@ struct VFile* bios;
struct VFile* patch; const char* fname; int activeKeys; - struct GBAInputMap inputMap; struct GBAAVStream* stream; // Run-time options
@@ -35,6 +35,7 @@ ConfigController.cpp
Display.cpp GBAApp.cpp GameController.cpp + InputController.cpp LoadSaveState.cpp LogView.cpp SavestateButton.cpp
@@ -57,6 +57,9 @@
const GBAOptions* options() const { return &m_opts; } bool parseArguments(GBAArguments* args, int argc, char* argv[]); + const Configuration* configuration() const { return &m_config.configTable; } + const Configuration* defaults() const { return &m_config.defaultsTable; } + ConfigOption* addOption(const char* key); void updateOption(const char* key);
@@ -14,6 +14,10 @@ GBAApp::GBAApp(int& argc, char* argv[])
: QApplication(argc, argv) , m_window(&m_configController) { +#ifdef BUILD_SDL + SDL_Init(SDL_INIT_NOPARACHUTE); +#endif + QApplication::setApplicationName(PROJECT_NAME); QApplication::setApplicationVersion(PROJECT_VERSION);
@@ -1,6 +1,7 @@
#include "GameController.h" #include "AudioProcessor.h" +#include "InputController.h" #include <QThread>@@ -26,6 +27,7 @@ , m_videoSync(VIDEO_SYNC)
, m_audioSync(AUDIO_SYNC) , m_turbo(false) , m_turboForced(false) + , m_inputController(nullptr) { m_renderer = new GBAVideoSoftwareRenderer; GBAVideoSoftwareRendererCreate(m_renderer);@@ -40,15 +42,6 @@ m_threadContext.userData = this;
m_threadContext.rewindBufferCapacity = 0; m_threadContext.logLevel = -1; - GBAInputMapInit(&m_threadContext.inputMap); - -#ifdef BUILD_SDL - SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE); - m_sdlEvents.bindings = &m_threadContext.inputMap; - GBASDLInitEvents(&m_sdlEvents); - SDL_JoystickEventState(SDL_QUERY); -#endif - m_threadContext.startCallback = [] (GBAThread* context) { GameController* controller = static_cast<GameController*>(context->userData); controller->m_audioProcessor->setInput(context);@@ -94,7 +87,6 @@ m_audioThread->quit();
m_audioThread->wait(); disconnect(); closeGame(); - GBAInputMapDeinit(&m_threadContext.inputMap); delete m_renderer; delete[] m_drawContext; }@@ -352,36 +344,11 @@ }
#ifdef BUILD_SDL void GameController::testSDLEvents() { - SDL_Joystick* joystick = m_sdlEvents.joystick; - SDL_JoystickUpdate(); - int numButtons = SDL_JoystickNumButtons(joystick); - m_activeButtons = 0; - int i; - for (i = 0; i < numButtons; ++i) { - GBAKey key = GBAInputMapKey(&m_threadContext.inputMap, SDL_BINDING_BUTTON, i); - if (key == GBA_KEY_NONE) { - continue; - } - if (SDL_JoystickGetButton(joystick, i)) { - m_activeButtons |= 1 << key; - } + if (!m_inputController) { + return; } - int numHats = SDL_JoystickNumHats(joystick); - for (i = 0; i < numHats; ++i) { - int hat = SDL_JoystickGetHat(joystick, i); - if (hat & SDL_HAT_UP) { - m_activeButtons |= 1 << GBA_KEY_UP; - } - if (hat & SDL_HAT_LEFT) { - m_activeButtons |= 1 << GBA_KEY_LEFT; - } - if (hat & SDL_HAT_DOWN) { - m_activeButtons |= 1 << GBA_KEY_DOWN; - } - if (hat & SDL_HAT_RIGHT) { - m_activeButtons |= 1 << GBA_KEY_RIGHT; - } - } + + m_activeButtons = m_inputController->testSDLEvents(); updateKeys(); } #endif
@@ -22,6 +22,7 @@
namespace QGBA { class AudioProcessor; +class InputController; class GameController : public QObject { Q_OBJECT@@ -41,6 +42,8 @@ bool isLoaded() { return m_gameOpen; }
bool audioSync() const { return m_audioSync; } bool videoSync() const { return m_videoSync; } + + void setInputController(InputController* controller) { m_inputController = controller; } #ifdef USE_GDB_STUB ARMDebugger* debugger();@@ -113,6 +116,8 @@ bool m_videoSync;
bool m_audioSync; bool m_turbo; bool m_turboForced; + + InputController* m_inputController; }; }
@@ -0,0 +1,89 @@
+#include "InputController.h" + +#include <Qt> + +extern "C" { +#include "util/configuration.h" +} + +using namespace QGBA; + +InputController::InputController() { + GBAInputMapInit(&m_inputMap); + +#ifdef BUILD_SDL + m_sdlEvents.bindings = &m_inputMap; + GBASDLInitEvents(&m_sdlEvents); + SDL_JoystickEventState(SDL_QUERY); +#endif + + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_X, GBA_KEY_A); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Z, GBA_KEY_B); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_A, GBA_KEY_L); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_S, GBA_KEY_R); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Return, GBA_KEY_START); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Backspace, GBA_KEY_SELECT); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Up, GBA_KEY_UP); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Down, GBA_KEY_DOWN); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Left, GBA_KEY_LEFT); + GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Right, GBA_KEY_RIGHT); +} + +InputController::~InputController() { + GBAInputMapDeinit(&m_inputMap); + +#ifdef BUILD_SDL + GBASDLDeinitEvents(&m_sdlEvents); +#endif +} + +void InputController::loadDefaultConfiguration(const Configuration* config) { + loadConfiguration(KEYBOARD, config); +#ifdef BUILD_SDL + loadConfiguration(SDL_BINDING_BUTTON, config); +#endif +} + +void InputController::loadConfiguration(uint32_t type, const Configuration* config) { + GBAInputMapLoad(&m_inputMap, type, config); +} + +GBAKey InputController::mapKeyboard(int key) const { + return GBAInputMapKey(&m_inputMap, KEYBOARD, key); +} + +#ifdef BUILD_SDL +int InputController::testSDLEvents() { + SDL_Joystick* joystick = m_sdlEvents.joystick; + SDL_JoystickUpdate(); + int numButtons = SDL_JoystickNumButtons(joystick); + int activeButtons = 0; + int i; + for (i = 0; i < numButtons; ++i) { + GBAKey key = GBAInputMapKey(&m_inputMap, SDL_BINDING_BUTTON, i); + if (key == GBA_KEY_NONE) { + continue; + } + if (SDL_JoystickGetButton(joystick, i)) { + activeButtons |= 1 << key; + } + } + 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; + } + } + return activeButtons; +} +#endif
@@ -0,0 +1,42 @@
+#ifndef QGBA_INPUT_CONTROLLER_H +#define QGBA_INPUT_CONTROLLER_H + +extern "C" { +#include "gba-input.h" + +#ifdef BUILD_SDL +#include "platform/sdl/sdl-events.h" +#endif +} + +struct Configuration; + +namespace QGBA { + +class InputController { +public: + static const uint32_t KEYBOARD = 0x51545F4B; + + InputController(); + ~InputController(); + + void loadDefaultConfiguration(const Configuration* config); + void loadConfiguration(uint32_t type, const Configuration* config); + + GBAKey mapKeyboard(int key) const; + +#ifdef BUILD_SDL + int testSDLEvents(); +#endif + +private: + GBAInputMap m_inputMap; + +#ifdef BUILD_SDL + GBASDLEvents m_sdlEvents; +#endif +}; + +} + +#endif
@@ -36,6 +36,7 @@ #endif
{ setWindowTitle(PROJECT_NAME); m_controller = new GameController(this); + m_controller->setInputController(&m_inputController); QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer)); format.setSwapInterval(1);@@ -66,43 +67,6 @@ delete m_logView;
delete m_videoView; } -GBAKey Window::mapKey(int qtKey) { - switch (qtKey) { - case Qt::Key_Z: - return GBA_KEY_A; - break; - case Qt::Key_X: - return GBA_KEY_B; - break; - case Qt::Key_A: - return GBA_KEY_L; - break; - case Qt::Key_S: - return GBA_KEY_R; - break; - case Qt::Key_Return: - return GBA_KEY_START; - break; - case Qt::Key_Backspace: - return GBA_KEY_SELECT; - break; - case Qt::Key_Up: - return GBA_KEY_UP; - break; - case Qt::Key_Down: - return GBA_KEY_DOWN; - break; - case Qt::Key_Left: - return GBA_KEY_LEFT; - break; - case Qt::Key_Right: - return GBA_KEY_RIGHT; - break; - default: - return GBA_KEY_NONE; - } -} - void Window::argumentsPassed(GBAArguments* args) { loadConfig();@@ -143,6 +107,8 @@
if (opts->width && opts->height) { m_screenWidget->setSizeHint(QSize(opts->width, opts->height)); } + + m_inputController.loadDefaultConfiguration(m_config->configuration()); } void Window::saveConfig() {@@ -202,7 +168,7 @@ }
if (event->key() == Qt::Key_Tab) { m_controller->setTurbo(true, false); } - GBAKey key = mapKey(event->key()); + GBAKey key = m_inputController.mapKeyboard(event->key()); if (key == GBA_KEY_NONE) { QWidget::keyPressEvent(event); return;@@ -219,7 +185,7 @@ }
if (event->key() == Qt::Key_Tab) { m_controller->setTurbo(false, false); } - GBAKey key = mapKey(event->key()); + GBAKey key = m_inputController.mapKeyboard(event->key()); if (key == GBA_KEY_NONE) { QWidget::keyPressEvent(event); return;
@@ -10,6 +10,7 @@ }
#include "GDBController.h" #include "Display.h" +#include "InputController.h" #include "LoadSaveState.h" struct GBAOptions;@@ -31,8 +32,6 @@ Window(ConfigController* config, QWidget* parent = nullptr);
virtual ~Window(); GameController* controller() { return m_controller; } - - static GBAKey mapKey(int qtKey); void setConfig(ConfigController*); void argumentsPassed(GBAArguments*);@@ -85,6 +84,7 @@ LoadSaveState* m_stateWindow;
WindowBackground* m_screenWidget; QPixmap m_logo; ConfigController* m_config; + InputController m_inputController; #ifdef USE_FFMPEG VideoView* m_videoView;
@@ -31,6 +31,9 @@ int main(int argc, char** argv) {
struct SDLSoftwareRenderer renderer; GBAVideoSoftwareRendererCreate(&renderer.d); + struct GBAInputMap inputMap; + GBAInputMapInit(&inputMap); + struct GBAConfig config; GBAConfigInit(&config, PORT); GBAConfigLoad(&config);@@ -88,7 +91,8 @@
renderer.audio.samples = context.audioBuffers; GBASDLInitAudio(&renderer.audio); - renderer.events.bindings = &context.inputMap; + renderer.events.bindings = &inputMap; + GBASDLInitindings(&inputMap); GBASDLInitEvents(&renderer.events); GBASDLEventsLoadConfig(&renderer.events, &config.configTable); // TODO: Don't use this directly@@ -101,6 +105,7 @@ freeArguments(&args);
GBAConfigFreeOpts(&opts); GBAConfigDeinit(&config); free(context.debugger); + GBAInputMapDeinit(&inputMap); _GBASDLDeinit(&renderer);
@@ -14,52 +14,56 @@ #else
#define GUI_MOD KMOD_CTRL #endif +static int _openContexts = 0; + bool GBASDLInitEvents(struct GBASDLEvents* context) { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { + if (!_openContexts && SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { return false; } + ++_openContexts; SDL_JoystickEventState(SDL_ENABLE); context->joystick = SDL_JoystickOpen(0); #if !SDL_VERSION_ATLEAST(2, 0, 0) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); #endif + return true; +} +void GBASDLInitindings(struct GBAInputMap* inputMap) { #if SDL_VERSION_ATLEAST(2, 0, 0) - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_X, GBA_KEY_A); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_Z, GBA_KEY_B); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_A, GBA_KEY_L); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_S, GBA_KEY_R); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_RETURN, GBA_KEY_START); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_BACKSPACE, GBA_KEY_SELECT); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_UP, GBA_KEY_UP); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_DOWN, GBA_KEY_DOWN); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_LEFT, GBA_KEY_LEFT); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_RIGHT, GBA_KEY_RIGHT); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_X, GBA_KEY_A); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_Z, GBA_KEY_B); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_A, GBA_KEY_L); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_S, GBA_KEY_R); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RETURN, GBA_KEY_START); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_BACKSPACE, GBA_KEY_SELECT); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_UP, GBA_KEY_UP); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_DOWN, GBA_KEY_DOWN); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_LEFT, GBA_KEY_LEFT); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RIGHT, GBA_KEY_RIGHT); #else - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_x, GBA_KEY_A); - GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_z, 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(inputMap, SDL_BINDING_KEY, SDLK_x, GBA_KEY_A); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_z, GBA_KEY_B); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_a, GBA_KEY_L); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_s, GBA_KEY_R); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RETURN, GBA_KEY_START); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_BACKSPACE, GBA_KEY_SELECT); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT); + GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT); #endif - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 13, GBA_KEY_A); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 14, GBA_KEY_B); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 10, GBA_KEY_L); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 11, GBA_KEY_R); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 3, GBA_KEY_START); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 0, GBA_KEY_SELECT); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 4, GBA_KEY_UP); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT); - GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 5, GBA_KEY_RIGHT); - - return true; + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 13, GBA_KEY_A); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 14, GBA_KEY_B); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 10, GBA_KEY_L); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 11, GBA_KEY_R); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 3, GBA_KEY_START); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 0, GBA_KEY_SELECT); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 4, GBA_KEY_UP); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT); + GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 5, GBA_KEY_RIGHT); } void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) {@@ -69,7 +73,11 @@ }
void GBASDLDeinitEvents(struct GBASDLEvents* context) { SDL_JoystickClose(context->joystick); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + + --_openContexts; + if (!_openContexts) { + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + } } static void _pauseAfterFrame(struct GBAThread* context) {@@ -81,9 +89,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
enum GBAKey key = GBA_KEY_NONE; if (!event->keysym.mod) { #if SDL_VERSION_ATLEAST(2, 0, 0) - key = GBAInputMapKey(&context->inputMap, SDL_BINDING_KEY, event->keysym.scancode); + key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.scancode); #else - key = GBAInputMapKey(&context->inputMap, SDL_BINDING_KEY, event->keysym.sym); + key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.sym); #endif } if (key != GBA_KEY_NONE) {@@ -225,9 +233,9 @@ return;
} } -static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) { +static void _GBASDLHandleJoyButton(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_JoyButtonEvent* event) { enum GBAKey key = 0; - key = GBAInputMapKey(&context->inputMap, SDL_BINDING_BUTTON, event->button); + key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_BUTTON, event->button); if (key == GBA_KEY_NONE) { return; }@@ -286,7 +294,7 @@ _GBASDLHandleKeypress(context, sdlContext, &event->key);
break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: - _GBASDLHandleJoyButton(context, &event->jbutton); + _GBASDLHandleJoyButton(context, sdlContext, &event->jbutton); break; case SDL_JOYHATMOTION: _GBASDLHandleJoyHat(context, &event->jhat);
@@ -26,6 +26,7 @@
bool GBASDLInitEvents(struct GBASDLEvents*); void GBASDLDeinitEvents(struct GBASDLEvents*); +void GBASDLInitindings(struct GBAInputMap* inputMap); void GBASDLEventsLoadConfig(struct GBASDLEvents*, const struct Configuration*); void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event);