src/platform/sdl/sdl-events.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "sdl-events.h"
7
8#include "core/input.h"
9#include "core/serialize.h"
10#include "core/thread.h"
11#include "debugger/debugger.h"
12#include "gba/input.h"
13#include "gba/io.h"
14#include "gba/rr/rr.h"
15#include "gba/video.h"
16#include "gba/renderers/video-software.h"
17#include "util/configuration.h"
18#include "util/formatting.h"
19#include "util/vfs.h"
20
21#if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__)
22#define GUI_MOD KMOD_GUI
23#else
24#define GUI_MOD KMOD_CTRL
25#endif
26
27#define GYRO_STEPS 100
28#define RUMBLE_PWM 20
29
30mLOG_DEFINE_CATEGORY(SDL_EVENTS, "SDL Events");
31
32DEFINE_VECTOR(SDL_JoystickList, struct SDL_JoystickCombo);
33
34#if SDL_VERSION_ATLEAST(2, 0, 0)
35static void _mSDLSetRumble(struct mRumble* rumble, int enable);
36#endif
37static int32_t _mSDLReadTiltX(struct mRotationSource* rumble);
38static int32_t _mSDLReadTiltY(struct mRotationSource* rumble);
39static int32_t _mSDLReadGyroZ(struct mRotationSource* rumble);
40static void _mSDLRotationSample(struct mRotationSource* source);
41
42bool mSDLInitEvents(struct mSDLEvents* context) {
43#if SDL_VERSION_ATLEAST(2, 0, 4)
44 SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
45#endif
46 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
47 mLOG(SDL_EVENTS, ERROR, "SDL joystick initialization failed: %s", SDL_GetError());
48 }
49
50#if SDL_VERSION_ATLEAST(2, 0, 0)
51 SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
52 if (SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0) {
53 mLOG(SDL_EVENTS, ERROR, "SDL haptic initialization failed: %s", SDL_GetError());
54 }
55 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
56 mLOG(SDL_EVENTS, ERROR, "SDL video initialization failed: %s", SDL_GetError());
57 }
58#endif
59
60 SDL_JoystickEventState(SDL_ENABLE);
61 int nJoysticks = SDL_NumJoysticks();
62 SDL_JoystickListInit(&context->joysticks, nJoysticks);
63 if (nJoysticks > 0) {
64 mSDLUpdateJoysticks(context);
65 // Some OSes don't do hotplug detection
66 if (!SDL_JoystickListSize(&context->joysticks)) {
67 int i;
68 for (i = 0; i < nJoysticks; ++i) {
69 struct SDL_JoystickCombo* joystick = SDL_JoystickListAppend(&context->joysticks);
70 joystick->joystick = SDL_JoystickOpen(i);
71 joystick->index = SDL_JoystickListSize(&context->joysticks) - 1;
72#if SDL_VERSION_ATLEAST(2, 0, 0)
73 joystick->id = SDL_JoystickInstanceID(joystick->joystick);
74 joystick->haptic = SDL_HapticOpenFromJoystick(joystick->joystick);
75#else
76 joystick->id = SDL_JoystickIndex(joystick->joystick);
77#endif
78 }
79 }
80 }
81
82 context->playersAttached = 0;
83
84 size_t i;
85 for (i = 0; i < MAX_PLAYERS; ++i) {
86 context->preferredJoysticks[i] = 0;
87 }
88
89#if !SDL_VERSION_ATLEAST(2, 0, 0)
90 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
91#else
92 context->screensaverSuspendDepth = 0;
93#endif
94 return true;
95}
96
97void mSDLDeinitEvents(struct mSDLEvents* context) {
98 size_t i;
99 for (i = 0; i < SDL_JoystickListSize(&context->joysticks); ++i) {
100 struct SDL_JoystickCombo* joystick = SDL_JoystickListGetPointer(&context->joysticks, i);
101#if SDL_VERSION_ATLEAST(2, 0, 0)
102 SDL_HapticClose(joystick->haptic);
103#endif
104 SDL_JoystickClose(joystick->joystick);
105 }
106 SDL_JoystickListDeinit(&context->joysticks);
107 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
108}
109
110void mSDLEventsLoadConfig(struct mSDLEvents* context, const struct Configuration* config) {
111 context->preferredJoysticks[0] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 0);
112 context->preferredJoysticks[1] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 1);
113 context->preferredJoysticks[2] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 2);
114 context->preferredJoysticks[3] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 3);
115}
116
117void mSDLInitBindingsGBA(struct mInputMap* inputMap) {
118#ifdef BUILD_PANDORA
119 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_PAGEDOWN, GBA_KEY_A);
120 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_END, GBA_KEY_B);
121 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RSHIFT, GBA_KEY_L);
122 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RCTRL, GBA_KEY_R);
123 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LALT, GBA_KEY_START);
124 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LCTRL, GBA_KEY_SELECT);
125 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP);
126 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN);
127 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT);
128 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT);
129#elif SDL_VERSION_ATLEAST(2, 0, 0)
130 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_X, GBA_KEY_A);
131 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_Z, GBA_KEY_B);
132 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_A, GBA_KEY_L);
133 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_S, GBA_KEY_R);
134 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RETURN, GBA_KEY_START);
135 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_BACKSPACE, GBA_KEY_SELECT);
136 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_UP, GBA_KEY_UP);
137 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_DOWN, GBA_KEY_DOWN);
138 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_LEFT, GBA_KEY_LEFT);
139 mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RIGHT, GBA_KEY_RIGHT);
140#else
141 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_x, GBA_KEY_A);
142 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_z, GBA_KEY_B);
143 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_a, GBA_KEY_L);
144 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_s, GBA_KEY_R);
145 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RETURN, GBA_KEY_START);
146 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_BACKSPACE, GBA_KEY_SELECT);
147 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP);
148 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN);
149 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT);
150 mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT);
151#endif
152
153 struct mInputAxis description = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x4000, -0x4000 };
154 mInputBindAxis(inputMap, SDL_BINDING_BUTTON, 0, &description);
155 description = (struct mInputAxis) { GBA_KEY_DOWN, GBA_KEY_UP, 0x4000, -0x4000 };
156 mInputBindAxis(inputMap, SDL_BINDING_BUTTON, 1, &description);
157}
158
159bool mSDLAttachPlayer(struct mSDLEvents* events, struct mSDLPlayer* player) {
160 player->joystick = 0;
161
162 if (events->playersAttached >= MAX_PLAYERS) {
163 return false;
164 }
165
166#if SDL_VERSION_ATLEAST(2, 0, 0)
167 player->rumble.d.setRumble = _mSDLSetRumble;
168 CircleBufferInit(&player->rumble.history, RUMBLE_PWM);
169 player->rumble.level = 0;
170 player->rumble.p = player;
171#endif
172
173 player->rotation.d.readTiltX = _mSDLReadTiltX;
174 player->rotation.d.readTiltY = _mSDLReadTiltY;
175 player->rotation.d.readGyroZ = _mSDLReadGyroZ;
176 player->rotation.d.sample = _mSDLRotationSample;
177 player->rotation.axisX = 2;
178 player->rotation.axisY = 3;
179 player->rotation.gyroSensitivity = 2.2e9f;
180 player->rotation.gyroX = 0;
181 player->rotation.gyroY = 1;
182 player->rotation.zDelta = 0;
183 CircleBufferInit(&player->rotation.zHistory, sizeof(float) * GYRO_STEPS);
184 player->rotation.p = player;
185
186 player->playerId = events->playersAttached;
187 events->players[player->playerId] = player;
188 size_t firstUnclaimed = SIZE_MAX;
189 size_t index = SIZE_MAX;
190
191 size_t i;
192 for (i = 0; i < SDL_JoystickListSize(&events->joysticks); ++i) {
193 bool claimed = false;
194
195 int p;
196 for (p = 0; p < events->playersAttached; ++p) {
197 if (events->players[p]->joystick == SDL_JoystickListGetPointer(&events->joysticks, i)) {
198 claimed = true;
199 break;
200 }
201 }
202 if (claimed) {
203 continue;
204 }
205
206 if (firstUnclaimed == SIZE_MAX) {
207 firstUnclaimed = i;
208 }
209
210 const char* joystickName;
211#if SDL_VERSION_ATLEAST(2, 0, 0)
212 joystickName = SDL_JoystickName(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick);
213#else
214 joystickName = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick));
215#endif
216 if (events->preferredJoysticks[player->playerId] && strcmp(events->preferredJoysticks[player->playerId], joystickName) == 0) {
217 index = i;
218 break;
219 }
220 }
221
222 if (index == SIZE_MAX && firstUnclaimed != SIZE_MAX) {
223 index = firstUnclaimed;
224 }
225
226 if (index != SIZE_MAX) {
227 player->joystick = SDL_JoystickListGetPointer(&events->joysticks, index);
228
229#if SDL_VERSION_ATLEAST(2, 0, 0)
230 if (player->joystick->haptic) {
231 SDL_HapticRumbleInit(player->joystick->haptic);
232 }
233#endif
234 }
235
236 ++events->playersAttached;
237 return true;
238}
239
240void mSDLDetachPlayer(struct mSDLEvents* events, struct mSDLPlayer* player) {
241 if (player != events->players[player->playerId]) {
242 return;
243 }
244 int i;
245 for (i = player->playerId; i < events->playersAttached; ++i) {
246 if (i + 1 < MAX_PLAYERS) {
247 events->players[i] = events->players[i + 1];
248 }
249 if (i < events->playersAttached - 1) {
250 events->players[i]->playerId = i;
251 }
252 }
253 --events->playersAttached;
254 CircleBufferDeinit(&player->rotation.zHistory);
255}
256
257void mSDLPlayerLoadConfig(struct mSDLPlayer* context, const struct Configuration* config) {
258 mInputMapLoad(context->bindings, SDL_BINDING_KEY, config);
259 if (context->joystick) {
260 mInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config);
261#if SDL_VERSION_ATLEAST(2, 0, 0)
262 const char* name = SDL_JoystickName(context->joystick->joystick);
263#else
264 const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick->joystick));
265#endif
266 mInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, name);
267
268 const char* value;
269 char* end;
270 int numAxes = SDL_JoystickNumAxes(context->joystick->joystick);
271 int axis;
272 value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisX", name);
273 if (value) {
274 axis = strtol(value, &end, 0);
275 if (axis >= 0 && axis < numAxes && end && !*end) {
276 context->rotation.axisX = axis;
277 }
278 }
279 value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisY", name);
280 if (value) {
281 axis = strtol(value, &end, 0);
282 if (axis >= 0 && axis < numAxes && end && !*end) {
283 context->rotation.axisY = axis;
284 }
285 }
286 value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisX", name);
287 if (value) {
288 axis = strtol(value, &end, 0);
289 if (axis >= 0 && axis < numAxes && end && !*end) {
290 context->rotation.gyroX = axis;
291 }
292 }
293 value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisY", name);
294 if (value) {
295 axis = strtol(value, &end, 0);
296 if (axis >= 0 && axis < numAxes && end && !*end) {
297 context->rotation.gyroY = axis;
298 }
299 }
300 value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroSensitivity", name);
301 if (value) {
302 float sensitivity = strtof_u(value, &end);
303 if (end && !*end) {
304 context->rotation.gyroSensitivity = sensitivity;
305 }
306 }
307 }
308}
309
310void mSDLPlayerSaveConfig(const struct mSDLPlayer* context, struct Configuration* config) {
311 if (context->joystick) {
312#if SDL_VERSION_ATLEAST(2, 0, 0)
313 const char* name = SDL_JoystickName(context->joystick->joystick);
314#else
315 const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick->joystick));
316#endif
317 char value[12];
318 snprintf(value, sizeof(value), "%i", context->rotation.axisX);
319 mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisX", value, name);
320 snprintf(value, sizeof(value), "%i", context->rotation.axisY);
321 mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisY", value, name);
322 snprintf(value, sizeof(value), "%i", context->rotation.gyroX);
323 mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisX", value, name);
324 snprintf(value, sizeof(value), "%i", context->rotation.gyroY);
325 mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisY", value, name);
326 snprintf(value, sizeof(value), "%g", context->rotation.gyroSensitivity);
327 mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroSensitivity", value, name);
328 }
329}
330
331void mSDLPlayerChangeJoystick(struct mSDLEvents* events, struct mSDLPlayer* player, size_t index) {
332 if (player->playerId >= MAX_PLAYERS || index >= SDL_JoystickListSize(&events->joysticks)) {
333 return;
334 }
335 player->joystick = SDL_JoystickListGetPointer(&events->joysticks, index);
336}
337
338void mSDLUpdateJoysticks(struct mSDLEvents* events) {
339 // Pump SDL joystick events without eating the rest of the events
340 SDL_JoystickUpdate();
341#if SDL_VERSION_ATLEAST(2, 0, 0)
342 SDL_Event event;
343 while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED) > 0) {
344 if (event.type == SDL_JOYDEVICEADDED) {
345 struct SDL_JoystickCombo* joystick = SDL_JoystickListAppend(&events->joysticks);
346 joystick->joystick = SDL_JoystickOpen(event.jdevice.which);
347 joystick->id = SDL_JoystickInstanceID(joystick->joystick);
348 joystick->index = SDL_JoystickListSize(&events->joysticks) - 1;
349#if SDL_VERSION_ATLEAST(2, 0, 0)
350 joystick->haptic = SDL_HapticOpenFromJoystick(joystick->joystick);
351#endif
352 } else if (event.type == SDL_JOYDEVICEREMOVED) {
353 SDL_JoystickID ids[MAX_PLAYERS];
354 size_t i;
355 for (i = 0; (int) i < events->playersAttached; ++i) {
356 if (events->players[i]->joystick) {
357 ids[i] = events->players[i]->joystick->id;
358 events->players[i]->joystick = 0;
359 } else {
360 ids[i] = -1;
361 }
362 }
363 for (i = 0; i < SDL_JoystickListSize(&events->joysticks);) {
364 struct SDL_JoystickCombo* joystick = SDL_JoystickListGetPointer(&events->joysticks, i);
365 if (joystick->id == event.jdevice.which) {
366 SDL_JoystickListShift(&events->joysticks, i, 1);
367 continue;
368 }
369 SDL_JoystickListGetPointer(&events->joysticks, i)->index = i;
370 int p;
371 for (p = 0; p < events->playersAttached; ++p) {
372 if (joystick->id == ids[p]) {
373 events->players[p]->joystick = SDL_JoystickListGetPointer(&events->joysticks, i);
374 }
375 }
376 ++i;
377 }
378 }
379 }
380#endif
381}
382
383static void _pauseAfterFrame(struct mCoreThread* context) {
384 context->frameCallback = 0;
385 mCoreThreadPauseFromThread(context);
386}
387
388static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const struct SDL_KeyboardEvent* event) {
389 int key = -1;
390 if (!event->keysym.mod) {
391#if !defined(BUILD_PANDORA) && SDL_VERSION_ATLEAST(2, 0, 0)
392 key = mInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.scancode);
393#else
394 key = mInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.sym);
395#endif
396 }
397 if (key != -1) {
398 if (event->type == SDL_KEYDOWN) {
399 context->core->addKeys(context->core, 1 << key);
400 } else {
401 context->core->clearKeys(context->core, 1 << key);
402 }
403 return;
404 }
405 if (event->keysym.sym == SDLK_TAB) {
406 context->sync.audioWait = event->type != SDL_KEYDOWN;
407 return;
408 }
409 if (event->keysym.sym == SDLK_BACKQUOTE) {
410 mCoreThreadSetRewinding(context, event->type == SDL_KEYDOWN);
411 }
412 if (event->type == SDL_KEYDOWN) {
413 switch (event->keysym.sym) {
414 case SDLK_F11:
415 if (context->core->debugger) {
416 mDebuggerEnter(context->core->debugger, DEBUGGER_ENTER_MANUAL, NULL);
417 }
418 return;
419#ifdef USE_PNG
420 case SDLK_F12:
421 mCoreTakeScreenshot(context->core);
422 return;
423#endif
424 case SDLK_BACKSLASH:
425 mCoreThreadPause(context);
426 context->frameCallback = _pauseAfterFrame;
427 mCoreThreadUnpause(context);
428 return;
429#ifdef BUILD_PANDORA
430 case SDLK_ESCAPE:
431 mCoreThreadEnd(context);
432 return;
433#endif
434 default:
435 if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) {
436 switch (event->keysym.sym) {
437#if SDL_VERSION_ATLEAST(2, 0, 0)
438 case SDLK_f:
439 SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
440 sdlContext->fullscreen = !sdlContext->fullscreen;
441 sdlContext->windowUpdated = 1;
442 break;
443#endif
444 case SDLK_p:
445 mCoreThreadTogglePause(context);
446 break;
447 case SDLK_n:
448 mCoreThreadPause(context);
449 context->frameCallback = _pauseAfterFrame;
450 mCoreThreadUnpause(context);
451 break;
452 case SDLK_r:
453 mCoreThreadReset(context);
454 break;
455 default:
456 break;
457 }
458 }
459 if (event->keysym.mod & KMOD_SHIFT) {
460 switch (event->keysym.sym) {
461 case SDLK_F1:
462 case SDLK_F2:
463 case SDLK_F3:
464 case SDLK_F4:
465 case SDLK_F5:
466 case SDLK_F6:
467 case SDLK_F7:
468 case SDLK_F8:
469 case SDLK_F9:
470 mCoreThreadInterrupt(context);
471 mCoreSaveState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
472 mCoreThreadContinue(context);
473 break;
474 default:
475 break;
476 }
477 } else {
478 switch (event->keysym.sym) {
479 case SDLK_F1:
480 case SDLK_F2:
481 case SDLK_F3:
482 case SDLK_F4:
483 case SDLK_F5:
484 case SDLK_F6:
485 case SDLK_F7:
486 case SDLK_F8:
487 case SDLK_F9:
488 mCoreThreadInterrupt(context);
489 mCoreLoadState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
490 mCoreThreadContinue(context);
491 break;
492 default:
493 break;
494 }
495 }
496 return;
497 }
498 }
499}
500
501static void _mSDLHandleJoyButton(struct mCore* core, struct mSDLPlayer* sdlContext, const struct SDL_JoyButtonEvent* event) {
502 int key = 0;
503 key = mInputMapKey(sdlContext->bindings, SDL_BINDING_BUTTON, event->button);
504 if (key == -1) {
505 return;
506 }
507
508 if (event->type == SDL_JOYBUTTONDOWN) {
509 core->addKeys(core, 1 << key);
510 } else {
511 core->clearKeys(core, 1 << key);
512 }
513}
514
515static void _mSDLHandleJoyAxis(struct mCore* core, struct mSDLPlayer* sdlContext, const struct SDL_JoyAxisEvent* event) {
516 int clearKeys = ~mInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, -1);
517 int newKeys = 0;
518 int key = mInputMapAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, event->value);
519 if (key != -1) {
520 newKeys |= 1 << key;
521 }
522 clearKeys &= ~newKeys;
523 core->clearKeys(core, clearKeys);
524 core->addKeys(core, newKeys);
525
526}
527
528#if SDL_VERSION_ATLEAST(2, 0, 0)
529static void _mSDLHandleWindowEvent(struct mSDLPlayer* sdlContext, const struct SDL_WindowEvent* event) {
530 switch (event->event) {
531 case SDL_WINDOWEVENT_SIZE_CHANGED:
532 sdlContext->windowUpdated = 1;
533 break;
534 }
535}
536#endif
537
538void mSDLHandleEvent(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const union SDL_Event* event) {
539 switch (event->type) {
540 case SDL_QUIT:
541 mCoreThreadEnd(context);
542 break;
543#if SDL_VERSION_ATLEAST(2, 0, 0)
544 case SDL_WINDOWEVENT:
545 _mSDLHandleWindowEvent(sdlContext, &event->window);
546 break;
547#endif
548 case SDL_KEYDOWN:
549 case SDL_KEYUP:
550 _mSDLHandleKeypress(context, sdlContext, &event->key);
551 break;
552 case SDL_JOYBUTTONDOWN:
553 case SDL_JOYBUTTONUP:
554 _mSDLHandleJoyButton(context->core, sdlContext, &event->jbutton);
555 break;
556 case SDL_JOYHATMOTION:
557 // TODO
558 break;
559 case SDL_JOYAXISMOTION:
560 _mSDLHandleJoyAxis(context->core, sdlContext, &event->jaxis);
561 break;
562 }
563}
564
565#if SDL_VERSION_ATLEAST(2, 0, 0)
566static void _mSDLSetRumble(struct mRumble* rumble, int enable) {
567 struct mSDLRumble* sdlRumble = (struct mSDLRumble*) rumble;
568 if (!sdlRumble->p->joystick || !sdlRumble->p->joystick->haptic || !SDL_HapticRumbleSupported(sdlRumble->p->joystick->haptic)) {
569 return;
570 }
571 sdlRumble->level += enable;
572 if (CircleBufferSize(&sdlRumble->history) == RUMBLE_PWM) {
573 int8_t oldLevel;
574 CircleBufferRead8(&sdlRumble->history, &oldLevel);
575 sdlRumble->level -= oldLevel;
576 }
577 CircleBufferWrite8(&sdlRumble->history, enable);
578 if (sdlRumble->level) {
579 SDL_HapticRumblePlay(sdlRumble->p->joystick->haptic, sdlRumble->level / (float) RUMBLE_PWM, 20);
580 } else {
581 SDL_HapticRumbleStop(sdlRumble->p->joystick->haptic);
582 }
583}
584#endif
585
586static int32_t _readTilt(struct mSDLPlayer* player, int axis) {
587 if (!player->joystick) {
588 return 0;
589 }
590 return SDL_JoystickGetAxis(player->joystick->joystick, axis) * 0x3800;
591}
592
593static int32_t _mSDLReadTiltX(struct mRotationSource* source) {
594 struct mSDLRotation* rotation = (struct mSDLRotation*) source;
595 return _readTilt(rotation->p, rotation->axisX);
596}
597
598static int32_t _mSDLReadTiltY(struct mRotationSource* source) {
599 struct mSDLRotation* rotation = (struct mSDLRotation*) source;
600 return _readTilt(rotation->p, rotation->axisY);
601}
602
603static int32_t _mSDLReadGyroZ(struct mRotationSource* source) {
604 struct mSDLRotation* rotation = (struct mSDLRotation*) source;
605 float z = rotation->zDelta;
606 return z * rotation->gyroSensitivity;
607}
608
609static void _mSDLRotationSample(struct mRotationSource* source) {
610 struct mSDLRotation* rotation = (struct mSDLRotation*) source;
611 SDL_JoystickUpdate();
612 if (!rotation->p->joystick) {
613 return;
614 }
615
616 int x = SDL_JoystickGetAxis(rotation->p->joystick->joystick, rotation->gyroX);
617 int y = SDL_JoystickGetAxis(rotation->p->joystick->joystick, rotation->gyroY);
618 union {
619 float f;
620 int32_t i;
621 } theta = { .f = atan2f(y, x) - atan2f(rotation->oldY, rotation->oldX) };
622 if (isnan(theta.f)) {
623 theta.f = 0.0f;
624 } else if (theta.f > M_PI) {
625 theta.f -= 2.0f * M_PI;
626 } else if (theta.f < -M_PI) {
627 theta.f += 2.0f * M_PI;
628 }
629 rotation->oldX = x;
630 rotation->oldY = y;
631
632 float oldZ = 0;
633 if (CircleBufferSize(&rotation->zHistory) == GYRO_STEPS * sizeof(float)) {
634 CircleBufferRead32(&rotation->zHistory, (int32_t*) &oldZ);
635 }
636 CircleBufferWrite32(&rotation->zHistory, theta.i);
637 rotation->zDelta += theta.f - oldZ;
638}
639
640#if SDL_VERSION_ATLEAST(2, 0, 0)
641void mSDLSuspendScreensaver(struct mSDLEvents* events) {
642 if (events->screensaverSuspendDepth == 0 && events->screensaverSuspendable) {
643 SDL_DisableScreenSaver();
644 }
645 ++events->screensaverSuspendDepth;
646}
647
648void mSDLResumeScreensaver(struct mSDLEvents* events) {
649 --events->screensaverSuspendDepth;
650 if (events->screensaverSuspendDepth == 0 && events->screensaverSuspendable) {
651 SDL_EnableScreenSaver();
652 }
653}
654
655void mSDLSetScreensaverSuspendable(struct mSDLEvents* events, bool suspendable) {
656 bool wasSuspendable = events->screensaverSuspendable;
657 events->screensaverSuspendable = suspendable;
658 if (events->screensaverSuspendDepth > 0) {
659 if (suspendable && !wasSuspendable) {
660 SDL_DisableScreenSaver();
661 } else if (!suspendable && wasSuspendable) {
662 SDL_EnableScreenSaver();
663 }
664 } else {
665 SDL_EnableScreenSaver();
666 }
667}
668#endif