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