all repos — mgba @ 2b012ef0bccfcc294d1c27efa69665430a35eb32

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				case SDLK_F10:
175					GBAThreadInterrupt(context);
176					GBASaveState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1, true);
177					GBAThreadContinue(context);
178					break;
179				default:
180					break;
181				}
182			} else {
183				switch (event->keysym.sym) {
184				case SDLK_F1:
185				case SDLK_F2:
186				case SDLK_F3:
187				case SDLK_F4:
188				case SDLK_F5:
189				case SDLK_F6:
190				case SDLK_F7:
191				case SDLK_F8:
192				case SDLK_F9:
193				case SDLK_F10:
194					GBAThreadInterrupt(context);
195					GBALoadState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1);
196					GBAThreadContinue(context);
197					break;
198				default:
199					break;
200				}
201			}
202		}
203		return;
204	}
205}
206
207static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) {
208	enum GBAKey key = 0;
209	key = GBAInputMapKey(&context->inputMap, SDL_BINDING_BUTTON, event->button);
210	if (key == GBA_KEY_NONE) {
211		return;
212	}
213
214	if (event->type == SDL_JOYBUTTONDOWN) {
215		context->activeKeys |= 1 << key;
216	} else {
217		context->activeKeys &= ~(1 << key);
218	}
219}
220
221static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
222	enum GBAKey key = 0;
223
224	if (event->value & SDL_HAT_UP) {
225		key |= 1 << GBA_KEY_UP;
226	}
227	if (event->value & SDL_HAT_LEFT) {
228		key |= 1 << GBA_KEY_LEFT;
229	}
230	if (event->value & SDL_HAT_DOWN) {
231		key |= 1 << GBA_KEY_DOWN;
232	}
233	if (event->value & SDL_HAT_RIGHT) {
234		key |= 1 << GBA_KEY_RIGHT;
235	}
236
237	context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
238	context->activeKeys |= key;
239}
240
241#if SDL_VERSION_ATLEAST(2, 0, 0)
242static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
243	UNUSED(context);
244	switch (event->event) {
245	case SDL_WINDOWEVENT_SIZE_CHANGED:
246		sdlContext->windowUpdated = 1;
247		break;
248	}
249}
250#endif
251
252void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
253	switch (event->type) {
254	case SDL_QUIT:
255		GBAThreadEnd(context);
256		break;
257#if SDL_VERSION_ATLEAST(2, 0, 0)
258	case SDL_WINDOWEVENT:
259		_GBASDLHandleWindowEvent(context, sdlContext, &event->window);
260		break;
261#endif
262	case SDL_KEYDOWN:
263	case SDL_KEYUP:
264		_GBASDLHandleKeypress(context, sdlContext, &event->key);
265		break;
266	case SDL_JOYBUTTONDOWN:
267	case SDL_JOYBUTTONUP:
268		_GBASDLHandleJoyButton(context, &event->jbutton);
269		break;
270	case SDL_JOYHATMOTION:
271		_GBASDLHandleJoyHat(context, &event->jhat);
272	}
273}