all repos — mgba @ a3fff6d1a5a93bd7eb36f174d498ccf1770cb26e

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, SDL_SCANCODE_X, GBA_KEY_A);
 28	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_Z, GBA_KEY_B);
 29	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_A, GBA_KEY_L);
 30	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_S, GBA_KEY_R);
 31	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_RETURN, GBA_KEY_START);
 32	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_BACKSPACE, GBA_KEY_SELECT);
 33	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_UP, GBA_KEY_UP);
 34	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_DOWN, GBA_KEY_DOWN);
 35	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_LEFT, GBA_KEY_LEFT);
 36	GBAInputBindKey(context->bindings, SDL_BINDING_KEY, SDL_SCANCODE_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
 49	return true;
 50}
 51
 52void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) {
 53	GBAInputMapLoad(context->bindings, SDL_BINDING_KEY, config);
 54	GBAInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config);
 55}
 56
 57void GBASDLDeinitEvents(struct GBASDLEvents* context) {
 58	SDL_JoystickClose(context->joystick);
 59	SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
 60}
 61
 62static void _pauseAfterFrame(struct GBAThread* context) {
 63	context->frameCallback = 0;
 64	GBAThreadPauseFromThread(context);
 65}
 66
 67static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
 68	enum GBAKey key = GBA_KEY_NONE;
 69	if (!event->keysym.mod) {
 70		key = GBAInputMapKey(&context->inputMap, SDL_BINDING_KEY, event->keysym.scancode);
 71	}
 72	if (key != GBA_KEY_NONE) {
 73		if (event->type == SDL_KEYDOWN) {
 74			context->activeKeys |= 1 << key;
 75		} else {
 76			context->activeKeys &= ~(1 << key);
 77		}
 78		return;
 79	}
 80	switch (event->keysym.sym) {
 81	case SDLK_F11:
 82		if (event->type == SDL_KEYDOWN && context->debugger) {
 83			ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL);
 84		}
 85		return;
 86#ifdef USE_PNG
 87	case SDLK_F12:
 88		if (event->type == SDL_KEYDOWN) {
 89			GBAThreadInterrupt(context);
 90			GBAThreadTakeScreenshot(context);
 91			GBAThreadContinue(context);
 92		}
 93		return;
 94#endif
 95	case SDLK_TAB:
 96		context->sync.audioWait = event->type != SDL_KEYDOWN;
 97		return;
 98	case SDLK_BACKSLASH:
 99		if (event->type == SDL_KEYDOWN) {
100			GBAThreadPause(context);
101			context->frameCallback = _pauseAfterFrame;
102			GBAThreadUnpause(context);
103		}
104		return;
105	case SDLK_LEFTBRACKET:
106		GBAThreadInterrupt(context);
107		GBARewind(context, 10);
108		GBAThreadContinue(context);
109		return;
110	case SDLK_ESCAPE:
111		GBAThreadInterrupt(context);
112		if (context->gba->rr) {
113			GBARRStopPlaying(context->gba->rr);
114			GBARRStopRecording(context->gba->rr);
115		}
116		GBAThreadContinue(context);
117		return;
118	default:
119		if (event->type == SDL_KEYDOWN) {
120			if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) {
121				switch (event->keysym.sym) {
122#if SDL_VERSION_ATLEAST(2, 0, 0)
123				case SDLK_f:
124					SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
125					sdlContext->fullscreen = !sdlContext->fullscreen;
126					sdlContext->windowUpdated = 1;
127					break;
128#endif
129				case SDLK_p:
130					GBAThreadTogglePause(context);
131					break;
132				case SDLK_n:
133					GBAThreadPause(context);
134					context->frameCallback = _pauseAfterFrame;
135					GBAThreadUnpause(context);
136					break;
137				case SDLK_r:
138					GBAThreadReset(context);
139					break;
140				case SDLK_t:
141					if (context->stateDir) {
142						GBAThreadInterrupt(context);
143						GBARRContextCreate(context->gba);
144						if (!GBARRIsRecording(context->gba->rr)) {
145							GBARRStopPlaying(context->gba->rr);
146							GBARRInitStream(context->gba->rr, context->stateDir);
147							GBARRReinitStream(context->gba->rr, INIT_EX_NIHILO);
148							GBARRStartRecording(context->gba->rr);
149							GBARRSaveState(context->gba);
150						}
151						GBAThreadContinue(context);
152					}
153					break;
154				case SDLK_y:
155					if (context->stateDir) {
156						GBAThreadInterrupt(context);
157						GBARRContextCreate(context->gba);
158						GBARRStopRecording(context->gba->rr);
159						GBARRInitStream(context->gba->rr, context->stateDir);
160						GBARRStartPlaying(context->gba->rr, false);
161						GBARRLoadState(context->gba);
162						GBAThreadContinue(context);
163					}
164					break;
165				default:
166					break;
167				}
168			}
169			if (event->keysym.mod & KMOD_SHIFT) {
170				switch (event->keysym.sym) {
171				case SDLK_F1:
172				case SDLK_F2:
173				case SDLK_F3:
174				case SDLK_F4:
175				case SDLK_F5:
176				case SDLK_F6:
177				case SDLK_F7:
178				case SDLK_F8:
179				case SDLK_F9:
180					GBAThreadInterrupt(context);
181					GBASaveState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1 + 1, true);
182					GBAThreadContinue(context);
183					break;
184				default:
185					break;
186				}
187			} else {
188				switch (event->keysym.sym) {
189				case SDLK_F1:
190				case SDLK_F2:
191				case SDLK_F3:
192				case SDLK_F4:
193				case SDLK_F5:
194				case SDLK_F6:
195				case SDLK_F7:
196				case SDLK_F8:
197				case SDLK_F9:
198					GBAThreadInterrupt(context);
199					GBALoadState(context->gba, context->stateDir, event->keysym.sym - SDLK_F1 + 1);
200					GBAThreadContinue(context);
201					break;
202				default:
203					break;
204				}
205			}
206		}
207		return;
208	}
209}
210
211static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) {
212	enum GBAKey key = 0;
213	key = GBAInputMapKey(&context->inputMap, SDL_BINDING_BUTTON, event->button);
214	if (key == GBA_KEY_NONE) {
215		return;
216	}
217
218	if (event->type == SDL_JOYBUTTONDOWN) {
219		context->activeKeys |= 1 << key;
220	} else {
221		context->activeKeys &= ~(1 << key);
222	}
223}
224
225static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
226	enum GBAKey key = 0;
227
228	if (event->value & SDL_HAT_UP) {
229		key |= 1 << GBA_KEY_UP;
230	}
231	if (event->value & SDL_HAT_LEFT) {
232		key |= 1 << GBA_KEY_LEFT;
233	}
234	if (event->value & SDL_HAT_DOWN) {
235		key |= 1 << GBA_KEY_DOWN;
236	}
237	if (event->value & SDL_HAT_RIGHT) {
238		key |= 1 << GBA_KEY_RIGHT;
239	}
240
241	context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
242	context->activeKeys |= key;
243}
244
245#if SDL_VERSION_ATLEAST(2, 0, 0)
246static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
247	UNUSED(context);
248	switch (event->event) {
249	case SDL_WINDOWEVENT_SIZE_CHANGED:
250		sdlContext->windowUpdated = 1;
251		break;
252	}
253}
254#endif
255
256void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
257	switch (event->type) {
258	case SDL_QUIT:
259		GBAThreadEnd(context);
260		break;
261#if SDL_VERSION_ATLEAST(2, 0, 0)
262	case SDL_WINDOWEVENT:
263		_GBASDLHandleWindowEvent(context, sdlContext, &event->window);
264		break;
265#endif
266	case SDL_KEYDOWN:
267	case SDL_KEYUP:
268		_GBASDLHandleKeypress(context, sdlContext, &event->key);
269		break;
270	case SDL_JOYBUTTONDOWN:
271	case SDL_JOYBUTTONUP:
272		_GBASDLHandleJoyButton(context, &event->jbutton);
273		break;
274	case SDL_JOYHATMOTION:
275		_GBASDLHandleJoyHat(context, &event->jhat);
276	}
277}