all repos — mgba @ e9864cbc99cb909c290f6acadf4ed39b6009f9d0

mGBA Game Boy Advance Emulator

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

  1#include "sdl-events.h"
  2
  3#include "debugger/debugger.h"
  4#include "gba-io.h"
  5#include "gba-rr.h"
  6#include "gba-serialize.h"
  7#include "gba-video.h"
  8#include "renderers/video-software.h"
  9#include "util/vfs.h"
 10
 11#if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__)
 12#define GUI_MOD KMOD_GUI
 13#else
 14#define GUI_MOD KMOD_CTRL
 15#endif
 16
 17bool GBASDLInitEvents(struct GBASDLEvents* context) {
 18	if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
 19		return false;
 20	}
 21	SDL_JoystickEventState(SDL_ENABLE);
 22	context->joystick = SDL_JoystickOpen(0);
 23#if !SDL_VERSION_ATLEAST(2, 0, 0)
 24	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 25#endif
 26
 27	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_z, GBA_KEY_A);
 28	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_x, GBA_KEY_B);
 29	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_a, GBA_KEY_L);
 30	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_s, GBA_KEY_R);
 31	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_RETURN, GBA_KEY_START);
 32	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_BACKSPACE, GBA_KEY_SELECT);
 33	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP);
 34	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN);
 35	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT);
 36	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT);
 37
 38	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 13, GBA_KEY_A);
 39	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 14, GBA_KEY_B);
 40	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 10, GBA_KEY_L);
 41	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 11, GBA_KEY_R);
 42	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 3, GBA_KEY_START);
 43	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 0, GBA_KEY_SELECT);
 44	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 4, GBA_KEY_UP);
 45	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN);
 46	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT);
 47	GBAInputBindKey(context->bindings, SDL_BINDING_BUTTON, 5, GBA_KEY_RIGHT);
 48	return true;
 49}
 50
 51void GBASDLDeinitEvents(struct GBASDLEvents* context) {
 52	SDL_JoystickClose(context->joystick);
 53	SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
 54}
 55
 56static void _pauseAfterFrame(struct GBAThread* context) {
 57	context->frameCallback = 0;
 58	GBAThreadPauseFromThread(context);
 59}
 60
 61static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
 62	enum GBAKey key = GBA_KEY_NONE;
 63	if (!event->keysym.mod) {
 64		key = GBAInputMapKey(&context->inputMap, SDL_BINDING_KEY, event->keysym.sym);
 65	}
 66	if (key != GBA_KEY_NONE) {
 67		if (event->type == SDL_KEYDOWN) {
 68			context->activeKeys |= 1 << key;
 69		} else {
 70			context->activeKeys &= ~(1 << key);
 71		}
 72		return;
 73	}
 74	switch (event->keysym.sym) {
 75	case SDLK_F11:
 76		if (event->type == SDL_KEYDOWN && context->debugger) {
 77			ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL);
 78		}
 79		return;
 80	case SDLK_F12:
 81		if (event->type == SDL_KEYDOWN) {
 82			GBAThreadInterrupt(context);
 83			GBAThreadTakeScreenshot(context);
 84			GBAThreadContinue(context);
 85		}
 86		return;
 87	case SDLK_TAB:
 88		context->sync.audioWait = event->type != SDL_KEYDOWN;
 89		return;
 90	case SDLK_BACKSLASH:
 91		if (event->type == SDL_KEYDOWN) {
 92			GBAThreadPause(context);
 93			context->frameCallback = _pauseAfterFrame;
 94			GBAThreadUnpause(context);
 95		}
 96		return;
 97	case SDLK_LEFTBRACKET:
 98		GBAThreadInterrupt(context);
 99		GBARewind(context, 10);
