all repos — mgba @ 5a17030c65e663cd6d3f9be710c658333f207add

mGBA Game Boy Advance Emulator

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

  1#include "sdl-events.h"
  2
  3#include "debugger.h"
  4#include "gba-io.h"
  5#include "gba-serialize.h"
  6#include "gba-video.h"
  7
  8#if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__)
  9#define GUI_MOD KMOD_GUI
 10#else
 11#define GUI_MOD KMOD_CTRL
 12#endif
 13
 14int GBASDLInitEvents(struct GBASDLEvents* context) {
 15	if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
 16		return 0;
 17	}
 18	SDL_JoystickEventState(SDL_ENABLE);
 19	context->joystick = SDL_JoystickOpen(0);
 20#if !SDL_VERSION_ATLEAST(2, 0, 0)
 21	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 22#endif
 23	return 1;
 24}
 25
 26void GBASDLDeinitEvents(struct GBASDLEvents* context) {
 27	SDL_JoystickClose(context->joystick);
 28	SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
 29}
 30
 31static void _pauseAfterFrame(struct GBAThread* context) {
 32	context->frameCallback = 0;
 33	GBAThreadPause(context);
 34}
 35
 36static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
 37	enum GBAKey key = 0;
 38	int isPaused = GBAThreadIsPaused(context);
 39	switch (event->keysym.sym) {
 40	case SDLK_z:
 41		key = GBA_KEY_A;
 42		break;
 43	case SDLK_x:
 44		key = GBA_KEY_B;
 45		break;
 46	case SDLK_a:
 47		key = GBA_KEY_L;
 48		break;
 49	case SDLK_s:
 50		key = GBA_KEY_R;
 51		break;
 52	case SDLK_RETURN:
 53		key = GBA_KEY_START;
 54		break;
 55	case SDLK_BACKSPACE:
 56		key = GBA_KEY_SELECT;
 57		break;
 58	case SDLK_UP:
 59		key = GBA_KEY_UP;
 60		break;
 61	case SDLK_DOWN:
 62		key = GBA_KEY_DOWN;
 63		break;
 64	case SDLK_LEFT:
 65		key = GBA_KEY_LEFT;
 66		break;
 67	case SDLK_RIGHT:
 68		key = GBA_KEY_RIGHT;
 69		break;
 70	case SDLK_F11:
 71		if (event->type == SDL_KEYDOWN && context->debugger) {
 72			ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL);
 73		}
 74		break;
 75	case SDLK_TAB:
 76		context->sync.audioWait = event->type != SDL_KEYDOWN;
 77		return;
 78	case SDLK_LEFTBRACKET:
 79		if (!isPaused) {
 80			GBAThreadPause(context);
 81		}
 82		GBARewind(context, 10);
 83		if (!isPaused) {
 84			GBAThreadUnpause(context);
 85		}
 86	default:
 87		if (event->type == SDL_KEYDOWN) {
 88			if (event->keysym.mod & GUI_MOD) {
 89				switch (event->keysym.sym) {
 90#if SDL_VERSION_ATLEAST(2, 0, 0)
 91				case SDLK_f:
 92					SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
 93					sdlContext->fullscreen = !sdlContext->fullscreen;
 94					break;
 95#endif
 96				case SDLK_p:
 97					GBAThreadTogglePause(context);
 98					break;
 99				case SDLK_n:
100					GBAThreadPause(context);
101					context->frameCallback = _pauseAfterFrame;
102					GBAThreadUnpause(context);
103					break;
104				default:
105					break;
106				}
107			}
108			if (event->keysym.mod & KMOD_SHIFT) {
109				switch (event->keysym.sym) {
110				case SDLK_F1:
111				case SDLK_F2:
112				case SDLK_F3:
113				case SDLK_F4:
114				case SDLK_F5:
115				case SDLK_F6:
116				case SDLK_F7:
117				case SDLK_F8:
118				case SDLK_F9:
119				case SDLK_F10:
120					if (!isPaused) {
121						GBAThreadPause(context);
122					}
123					GBASaveState(context->gba, event->keysym.sym - SDLK_F1);
124					if (!isPaused) {
125						GBAThreadUnpause(context);
126					}
127					break;
128				default:
129					break;
130				}
131			} else {
132				switch (event->keysym.sym) {
133				case SDLK_F1:
134				case SDLK_F2:
135				case SDLK_F3:
136				case SDLK_F4:
137				case SDLK_F5:
138				case SDLK_F6:
139				case SDLK_F7:
140				case SDLK_F8:
141				case SDLK_F9:
142				case SDLK_F10:
143					if (!isPaused) {
144						GBAThreadPause(context);
145					}
146					GBALoadState(context->gba, event->keysym.sym - SDLK_F1);
147					if (!isPaused) {
148						GBAThreadUnpause(context);
149					}
150					break;
151				default:
152					break;
153				}
154			}
155		}
156		return;
157	}
158
159	if (event->type == SDL_KEYDOWN) {
160		context->activeKeys |= 1 << key;
161	} else {
162		context->activeKeys &= ~(1 << key);
163	}
164}
165
166static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) {
167	enum GBAKey key = 0;
168	// Sorry, hardcoded to my gamepad for now
169	switch (event->button) {
170	case 2:
171		key = GBA_KEY_A;
172		break;
173	case 1:
174		key = GBA_KEY_B;
175		break;
176	case 6:
177		key = GBA_KEY_L;
178		break;
179	case 7:
180		key = GBA_KEY_R;
181		break;
182	case 8:
183		key = GBA_KEY_START;
184		break;
185	case 9:
186		key = GBA_KEY_SELECT;
187		break;
188	default:
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
219void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
220	switch (event->type) {
221	case SDL_QUIT:
222		// FIXME: this isn't thread-safe
223		if (context->debugger) {
224			context->debugger->state = DEBUGGER_EXITING;
225		}
226		MutexLock(&context->stateMutex);
227		context->state = THREAD_EXITING;
228		ConditionWake(&context->stateCond);
229		MutexUnlock(&context->stateMutex);
230		break;
231	case SDL_KEYDOWN:
232	case SDL_KEYUP:
233		_GBASDLHandleKeypress(context, sdlContext, &event->key);
234		break;
235	case SDL_JOYBUTTONDOWN:
236	case SDL_JOYBUTTONUP:
237		_GBASDLHandleJoyButton(context, &event->jbutton);
238		break;
239	case SDL_JOYHATMOTION:
240		_GBASDLHandleJoyHat(context, &event->jhat);
241	}
242}