all repos — mgba @ 5eb729faf654e96ff6f223605af88f6b0f6dad56

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