100		GBAThreadContinue(context);
101		return;
102	case SDLK_ESCAPE:
103		GBAThreadInterrupt(context);
104		if (context->gba->rr) {
105			GBARRStopPlaying(context->gba->rr);
106			GBARRStopRecording(context->gba->rr);
107		}
108		GBAThreadContinue(context);
109		return;
110	default:
111		if (event->type == SDL_KEYDOWN) {
112			if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) {
113				switch (event->keysym.sym) {
114#if SDL_VERSION_ATLEAST(2, 0, 0)
115				case SDLK_f:
116					SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
117					sdlContext->fullscreen = !sdlContext->fullscreen;
118					sdlContext->windowUpdated = 1;
119					break;
120#endif
121				case SDLK_p:
122					GBAThreadTogglePause(context);
123					break;
124				case SDLK_n:
125					GBAThreadPause(context);
126					context->frameCallback = _pauseAfterFrame;
127					GBAThreadUnpause(context);
128					break;
129				case SDLK_r:
130					GBAThreadReset(context);
131					break;
132				case SDLK_t:
133					if (context->stateDir) {
134						GBAThreadInterrupt(context);
135						GBARRContextCreate(context->gba);
136						if (!GBARRIsRecording(context->gba->rr)) {
137							GBARRStopPlaying(context->gba->rr);
138							GBARRInitStream(context->gba->rr, context->stateDir);
139							GBARRReinitStream(context->gba->rr, INIT_EX_NIHILO);
140							GBARRStartRecording(context->gba->rr);
141							GBARRSaveState(context->gba);
142						}
143						GBAThreadContinue(context);
144					}
145					break;
146				case SDLK_y:
147					if (context->stateDir) {
148						GBAThreadInterrupt(context);
149						GBARRContextCreate(context->gba);
150						GBARRStopRecording(context->gba->rr);
151						GBARRInitStream(context->gba->rr, context->stateDir);
152						GBARRStartPlaying(context->gba->rr, false);
153						GBARRLoadState(context->gba);
154						GBAThreadContinue(context);
155					}
156					break;
157				default:
158					break;
159				}
160			}
161			if (event->keysym.mod & KMOD_SHIFT) {
162				switch (event->keysym.sym) {
163				case SDLK_F1:
164				case SDLK_F2:
165				case SDLK_F3:
166				case SDLK_F4:
167				case SDLK_F5:
168				case SDLK_F6:
169				case SDLK_F7:
170				case SDLK_F8:
171				case SDLK_F9:
172				case SDLK_F10:
173					GBAThreadInterrupt(context);
174					GBASaveState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1, true);
175					GBAThreadContinue(context);
176					break;
177				default:
178					break;
179				}
180			} else {
181				switch (event->keysym.sym) {
182				case SDLK_F1:
183				case SDLK_F2:
184				case SDLK_F3:
185				case SDLK_F4:
186				case SDLK_F5:
187				case SDLK_F6:
188				case SDLK_F7:
189				case SDLK_F8:
190				case SDLK_F9:
191				case SDLK_F10:
192					GBAThreadInterrupt(context);
193					GBALoadState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1);
194					GBAThreadContinue(context);
195					break;
196				default:
197					break;
198				}
199			}
200		}
201		return;
202	}
203}
204
205static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) {
206	enum GBAKey key = 0;
207	key = GBAInputMapKey(&context->inputMap, SDL_BINDING_BUTTON, event->button);
208	if (key == GBA_KEY_NONE) {
209		return;
210	}
211
212	if (event->type == SDL_JOYBUTTONDOWN) {
213		context->activeKeys |= 1 << key;
214	} else {
215		context->activeKeys &= ~(1 << key);
216	}
217}
218
219static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
220	enum GBAKey key = 0;
221
222	if (event->value & SDL_HAT_UP) {
223		key |= 1 << GBA_KEY_UP;
224	}
225	if (event->value & SDL_HAT_LEFT) {
226		key |= 1 << GBA_KEY_LEFT;
227	}
228	if (event->value & SDL_HAT_DOWN) {
229		key |= 1 << GBA_KEY_DOWN;
230	}
231	if (event->value & SDL_HAT_RIGHT) {
232		key |= 1 << GBA_KEY_RIGHT;
233	}
234
235	context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
236	context->activeKeys |= key;
237}
238
239#if SDL_VERSION_ATLEAST(2, 0, 0)
240static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
241	UNUSED(context);
242	switch (event->event) {
243	case SDL_WINDOWEVENT_SIZE_CHANGED:
244		sdlContext->windowUpdated = 1;
245		break;
246	}
247}
248#endif
249
250void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
251	switch (event->type) {
252	case SDL_QUIT:
253		GBAThreadEnd(context);
254		break;
255#if SDL_VERSION_ATLEAST(2, 0, 0)
256	case SDL_WINDOWEVENT:
257		_GBASDLHandleWindowEvent(context, sdlContext, &event->window);
258		break;
259#endif
260	case SDL_KEYDOWN:
261	case SDL_KEYUP:
262		_GBASDLHandleKeypress(context, sdlContext, &event->key);
263		break;
264	case SDL_JOYBUTTONDOWN:
265	case SDL_JOYBUTTONUP:
266		_GBASDLHandleJoyButton(context, &event->jbutton);
267		break;
268	case SDL_JOYHATMOTION:
269		_GBASDLHandleJoyHat(context, &event->jhat);
270	}
271}