all repos — mgba @ 8c02615593484913353dd4806189357710945384

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#ifdef USE_PNG
 81	case SDLK_F12:
 82		if (event->type == SDL_KEYDOWN) {
 83			GBAThreadInterrupt(context);
 84			GBAThreadTakeScreenshot(context);
 85			GBAThreadContinue(context);
 86		}
 87		return;
 88#endif
 89	case SDLK_TAB:
 90		context->sync.audioWait = event->type != SDL_KEYDOWN;
 91		return;
 92	case SDLK_BACKSLASH:
 93		if (event->type == SDL_KEYDOWN) {
 94			GBAThreadPause(context);
 95			context->frameCallback = _pauseAfterFrame;
 96			GBAThreadUnpause(context);
 97		}
 98		return;
 99	case SDLK_LEFTBRACKET:
100		GBAThreadInterrupt(context);
101		GBARewind(context, 10);
102		GBAThreadContinue(context);
103		return;
104	case SDLK_ESCAPE:
105		GBAThreadInterrupt(context);
106		if (context->gba->rr) {
107			GBARRStopPlaying(context->gba->rr);
108			GBARRStopRecording(context->gba->rr);
109		}
110		GBAThreadContinue(context);
111		return;
112	default:
113		if (event->type == SDL_KEYDOWN) {
114			if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) {
115				switch (event->keysym.sym) {
116#if SDL_VERSION_ATLEAST(2, 0, 0)
117				case SDLK_f:
118					SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
119					sdlContext->fullscreen = !sdlContext->fullscreen;
120					sdlContext->windowUpdated = 1;
121					break;
122#endif
123				case SDLK_p:
124					GBAThreadTogglePause(context);
125					break;
126				case SDLK_n:
127					GBAThreadPause(context);
128					context->frameCallback = _pauseAfterFrame;
129					GBAThreadUnpause(context);
130					break;
131				case SDLK_r:
132					GBAThreadReset(context);
133					break;
134				case SDLK_t:
135					if (context->stateDir) {
136						GBAThreadInterrupt(context);
137						GBARRContextCreate(context->gba);
138						if (!GBARRIsRecording(context->gba->rr)) {
139							GBARRStopPlaying(context->gba->rr);
140							GBARRInitStream(context->gba->rr, context->stateDir);
141							GBARRReinitStream(context->gba->rr, INIT_EX_NIHILO);
142							GBARRStartRecording(context->gba->rr);
143							GBARRSaveState(context->gba);
144						}
145						GBAThreadContinue(context);
146					}
147					break;
148				case SDLK_y:
149					if (context->stateDir) {
150						GBAThreadInterrupt(context);
151						GBARRContextCreate(context->gba);
152						GBARRStopRecording(context->gba->rr);
153						GBARRInitStream(context->gba->rr, context->stateDir);
154						GBARRStartPlaying(context->gba->rr, false);
155						GBARRLoadState(context->gba);
156						GBAThreadContinue(context);
157					}
158					break;
159				default:
160					break;
161				}
162			}
163			if (event->keysym.mod & KMOD_SHIFT) {
164				switch (event->keysym.sym) {
165				case SDLK_F1:
166				case SDLK_F2:
167				case SDLK_F3:
168				case SDLK_F4:
169				case SDLK_F5:
170				case SDLK_F6:
171				case SDLK_F7:
172				case SDLK_F8:
173				case SDLK_F9:
174					GBAThreadInterrupt(context);
175					GBASaveState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1 + 1, true);
176					GBAThreadContinue(context);
177					break;
178				default:
179					break;
180				}
181			} else {
182				switch (event->keysym.sym) {
183				case SDLK_F1:
184				case SDLK_F2:
185				case SDLK_F3:
186				case SDLK_F4:
187				case SDLK_F5:
188				case SDLK_F6:
189				case SDLK_F7:
190				case SDLK_F8:
191				case SDLK_F9:
192					GBAThreadInterrupt(context);
193					GBALoadState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1 + 1);
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}