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}