all repos — mgba @ e9a2b2a57c4f478fb3600fe9d87e1b97804d73de

mGBA Game Boy Advance Emulator

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

  1/* Copyright (c) 2013-2014 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "sdl-events.h"
  7
  8#include "debugger/debugger.h"
  9#include "gba-io.h"
 10#include "gba-rr.h"
 11#include "gba-serialize.h"
 12#include "gba-video.h"
 13#include "renderers/video-software.h"
 14#include "util/vfs.h"
 15
 16#if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__)
 17#define GUI_MOD KMOD_GUI
 18#else
 19#define GUI_MOD KMOD_CTRL
 20#endif
 21
 22static int _openContexts = 0;
 23
 24bool GBASDLInitEvents(struct GBASDLEvents* context) {
 25	if (!_openContexts && SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
 26		return false;
 27	}
 28	++_openContexts;
 29	SDL_JoystickEventState(SDL_ENABLE);
 30	context->joystick = SDL_JoystickOpen(0);
 31#if !SDL_VERSION_ATLEAST(2, 0, 0)
 32	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 33#endif
 34	return true;
 35}
 36
 37void GBASDLInitBindings(struct GBAInputMap* inputMap) {
 38#if SDL_VERSION_ATLEAST(2, 0, 0)
 39	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_X, GBA_KEY_A);
 40	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_Z, GBA_KEY_B);
 41	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_A, GBA_KEY_L);
 42	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_S, GBA_KEY_R);
 43	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RETURN, GBA_KEY_START);
 44	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_BACKSPACE, GBA_KEY_SELECT);
 45	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_UP, GBA_KEY_UP);
 46	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_DOWN, GBA_KEY_DOWN);
 47	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_LEFT, GBA_KEY_LEFT);
 48	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RIGHT, GBA_KEY_RIGHT);
 49#else
 50	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_x, GBA_KEY_A);
 51	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_z, GBA_KEY_B);
 52	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_a, GBA_KEY_L);
 53	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_s, GBA_KEY_R);
 54	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RETURN, GBA_KEY_START);
 55	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_BACKSPACE, GBA_KEY_SELECT);
 56	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP);
 57	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN);
 58	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT);
 59	GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT);
 60#endif
 61
 62	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 13, GBA_KEY_A);
 63	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 14, GBA_KEY_B);
 64	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 10, GBA_KEY_L);
 65	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 11, GBA_KEY_R);
 66	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 3, GBA_KEY_START);
 67	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 0, GBA_KEY_SELECT);
 68	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 4, GBA_KEY_UP);
 69	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN);
 70	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT);
 71	GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 5, GBA_KEY_RIGHT);
 72
 73	struct GBAAxis description = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x4000, -0x4000 };
 74	GBAInputBindAxis(inputMap, SDL_BINDING_BUTTON, 0, &description);
 75	description = (struct GBAAxis) { GBA_KEY_DOWN, GBA_KEY_UP, 0x4000, -0x4000 };
 76	GBAInputBindAxis(inputMap, SDL_BINDING_BUTTON, 1, &description);
 77}
 78
 79void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) {
 80	GBAInputMapLoad(context->bindings, SDL_BINDING_KEY, config);
 81	GBAInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config);
 82}
 83
 84void GBASDLDeinitEvents(struct GBASDLEvents* context) {
 85	SDL_JoystickClose(context->joystick);
 86
 87	--_openContexts;
 88	if (!_openContexts) {
 89		SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
 90	}
 91}
 92
 93static void _pauseAfterFrame(struct GBAThread* context) {
 94	context->frameCallback = 0;
 95	GBAThreadPauseFromThread(context);
 96}
 97
 98static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
 99	enum GBAKey key = GBA_KEY_NONE;
100	if (!event->keysym.mod) {
101#if SDL_VERSION_ATLEAST(2, 0, 0)
102		key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.scancode);
103#else
104		key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.sym);
105#endif
106	}
107	if (key != GBA_KEY_NONE) {
108		if (event->type == SDL_KEYDOWN) {
109			context->activeKeys |= 1 << key;
110		} else {
111			context->activeKeys &= ~(1 << key);
112		}
113		return;
114	}
115	if (event->keysym.sym == SDLK_TAB) {
116		context->sync.audioWait = event->type != SDL_KEYDOWN;
117		return;
118	}
119	if (event->type == SDL_KEYDOWN) {
120		switch (event->keysym.sym) {
121		case SDLK_F11:
122			if (context->debugger) {
123				ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL, 0);
124			}
125			return;
126#ifdef USE_PNG
127		case SDLK_F12:
128			GBAThreadInterrupt(context);
129			GBAThreadTakeScreenshot(context);
130			GBAThreadContinue(context);
131			return;
132#endif
133		case SDLK_BACKSLASH:
134			GBAThreadPause(context);
135			context->frameCallback = _pauseAfterFrame;
136			GBAThreadUnpause(context);
137			return;
138		case SDLK_BACKQUOTE:
139			GBAThreadInterrupt(context);
140			GBARewind(context, 10);
141			GBAThreadContinue(context);
142			return;
143		case SDLK_ESCAPE:
144			GBAThreadInterrupt(context);
145			if (context->gba->rr) {
146				GBARRStopPlaying(context->gba->rr);
147				GBARRStopRecording(context->gba->rr);
148			}
149			GBAThreadContinue(context);
150			return;
151		default:
152			if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) {
153				switch (event->keysym.sym) {
154#if SDL_VERSION_ATLEAST(2, 0, 0)
155				case SDLK_f:
156					SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
157					sdlContext->fullscreen = !sdlContext->fullscreen;
158					sdlContext->windowUpdated = 1;
159					break;
160#endif
161				case SDLK_p:
162					GBAThreadTogglePause(context);
163					break;
164				case SDLK_n:
165					GBAThreadPause(context);
166					context->frameCallback = _pauseAfterFrame;
167					GBAThreadUnpause(context);
168					break;
169				case SDLK_r:
170					GBAThreadReset(context);
171					break;
172				case SDLK_t:
173					if (context->stateDir) {
174						GBAThreadInterrupt(context);
175						GBARRContextCreate(context->gba);
176						if (!GBARRIsRecording(context->gba->rr)) {
177							GBARRStopPlaying(context->gba->rr);
178							GBARRInitStream(context->gba->rr, context->stateDir);
179							GBARRReinitStream(context->gba->rr, INIT_EX_NIHILO);
180							GBARRStartRecording(context->gba->rr);
181							GBARRSaveState(context->gba);
182						}
183						GBAThreadContinue(context);
184					}
185					break;
186				case SDLK_y:
187					if (context->stateDir) {
188						GBAThreadInterrupt(context);
189						GBARRContextCreate(context->gba);
190						GBARRStopRecording(context->gba->rr);
191						GBARRInitStream(context->gba->rr, context->stateDir);
192						GBARRStartPlaying(context->gba->rr, false);
193						GBARRLoadState(context->gba);
194						GBAThreadContinue(context);
195					}
196					break;
197				default:
198					break;
199				}
200			}
201			if (event->keysym.mod & KMOD_SHIFT) {
202				switch (event->keysym.sym) {
203				case SDLK_F1:
204				case SDLK_F2:
205				case SDLK_F3:
206				case SDLK_F4:
207				case SDLK_F5:
208				case SDLK_F6:
209				case SDLK_F7:
210				case SDLK_F8:
211				case SDLK_F9:
212					GBAThreadInterrupt(context);
213					GBASaveState(context, context->stateDir, event->keysym.sym - SDLK_F1 + 1, true);
214					GBAThreadContinue(context);
215					break;
216				default:
217					break;
218				}
219			} else {
220				switch (event->keysym.sym) {
221				case SDLK_F1:
222				case SDLK_F2:
223				case SDLK_F3:
224				case SDLK_F4:
225				case SDLK_F5:
226				case SDLK_F6:
227				case SDLK_F7:
228				case SDLK_F8:
229				case SDLK_F9:
230					GBAThreadInterrupt(context);
231					GBALoadState(context, context->stateDir, event->keysym.sym - SDLK_F1 + 1);
232					GBAThreadContinue(context);
233					break;
234				default:
235					break;
236				}
237			}
238			return;
239		}
240	}
241}
242
243static void _GBASDLHandleJoyButton(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_JoyButtonEvent* event) {
244	enum GBAKey key = 0;
245	key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_BUTTON, event->button);
246	if (key == GBA_KEY_NONE) {
247		return;
248	}
249
250	if (event->type == SDL_JOYBUTTONDOWN) {
251		context->activeKeys |= 1 << key;
252	} else {
253		context->activeKeys &= ~(1 << key);
254	}
255}
256
257static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
258	enum GBAKey key = 0;
259
260	if (event->value & SDL_HAT_UP) {
261		key |= 1 << GBA_KEY_UP;
262	}
263	if (event->value & SDL_HAT_LEFT) {
264		key |= 1 << GBA_KEY_LEFT;
265	}
266	if (event->value & SDL_HAT_DOWN) {
267		key |= 1 << GBA_KEY_DOWN;
268	}
269	if (event->value & SDL_HAT_RIGHT) {
270		key |= 1 << GBA_KEY_RIGHT;
271	}
272
273	context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
274	context->activeKeys |= key;
275}
276
277static void _GBASDLHandleJoyAxis(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_JoyAxisEvent* event) {
278	int keys = context->activeKeys;
279
280	keys = GBAInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, keys);
281	enum GBAKey key = GBAInputMapAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, event->value);
282	if (key != GBA_KEY_NONE) {
283		keys |= 1 << key;
284	}
285
286	context->activeKeys = keys;
287}
288
289#if SDL_VERSION_ATLEAST(2, 0, 0)
290static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
291	UNUSED(context);
292	switch (event->event) {
293	case SDL_WINDOWEVENT_SIZE_CHANGED:
294		sdlContext->windowUpdated = 1;
295		break;
296	}
297}
298#endif
299
300void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
301	switch (event->type) {
302	case SDL_QUIT:
303		GBAThreadEnd(context);
304		break;
305#if SDL_VERSION_ATLEAST(2, 0, 0)
306	case SDL_WINDOWEVENT:
307		_GBASDLHandleWindowEvent(context, sdlContext, &event->window);
308		break;
309#endif
310	case SDL_KEYDOWN:
311	case SDL_KEYUP:
312		_GBASDLHandleKeypress(context, sdlContext, &event->key);
313		break;
314	case SDL_JOYBUTTONDOWN:
315	case SDL_JOYBUTTONUP:
316		_GBASDLHandleJoyButton(context, sdlContext, &event->jbutton);
317		break;
318	case SDL_JOYHATMOTION:
319		_GBASDLHandleJoyHat(context, &event->jhat);
320		break;
321	case SDL_JOYAXISMOTION:
322		_GBASDLHandleJoyAxis(context, sdlContext, &event->jaxis);
323		break;
324	}
325}