all repos — mgba @ d75042ea38fbffafdd53d2827421ab4470b47737

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