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