src/platform/sdl/sdl-events.c (view raw)
1#include "sdl-events.h"
2
3#include "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 break;
111#endif
112 case SDLK_p:
113 GBAThreadTogglePause(context);
114 break;
115 case SDLK_n:
116 GBAThreadPause(context);
117 context->frameCallback = _pauseAfterFrame;
118 GBAThreadUnpause(context);
119 break;
120 default:
121 break;
122 }
123 }
124 if (event->keysym.mod & KMOD_SHIFT) {
125 switch (event->keysym.sym) {
126 case SDLK_F1:
127 case SDLK_F2:
128 case SDLK_F3:
129 case SDLK_F4:
130 case SDLK_F5:
131 case SDLK_F6:
132 case SDLK_F7:
133 case SDLK_F8:
134 case SDLK_F9:
135 case SDLK_F10:
136 GBAThreadInterrupt(context);
137 GBASaveState(context->gba, event->keysym.sym - SDLK_F1);
138 GBAThreadContinue(context);
139 break;
140 default:
141 break;
142 }
143 } else {
144 switch (event->keysym.sym) {
145 case SDLK_F1:
146 case SDLK_F2:
147 case SDLK_F3:
148 case SDLK_F4:
149 case SDLK_F5:
150 case SDLK_F6:
151 case SDLK_F7:
152 case SDLK_F8:
153 case SDLK_F9:
154 case SDLK_F10:
155 GBAThreadInterrupt(context);
156 GBALoadState(context->gba, event->keysym.sym - SDLK_F1);
157 GBAThreadContinue(context);
158 break;
159 default:
160 break;
161 }
162 }
163 }
164 return;
165 }
166
167 if (event->type == SDL_KEYDOWN) {
168 context->activeKeys |= 1 << key;
169 } else {
170 context->activeKeys &= ~(1 << key);
171 }
172}
173
174static void _GBASDLHandleJoyButton(struct GBAThread* context, const struct SDL_JoyButtonEvent* event) {
175 enum GBAKey key = 0;
176 key = GBASDLMapButtonToKey(event->button);
177 if (key == GBA_KEY_NONE) {
178 return;
179 }
180
181 if (event->type == SDL_JOYBUTTONDOWN) {
182 context->activeKeys |= 1 << key;
183 } else {
184 context->activeKeys &= ~(1 << key);
185 }
186}
187
188static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
189 enum GBAKey key = 0;
190
191 if (event->value & SDL_HAT_UP) {
192 key |= 1 << GBA_KEY_UP;
193 }
194 if (event->value & SDL_HAT_LEFT) {
195 key |= 1 << GBA_KEY_LEFT;
196 }
197 if (event->value & SDL_HAT_DOWN) {
198 key |= 1 << GBA_KEY_DOWN;
199 }
200 if (event->value & SDL_HAT_RIGHT) {
201 key |= 1 << GBA_KEY_RIGHT;
202 }
203
204 context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
205 context->activeKeys |= key;
206}
207
208void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
209 switch (event->type) {
210 case SDL_QUIT:
211 // FIXME: this isn't thread-safe
212 if (context->debugger) {
213 context->debugger->state = DEBUGGER_EXITING;
214 }
215 MutexLock(&context->stateMutex);
216 context->state = THREAD_EXITING;
217 ConditionWake(&context->stateCond);
218 MutexUnlock(&context->stateMutex);
219 break;
220 case SDL_KEYDOWN:
221 case SDL_KEYUP:
222 _GBASDLHandleKeypress(context, sdlContext, &event->key);
223 break;
224 case SDL_JOYBUTTONDOWN:
225 case SDL_JOYBUTTONUP:
226 _GBASDLHandleJoyButton(context, &event->jbutton);
227 break;
228 case SDL_JOYHATMOTION:
229 _GBASDLHandleJoyHat(context, &event->jhat);
230 }
231}