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-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
31enum GBAKey GBASDLMapButtonToKey(int button) {
32 // Sorry, hardcoded to my gamepad for now
33 switch (button) {
34 case 2:
35 return GBA_KEY_A;
36 case 1:
37 return GBA_KEY_B;
38 case 6:
39 return GBA_KEY_L;
40 case 7:
41 return GBA_KEY_R;
42 case 8:
43 return GBA_KEY_START;
44 case 9:
45 return GBA_KEY_SELECT;
46 default:
47 return GBA_KEY_NONE;
48 }
49}
50
51static void _pauseAfterFrame(struct GBAThread* context) {
52 context->frameCallback = 0;
53 GBAThreadPause(context);
54}
55
56static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
57 enum GBAKey key = 0;
58 switch (event->keysym.sym) {
59 case SDLK_z:
60 key = GBA_KEY_A;
61 break;
62 case SDLK_x:
63 key = GBA_KEY_B;
64 break;
65 case SDLK_a:
66 key = GBA_KEY_L;
67 break;
68 case SDLK_s:
69 key = GBA_KEY_R;
70 break;
71 case SDLK_RETURN:
72 key = GBA_KEY_START;
73 break;
74 case SDLK_BACKSPACE:
75 key = GBA_KEY_SELECT;
76 break;
77 case SDLK_UP:
78 key = GBA_KEY_UP;
79 break;
80 case SDLK_DOWN:
81 key = GBA_KEY_DOWN;
82 break;
83 case SDLK_LEFT:
84 key = GBA_KEY_LEFT;
85 break;
86 case SDLK_RIGHT:
87 key = GBA_KEY_RIGHT;
88 break;
89 case SDLK_F11:
90 if (event->type == SDL_KEYDOWN && context->debugger) {
91 ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL);
92 }
93 return;
94 case SDLK_TAB:
95 context->sync.audioWait = event->type != SDL_KEYDOWN;
96 return;
97 case SDLK_LEFTBRACKET:
98 GBAThreadInterrupt(context);
99 GBARewind(context, 10);
100 GBAThreadContinue(context);
101 return;
102 default:
103 if (event->type == SDL_KEYDOWN) {
104 if (event->keysym.mod & GUI_MOD) {
105 switch (event->keysym.sym) {
106#if SDL_VERSION_ATLEAST(2, 0, 0)
107 case SDLK_f:
108 SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
109 sdlContext->fullscreen = !sdlContext->fullscreen;
110 sdlContext->windowUpdated = 1;
111 break;
112#endif
113 case SDLK_p:
114 GBAThreadTogglePause(context);
115 break;
116 case SDLK_n:
117 GBAThreadPause(context);
118 context->frameCallback = _pauseAfterFrame;
119 GBAThreadUnpause(context);
120 break;
121 case SDLK_r:
122 GBAThreadReset(context);
123 break;
124 default:
125 break;
126 }
127 }
128 if (event->keysym.mod & KMOD_SHIFT) {
129 switch (event->keysym.sym) {
130 case SDLK_F1:
131 case SDLK_F2:
132 case SDLK_F3:
133 case SDLK_F4:
134 case SDLK_F5:
135 case SDLK_F6:
136 case SDLK_F7:
137 case SDLK_F8:
138 case SDLK_F9:
139 case SDLK_F10:
140 GBAThreadInterrupt(context);
141 GBASaveState(context->gba, event->keysym.sym - SDLK_F1);
142 GBAThreadContinue(context);
143 break;
144 default:
145 break;
146 }
147 } else {
148 switch (event->keysym.sym) {
149 case SDLK_F1:
150 case SDLK_F2:
151 case SDLK_F3:
152 case SDLK_F4:
153 case SDLK_F5:
154 case SDLK_F6:
155 case SDLK_F7:
156 case SDLK_F8:
157 case SDLK_F9:
158 case SDLK_F10:
159 GBAThreadInterrupt(context);
160 GBALoadState(context->gba, event->keysym.sym - SDLK_F1);
161 GBAThreadContinue(context);
162 break;
163 default:
164 break;
165 }
166 }
167 }
168 return;
169 }
170
171 if (event->type == SDL_KEYDOWN) {
172 context->activeKeys |= 1 << key;
173 } else {
174 context->activeKeys &= ~(1 << key);
175 }
176}
177
178static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) {
179 enum GBAKey key = 0;
180 key = GBASDLMapButtonToKey(event->button);
181 if (key == GBA_KEY_NONE) {
182 return;
183 }
184
185 if (event->type == SDL_JOYBUTTONDOWN) {
186 context->activeKeys |= 1 << key;
187 } else {
188 context->activeKeys &= ~(1 << key);
189 }
190}
191
192static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
193 enum GBAKey key = 0;
194
195 if (event->value & SDL_HAT_UP) {
196 key |= 1 << GBA_KEY_UP;
197 }
198 if (event->value & SDL_HAT_LEFT) {
199 key |= 1 << GBA_KEY_LEFT;
200 }
201 if (event->value & SDL_HAT_DOWN) {
202 key |= 1 << GBA_KEY_DOWN;
203 }
204 if (event->value & SDL_HAT_RIGHT) {
205 key |= 1 << GBA_KEY_RIGHT;
206 }
207
208 context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
209 context->activeKeys |= key;
210}
211
212#if SDL_VERSION_ATLEAST(2, 0, 0)
213static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
214 UNUSED(context);
215 switch (event->event) {
216 case SDL_WINDOWEVENT_SIZE_CHANGED:
217 sdlContext->windowUpdated = 1;
218 break;
219 }
220}
221#endif
222
223void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
224 switch (event->type) {
225 case SDL_QUIT:
226 // FIXME: this isn't thread-safe
227 if (context->debugger) {
228 context->debugger->state = DEBUGGER_EXITING;
229 }
230 MutexLock(&context->stateMutex);
231 context->state = THREAD_EXITING;
232 ConditionWake(&context->stateCond);
233 MutexUnlock(&context->stateMutex);
234 break;
235#if SDL_VERSION_ATLEAST(2, 0, 0)
236 case SDL_WINDOWEVENT:
237 _GBASDLHandleWindowEvent(context, sdlContext, &event->window);
238 break;
239#endif
240 case SDL_KEYDOWN:
241 case SDL_KEYUP:
242 _GBASDLHandleKeypress(context, sdlContext, &event->key);
243 break;
244 case SDL_JOYBUTTONDOWN:
245 case SDL_JOYBUTTONUP:
246 _GBASDLHandleJoyButton(context, &event->jbutton);
247 break;
248 case SDL_JOYHATMOTION:
249 _GBASDLHandleJoyHat(context, &event->jhat);
250 }
251}