diff --git a/src/gba/gba-io.c b/src/gba/gba-io.c index 4aeef0cc2..11f9e53c2 100644 --- a/src/gba/gba-io.c +++ b/src/gba/gba-io.c @@ -150,6 +150,12 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { GBATimerUpdateRegister(gba, 3); break; + case REG_KEYINPUT: + if (gba->keySource) { + return 0x3FF ^ *gba->keySource; + } + break; + case REG_DMA0CNT_LO: case REG_DMA1CNT_LO: case REG_DMA2CNT_LO: diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 31303fdde..a47befd10 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -26,6 +26,7 @@ static void* _GBAThreadRun(void* context) { GBALoadROM(&gba, threadContext->fd); } GBAAttachDebugger(&gba, &debugger); + gba.keySource = &threadContext->activeKeys; threadContext->started = 1; pthread_mutex_lock(&threadContext->mutex); @@ -51,6 +52,7 @@ int GBAThreadStart(struct GBAThread* threadContext) { pthread_cond_init(&threadContext->cond, 0); pthread_mutex_lock(&threadContext->mutex); + threadContext->activeKeys = 0; threadContext->started = 0; pthread_create(&threadContext->thread, 0, _GBAThreadRun, threadContext); pthread_cond_wait(&threadContext->cond, &threadContext->mutex); diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index ee20c43fb..2270394ec 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -12,6 +12,7 @@ struct GBAThread { // Input struct GBAVideoRenderer* renderer; int fd; + int activeKeys; // Threading state pthread_mutex_t mutex; diff --git a/src/gba/gba.c b/src/gba/gba.c index b98fc8d7f..70b69005e 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -44,6 +44,7 @@ void GBAInit(struct GBA* gba) { memset(gba->timers, 0, sizeof(gba->timers)); gba->springIRQ = 0; + gba->keySource = 0; ARMReset(&gba->cpu); } diff --git a/src/gba/gba.h b/src/gba/gba.h index 8160ea199..3628ad56b 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -33,6 +33,19 @@ enum GBALogLevel { GBA_LOG_WARN }; +enum GBAKey { + GBA_KEY_A = 0, + GBA_KEY_B = 1, + GBA_KEY_SELECT = 2, + GBA_KEY_START = 3, + GBA_KEY_RIGHT = 4, + GBA_KEY_LEFT = 5, + GBA_KEY_UP = 6, + GBA_KEY_DOWN = 7, + GBA_KEY_R = 8, + GBA_KEY_L = 9 +}; + struct GBABoard { struct ARMBoard d; struct GBA* p; @@ -60,6 +73,7 @@ struct GBA { } timers[4]; int springIRQ; + int* keySource; enum GBAError errno; const char* errstr; diff --git a/src/main.c b/src/main.c index 91366c6af..71e39b6ce 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ #include "debugger.h" #include "gba-thread.h" +#include "gba.h" #include "renderers/video-software.h" #include @@ -19,6 +20,7 @@ struct GLSoftwareRenderer { static int _GBASDLInit(struct GLSoftwareRenderer* renderer); static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer); static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* renderer); +static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event); static const GLint _glVertices[] = { 0, 0, @@ -112,8 +114,17 @@ static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* pthread_mutex_lock(&renderer->d.mutex); pthread_cond_broadcast(&renderer->d.cond); pthread_mutex_unlock(&renderer->d.mutex); - while(SDL_PollEvent(&event)) { - + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + // FIXME: this isn't thread-safe + context->debugger->state = DEBUGGER_EXITING; + break; + case SDL_KEYDOWN: + case SDL_KEYUP: + _GBASDLHandleKeypress(context, &event.key); + break; + } } } } @@ -123,3 +134,47 @@ static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) { SDL_Quit(); } + +static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event) { + enum GBAKey key = 0; + 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; + default: + return; + } + + if (event->type == SDL_KEYDOWN) { + context->activeKeys |= 1 << key; + } else { + context->activeKeys &= ~(1 << key); + } +}