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