all repos — mgba @ 02aec4fc6573661573912c501717cfce03aed24f

mGBA Game Boy Advance Emulator

src/platform/sdl/sdl-events.c (view raw)

  1#include "sdl-events.h"
  2
  3#include "debugger.h"
  4#include "gba-io.h"
  5#include "gba-serialize.h"
  6#include "gba-video.h"
  7
  8int GBASDLInitEvents(struct GBASDLEvents* context) {
  9	if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
 10		return 0;
 11	}
 12	SDL_JoystickEventState(SDL_ENABLE);
 13	context->joystick = SDL_JoystickOpen(0);
 14#if !SDL_VERSION_ATLEAST(2, 0, 0)
 15	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 16#endif
 17	return 1;
 18}
 19
 20void GBASDLDeinitEvents(struct GBASDLEvents* context) {
 21	SDL_JoystickClose(context->joystick);
 22	SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
 23}
 24
 25static void _pauseAfterFrame(struct GBAThread* context) {
 26	context->frameCallback = 0;
 27	GBAThreadPause(context);
 28}
 29
 30static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event) {
 31	enum GBAKey key = 0;
 32	int isPaused = GBAThreadIsPaused(context);
 33	switch (event->keysym.sym) {
 34	case SDLK_z:
 35		key = GBA_KEY_A;
 36		break;
 37	case SDLK_x:
 38		key = GBA_KEY_B;
 39		break;
 40	case SDLK_a:
 41		key = GBA_KEY_L;
 42		break;
 43	case SDLK_s:
 44		key = GBA_KEY_R;
 45		break;
 46	case SDLK_RETURN:
 47		key = GBA_KEY_START;
 48		break;
 49	case SDLK_BACKSPACE:
 50		key = GBA_KEY_SELECT;
 51		break;
 52	case SDLK_UP:
 53		key = GBA_KEY_UP;
 54		break;
 55	case SDLK_DOWN:
 56		key = GBA_KEY_DOWN;
 57		break;
 58	case SDLK_LEFT:
 59		key = GBA_KEY_LEFT;
 60		break;
 61	case SDLK_RIGHT:
 62		key = GBA_KEY_RIGHT;
 63		break;
 64	case SDLK_F11:
 65		if (event->type == SDL_KEYDOWN && context->debugger) {
 66			ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL);
 67		}
 68		break;
 69	case SDLK_TAB:
 70		context->sync.audioWait = event->type != SDL_KEYDOWN;
 71		return;
 72	case SDLK_LEFTBRACKET:
 73		if (!isPaused) {
 74			GBAThreadPause(context);
 75		}
 76		GBARewind(context, 10);
 77		if (!isPaused) {
 78			GBAThreadUnpause(context);
 79		}
 80	default:
 81		if (event->type == SDL_KEYDOWN) {
 82			if (event->keysym.mod & KMOD_CTRL) {
 83				switch (event->keysym.sym) {
 84				case SDLK_p:
 85					GBAThreadTogglePause(context);
 86					break;
 87				case SDLK_n:
 88					GBAThreadPause(context);
 89					context->frameCallback = _pauseAfterFrame;
 90					GBAThreadUnpause(context);
 91					break;
 92				default:
 93					break;
 94				}
 95			}
 96			if (event->keysym.mod & KMOD_SHIFT) {
 97				switch (event->keysym.sym) {
 98				case SDLK_F1:
 99				case SDLK_F2:
100				case SDLK_F3:
101				case SDLK_F4:
102				case SDLK_F5:
103				case SDLK_F6:
104				case SDLK_F7:
105				case SDLK_F8:
106				case SDLK_F9:
107				case SDLK_F10:
108					if (!isPaused) {
109						GBAThreadPause(context);
110					}
111					GBASaveState(context->gba, event->keysym.sym - SDLK_F1);
112					if (!isPaused) {
113						GBAThreadUnpause(context);
114					}
115					break;
116				default:
117					break;
118				}
119			} else {
120				switch (event->keysym.sym) {
121				case SDLK_F1:
122				case SDLK_F2:
123				case SDLK_F3:
124				case SDLK_F4:
125				case SDLK_F5:
126				case SDLK_F6:
127				case SDLK_F7:
128				case SDLK_F8:
129				case SDLK_F9:
130				case SDLK_F10:
131					if (!isPaused) {
132						GBAThreadPause(context);
133					}
134					GBALoadState(context->gba, event->keysym.sym - SDLK_F1);
135					if (!isPaused) {
136						GBAThreadUnpause(context);
137					}
138					break;
139				default:
140					break;
141				}
142			}
143		}
144		return;
145	}
146
147	if (event->type == SDL_KEYDOWN) {
148		context->activeKeys |= 1 << key;
149	} else {
150		context->activeKeys &= ~(1 << key);
151	}
152}
153
154static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) {
155	enum GBAKey key = 0;
156	// Sorry, hardcoded to my gamepad for now
157	switch (event->button) {
158	case 2:
159		key = GBA_KEY_A;
160		break;
161	case 1:
162		key = GBA_KEY_B;
163		break;
164	case 6:
165		key = GBA_KEY_L;
166		break;
167	case 7:
168		key = GBA_KEY_R;
169		break;
170	case 8:
171		key = GBA_KEY_START;
172		break;
173	case 9:
174		key = GBA_KEY_SELECT;
175		break;
176	default:
177		return;
178	}
179
180	if (event->type == SDL_JOYBUTTONDOWN) {
181		context->activeKeys |= 1 << key;
182	} else {
183		context->activeKeys &= ~(1 << key);
184	}
185}
186
187static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
188	enum GBAKey key = 0;
189
190	if (event->value & SDL_HAT_UP) {
191		key |= 1 << GBA_KEY_UP;
192	}
193	if (event->value & SDL_HAT_LEFT) {
194		key |= 1 << GBA_KEY_LEFT;
195	}
196	if (event->value & SDL_HAT_DOWN) {
197		key |= 1 << GBA_KEY_DOWN;
198	}
199	if (event->value & SDL_HAT_RIGHT) {
200		key |= 1 << GBA_KEY_RIGHT;
201	}
202
203	context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
204	context->activeKeys |= key;
205}
206
207void GBASDLHandleEvent(struct GBAThread* context, const union SDL_Event* event) {
208	switch (event->type) {
209	case SDL_QUIT:
210		// FIXME: this isn't thread-safe
211		if (context->debugger) {
212			context->debugger->state = DEBUGGER_EXITING;
213		}
214		MutexLock(&context->stateMutex);
215		context->state = THREAD_EXITING;
216		ConditionWake(&context->stateCond);
217		MutexUnlock(&context->stateMutex);
218		break;
219	case SDL_KEYDOWN:
220	case SDL_KEYUP:
221		_GBASDLHandleKeypress(context, &event->key);
222		break;
223	case SDL_JOYBUTTONDOWN:
224	case SDL_JOYBUTTONUP:
225		_GBASDLHandleJoyButton(context, &event->jbutton);
226		break;
227	case SDL_JOYHATMOTION:
228		_GBASDLHandleJoyHat(context, &event->jhat);
229	}
230}