1 /*
2 * OpenBOR - http://www.chronocrash.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2019 OpenBOR Team
7 */
8
9 // Generic control stuff (keyboard+joystick)
10
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include "globals.h"
15 #include "control.h"
16 #include "openbor.h"
17 #include "List.h"
18
19 #define AXIS_THRESHOLD 7000
20
21 typedef enum {
22 DEVICE_TYPE_NONE,
23 DEVICE_TYPE_KEYBOARD,
24 DEVICE_TYPE_CONTROLLER, // XInput compatible controller
25 DEVICE_TYPE_JOYSTICK, // controller not compatible with XInput
26 } DeviceType;
27
28 typedef struct {
29 DeviceType deviceType;
30 char name[CONTROL_DEVICE_NAME_SIZE];
31 int mappings[SDID_COUNT];
32 SDL_Haptic *haptic;
33 union {
34 // no extra structure needed for keyboard
35 SDL_GameController *controller;
36 SDL_Joystick *joystick;
37 };
38 } InputDevice;
39
40 static InputDevice devices[MAX_DEVICES];
41 static bool controlInited = false;
42 static int keyboardDeviceID = -1;
43 static bool altEnterPressed = false;
44
45 // if non-null, device is being remapped in the input settings menu
46 static InputDevice *remapDevice = NULL;
47 static int remapKeycode = -1;
48
49 // each list member is an array of SDID_COUNT ints, dynamically allocated
50 static List savedMappings;
51 static bool savedMappingsInited = false;
52
53 #ifdef ANDROID
54 #define MAX_POINTERS 30
55 typedef enum
56 {
57 TOUCH_STATUS_UP,
58 TOUCH_STATUS_DOWN
59 } touch_status;
60
61 typedef struct TouchStatus {
62 float px[MAX_POINTERS];
63 float py[MAX_POINTERS];
64 SDL_FingerID pid[MAX_POINTERS];
65 touch_status pstatus[MAX_POINTERS];
66 } TouchStatus;
67
68 extern int nativeWidth;
69 extern int nativeHeight;
70 static TouchStatus touch_info;
71
72 static void control_update_android_touch(TouchStatus *touch_info, int maxp);
73 #endif
74
75 // update the mappings for a device in the save data
update_saved_mapping(int deviceID)76 static void update_saved_mapping(int deviceID)
77 {
78 InputDevice *device = &devices[deviceID];
79 if (device->deviceType == DEVICE_TYPE_NONE) return;
80
81 if (List_FindByName(&savedMappings, device->name))
82 {
83 memcpy(List_Retrieve(&savedMappings), device->mappings, SDID_COUNT * sizeof(int));
84 }
85 else
86 {
87 int *mappings = malloc(SDID_COUNT * sizeof(int));
88 memcpy(mappings, device->mappings, SDID_COUNT * sizeof(int));
89 List_InsertAfter(&savedMappings, mappings, device->name);
90 }
91 }
92
93 // set the mappings for a device to the saved settings
load_from_saved_mapping(int deviceID)94 static void load_from_saved_mapping(int deviceID)
95 {
96 InputDevice *device = &devices[deviceID];
97 if (device->deviceType == DEVICE_TYPE_NONE) return;
98
99 if (List_FindByName(&savedMappings, device->name))
100 {
101 memcpy(device->mappings, List_Retrieve(&savedMappings), SDID_COUNT * sizeof(int));
102 }
103 else
104 {
105 control_resetmappings(deviceID);
106 }
107 }
108
clear_saved_mappings()109 static void clear_saved_mappings()
110 {
111 if (!savedMappingsInited)
112 {
113 List_Init(&savedMappings);
114 savedMappingsInited = true;
115 }
116
117 int numMappings = List_GetSize(&savedMappings);
118 List_Reset(&savedMappings);
119 for (int i = 0; i < numMappings; i++)
120 {
121 free(List_Retrieve(&savedMappings));
122 List_GotoNext(&savedMappings);
123 }
124 List_Clear(&savedMappings);
125 }
126
127 /* If 2 or more of the same type of controller are plugged in, we need to disambiguate them so that a player assigning
128 devices in the options menu can tell them apart. Do this by appending "#2", "#3", etc. to the names. */
set_device_name(int deviceID,const char * name)129 static void set_device_name(int deviceID, const char *name)
130 {
131 char fullName[CONTROL_DEVICE_NAME_SIZE];
132
133 for (int i = 0; i < MAX_DEVICES; i++)
134 {
135 bool nameTaken = false;
136
137 if (i == 0)
138 {
139 snprintf(fullName, sizeof(fullName), "%s", name);
140 }
141 else
142 {
143 snprintf(fullName, sizeof(fullName), "%s #%i", name, i + 1);
144 }
145
146 for (int j = 0; j < MAX_DEVICES; j++)
147 {
148 if (j != deviceID && devices[j].deviceType != DEVICE_TYPE_NONE)
149 {
150 if (0 == strcmp(devices[j].name, fullName))
151 {
152 nameTaken = true;
153 break;
154 }
155 }
156 }
157
158 if (!nameTaken) break;
159 }
160
161 snprintf(devices[deviceID].name, sizeof(devices[deviceID].name), "%s", fullName);
162 }
163
setup_joystick(int deviceID,int sdlDeviceID)164 static void setup_joystick(int deviceID, int sdlDeviceID)
165 {
166 if (SDL_IsGameController(sdlDeviceID))
167 {
168 devices[deviceID].deviceType = DEVICE_TYPE_CONTROLLER;
169 devices[deviceID].controller = SDL_GameControllerOpen(sdlDeviceID);
170 const char *name = SDL_GameControllerNameForIndex(sdlDeviceID);
171 if (name == NULL)
172 {
173 name = SDL_JoystickNameForIndex(sdlDeviceID);
174 if (name == NULL)
175 {
176 name = "Unknown Controller";
177 }
178 }
179 //snprintf(devices[deviceID].name, sizeof(devices[deviceID].name), "%s", name);
180 set_device_name(deviceID, name);
181 load_from_saved_mapping(deviceID);
182 printf("%s (device #%i, SDL ID %i) is a game controller.\n", devices[deviceID].name, deviceID, sdlDeviceID);
183 }
184 else
185 {
186 devices[deviceID].deviceType = DEVICE_TYPE_JOYSTICK;
187 devices[deviceID].joystick = SDL_JoystickOpen(sdlDeviceID);
188 const char *name = SDL_JoystickNameForIndex(sdlDeviceID);
189 if (name == NULL)
190 {
191 name = "Unknown Controller";
192 }
193 //snprintf(devices[deviceID].name, sizeof(devices[deviceID].name), "%s", name);
194 set_device_name(deviceID, name);
195 load_from_saved_mapping(deviceID);
196 printf("%s (device #%i, SDL ID %i) is not a game controller.\n", devices[deviceID].name, deviceID, sdlDeviceID);
197 }
198
199 devices[deviceID].haptic = SDL_HapticOpen(sdlDeviceID);
200 if (devices[deviceID].haptic != NULL)
201 {
202 // initialize rumble
203 if (SDL_HapticRumbleInit(devices[deviceID].haptic) < 0)
204 {
205 printf("Warning: Unable to initialize rumble for %s! %s\n", devices[deviceID].name, SDL_GetError());
206 }
207 }
208 }
209
control_init()210 void control_init()
211 {
212 if (controlInited) return;
213
214 if (!savedMappingsInited)
215 {
216 List_Init(&savedMappings);
217 savedMappingsInited = true;
218 }
219
220 // initialize all devices to DEVICE_TYPE_NONE
221 memset(devices, 0, sizeof(devices));
222
223 int numJoysticks = SDL_NumJoysticks();
224
225 if (numJoysticks >= MAX_DEVICES)
226 {
227 // subtract 1 so we have room for the keyboard later
228 numJoysticks = MAX_DEVICES - 1;
229 }
230
231 int joystickCount = 0;
232 for (int i = 0; i < numJoysticks; i++)
233 {
234 // blacklist the Android accelerometer that SDL counts as a "joystick"
235 if (0 == stricmp("Android Accelerometer", SDL_JoystickNameForIndex(i)))
236 {
237 continue;
238 }
239
240 setup_joystick(joystickCount, i);
241 joystickCount++;
242 }
243
244 keyboardDeviceID = joystickCount;
245 devices[joystickCount].deviceType = DEVICE_TYPE_KEYBOARD;
246 #ifdef ANDROID
247 snprintf(devices[joystickCount].name, sizeof(devices[joystickCount].name), "%s", "On-Screen Controller");
248 #else
249 snprintf(devices[joystickCount].name, sizeof(devices[joystickCount].name), "%s", "Keyboard");
250 #endif
251 load_from_saved_mapping(joystickCount);
252
253 #ifdef ANDROID
254 for (int i = 0; i < MAX_POINTERS; i++)
255 {
256 touch_info.pstatus[i] = TOUCH_STATUS_UP;
257 }
258 #endif
259
260 controlInited = true;
261 }
262
control_exit()263 void control_exit()
264 {
265 if (!controlInited) return;
266
267 clear_saved_mappings();
268
269 for (int i = 0; i < MAX_DEVICES; i++)
270 {
271 InputDevice *device = &devices[i];
272 if (device->deviceType == DEVICE_TYPE_CONTROLLER)
273 {
274 SDL_GameControllerClose(device->controller);
275 device->controller = NULL;
276 }
277 else if (device->deviceType == DEVICE_TYPE_JOYSTICK)
278 {
279 SDL_JoystickClose(device->joystick);
280 device->joystick = NULL;
281 }
282 if (device->haptic)
283 {
284 SDL_HapticClose(device->haptic);
285 device->haptic = NULL;
286 }
287 device->deviceType = DEVICE_TYPE_NONE;
288 }
289
290 keyboardDeviceID = -1;
291 remapDevice = NULL;
292 remapKeycode = -1;
293 controlInited = false;
294 }
295
set_default_keyboard_mappings(InputDevice * device)296 static void set_default_keyboard_mappings(InputDevice *device)
297 {
298 device->mappings[SDID_MOVEUP] = SDL_SCANCODE_UP;
299 device->mappings[SDID_MOVEDOWN] = SDL_SCANCODE_DOWN;
300 device->mappings[SDID_MOVELEFT] = SDL_SCANCODE_LEFT;
301 device->mappings[SDID_MOVERIGHT] = SDL_SCANCODE_RIGHT;
302 device->mappings[SDID_ATTACK] = SDL_SCANCODE_A;
303 device->mappings[SDID_ATTACK2] = SDL_SCANCODE_S;
304 device->mappings[SDID_ATTACK3] = SDL_SCANCODE_Z;
305 device->mappings[SDID_ATTACK4] = SDL_SCANCODE_X;
306 device->mappings[SDID_JUMP] = SDL_SCANCODE_D;
307 device->mappings[SDID_SPECIAL] = SDL_SCANCODE_F;
308 device->mappings[SDID_START] = SDL_SCANCODE_RETURN;
309 device->mappings[SDID_SCREENSHOT] = SDL_SCANCODE_F12;
310 device->mappings[SDID_ESC] = SDL_SCANCODE_ESCAPE;
311 }
312
set_default_controller_mappings(InputDevice * device)313 static void set_default_controller_mappings(InputDevice *device)
314 {
315 device->mappings[SDID_MOVEUP] = SDL_CONTROLLER_BUTTON_DPAD_UP;
316 device->mappings[SDID_MOVEDOWN] = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
317 device->mappings[SDID_MOVELEFT] = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
318 device->mappings[SDID_MOVERIGHT] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
319 device->mappings[SDID_ATTACK] = SDL_CONTROLLER_BUTTON_A;
320 device->mappings[SDID_ATTACK2] = SDL_CONTROLLER_BUTTON_X;
321 device->mappings[SDID_ATTACK3] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
322 device->mappings[SDID_ATTACK4] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
323 device->mappings[SDID_JUMP] = SDL_CONTROLLER_BUTTON_B;
324 device->mappings[SDID_SPECIAL] = SDL_CONTROLLER_BUTTON_Y;
325 device->mappings[SDID_START] = SDL_CONTROLLER_BUTTON_START;
326 device->mappings[SDID_SCREENSHOT] = SDL_CONTROLLER_BUTTON_BACK;
327 device->mappings[SDID_ESC] = SDL_CONTROLLER_BUTTON_B;
328 }
329
set_default_joystick_mappings(InputDevice * device)330 static void set_default_joystick_mappings(InputDevice *device)
331 {
332 int numButtons = SDL_JoystickNumButtons(device->joystick);
333
334 device->mappings[SDID_MOVEUP] = numButtons;
335 device->mappings[SDID_MOVEDOWN] = numButtons + 1;
336 device->mappings[SDID_MOVELEFT] = numButtons + 2;
337 device->mappings[SDID_MOVERIGHT] = numButtons + 3;
338 device->mappings[SDID_ATTACK] = 0;
339 device->mappings[SDID_ATTACK2] = 3;
340 device->mappings[SDID_ATTACK3] = 4;
341 device->mappings[SDID_ATTACK4] = 5;
342 device->mappings[SDID_JUMP] = 1;
343 device->mappings[SDID_SPECIAL] = 2;
344 device->mappings[SDID_START] = 6;
345 device->mappings[SDID_SCREENSHOT] = 7;
346 device->mappings[SDID_ESC] = device->mappings[SDID_SPECIAL];
347 }
348
control_resetmappings(int deviceID)349 void control_resetmappings(int deviceID)
350 {
351 if (deviceID < 0) return;
352
353 InputDevice *device = &devices[deviceID];
354 switch (device->deviceType)
355 {
356 case DEVICE_TYPE_KEYBOARD:
357 set_default_keyboard_mappings(device);
358 break;
359 case DEVICE_TYPE_CONTROLLER:
360 set_default_controller_mappings(device);
361 break;
362 case DEVICE_TYPE_JOYSTICK:
363 set_default_joystick_mappings(device);
364 break;
365 default:
366 memset(device->mappings, 0, sizeof(device->mappings));
367 break;
368 }
369 }
370
handle_events()371 static void handle_events()
372 {
373 SDL_Event ev;
374 while (SDL_PollEvent(&ev))
375 {
376 switch (ev.type)
377 {
378 case SDL_QUIT:
379 {
380 borShutdown(0, DEFAULT_SHUTDOWN_MESSAGE);
381 break;
382 }
383
384 /* There is also a CONTROLLERDEVICEADDED event, but we can ignore it since this one works for
385 both kinds of controllers/joysticks. */
386 case SDL_JOYDEVICEADDED:
387 {
388 bool already_in_use = false;
389
390 /* We get this event for devices that were plugged in at application start, which we already
391 initialized in control_init(). So look through the device list to avoid duplicates. */
392 if (SDL_IsGameController(ev.jdevice.which))
393 {
394 SDL_GameController *controller = SDL_GameControllerOpen(ev.jdevice.which);
395 for (int i = 0; i < MAX_DEVICES; i++)
396 {
397 if (devices[i].deviceType == DEVICE_TYPE_CONTROLLER &&
398 devices[i].controller == controller)
399 {
400 already_in_use = true;
401 //printf("Already in use as device %i\n", i);
402 break;
403 }
404 }
405 SDL_GameControllerClose(controller);
406 }
407 else
408 {
409 SDL_Joystick *joystick = SDL_JoystickOpen(ev.jdevice.which);
410 for (int i = 0; i < MAX_DEVICES; i++)
411 {
412 if (devices[i].deviceType == DEVICE_TYPE_JOYSTICK &&
413 devices[i].joystick == joystick)
414 {
415 already_in_use = true;
416 //printf("Already in use as device %i\n", i);
417 break;
418 }
419 }
420 SDL_JoystickClose(joystick);
421 }
422
423 if (already_in_use)
424 {
425 break;
426 }
427
428 // Okay, it's actually a newly inserted device, not a duplicate. Initialize it.
429 printf("Controller or joystick hotplugged: SDL device ID=%i\n", ev.jdevice.which);
430 for (int i = 0; i < MAX_DEVICES; i++)
431 {
432 if (devices[i].deviceType == DEVICE_TYPE_NONE)
433 {
434 setup_joystick(i, ev.jdevice.which);
435 printf("Hotplugged %s set as device #%i\n",
436 devices[i].deviceType == DEVICE_TYPE_CONTROLLER ? "controller" : "joystick",
437 i);
438 break;
439 }
440 }
441 break;
442 }
443
444 /* There is also a CONTROLLERDEVICEREMOVED event, but we can ignore it since this one works for
445 both kinds of controllers/joysticks. */
446 case SDL_JOYDEVICEREMOVED:
447 {
448 for (int i = 0; i < MAX_DEVICES; i++)
449 {
450 if (devices[i].deviceType == DEVICE_TYPE_CONTROLLER &&
451 devices[i].controller == SDL_GameControllerFromInstanceID(ev.jdevice.which))
452 {
453 SDL_GameControllerClose(devices[i].controller);
454 devices[i].deviceType = DEVICE_TYPE_NONE;
455 printf("Controller removed: device #%i (SDL instance ID=%i)\n", i, ev.jdevice.which);
456 break;
457 }
458 else if (devices[i].deviceType == DEVICE_TYPE_JOYSTICK &&
459 devices[i].joystick == SDL_JoystickFromInstanceID(ev.jdevice.which))
460 {
461 SDL_JoystickClose(devices[i].joystick);
462 devices[i].deviceType = DEVICE_TYPE_NONE;
463 printf("Joystick removed: device #%i (SDL instance ID=%i)\n", i, ev.jdevice.which);
464 }
465 }
466 break;
467 }
468
469 case SDL_KEYDOWN:
470 {
471 if (remapDevice && remapDevice->deviceType == DEVICE_TYPE_KEYBOARD)
472 {
473 remapKeycode = ev.key.keysym.scancode;
474 }
475
476 #if 0 // disable Alt+Enter fullscreen toggle for now because it causes problems under X11
477 // Alt+Enter toggles fullscreen
478 if (ev.key.keysym.scancode == SDL_SCANCODE_RETURN && (SDL_GetModState() & KMOD_ALT) && !altEnterPressed)
479 {
480 fprintf(stderr, "Alt+Enter pressed, repeat=%i\n", ev.key.repeat);
481 video_fullscreen_flip();
482
483 /* Force the Enter key to unpressed in the SDL keyboard state so it won't be read by the
484 is_key_pressed() function if it's mapped to something in-game. */
485 //((Uint8*)SDL_GetKeyboardState(NULL))[SDL_SCANCODE_RETURN] = 0;
486 altEnterPressed = true;
487 }
488 #endif
489 break;
490 }
491
492 #if 0 // disable Alt+Enter fullscreen toggle for now because it causes problems under X11
493 case SDL_KEYUP:
494 {
495 if (ev.key.keysym.scancode == SDL_SCANCODE_RETURN)
496 {
497 altEnterPressed = false;
498 }
499 break;
500 }
501 #endif
502
503 case SDL_CONTROLLERBUTTONDOWN:
504 {
505 if (remapDevice &&
506 remapDevice->deviceType == DEVICE_TYPE_CONTROLLER &&
507 SDL_GameControllerFromInstanceID(ev.cbutton.which) == remapDevice->controller)
508 {
509 remapKeycode = ev.cbutton.button;
510 }
511 break;
512 }
513 case SDL_CONTROLLERAXISMOTION:
514 {
515 if (remapDevice &&
516 remapDevice->deviceType == DEVICE_TYPE_CONTROLLER &&
517 SDL_GameControllerFromInstanceID(ev.caxis.which) == remapDevice->controller)
518 {
519 if (ev.caxis.value > AXIS_THRESHOLD)
520 {
521 switch (ev.caxis.axis)
522 {
523 case SDL_CONTROLLER_AXIS_LEFTX:
524 case SDL_CONTROLLER_AXIS_LEFTY:
525 case SDL_CONTROLLER_AXIS_RIGHTX:
526 case SDL_CONTROLLER_AXIS_RIGHTY:
527 remapKeycode = SDL_CONTROLLER_BUTTON_MAX + (ev.caxis.axis * 2) + 1;
528 break;
529 case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
530 remapKeycode = SDL_CONTROLLER_BUTTON_MAX + 8;
531 break;
532 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
533 remapKeycode = SDL_CONTROLLER_BUTTON_MAX + 9;
534 break;
535 }
536 }
537 else if (ev.caxis.value < -AXIS_THRESHOLD)
538 {
539 // the triggers can't have negative values, so we don't need to handle them here
540 remapKeycode = SDL_CONTROLLER_BUTTON_MAX + (ev.caxis.axis * 2);
541 }
542 break;
543 }
544 break;
545 }
546 case SDL_JOYBUTTONDOWN:
547 {
548 if (remapDevice &&
549 remapDevice->deviceType == DEVICE_TYPE_JOYSTICK &&
550 remapDevice->joystick &&
551 SDL_JoystickFromInstanceID(ev.jbutton.which) == remapDevice->joystick)
552 {
553 remapKeycode = ev.jbutton.button;
554 }
555 break;
556 }
557 case SDL_JOYHATMOTION:
558 {
559 if (remapDevice &&
560 remapDevice->deviceType == DEVICE_TYPE_JOYSTICK &&
561 remapDevice->joystick &&
562 SDL_JoystickFromInstanceID(ev.jhat.which) == remapDevice->joystick)
563 {
564 // do nothing if the d-pad is pressed diagonally; wait for a cardinal direction
565 unsigned int base = SDL_JoystickNumButtons(remapDevice->joystick) + (4 * ev.jhat.hat);
566 switch (ev.jhat.value)
567 {
568 case SDL_HAT_UP:
569 remapKeycode = base;
570 break;
571 case SDL_HAT_DOWN:
572 remapKeycode = base + 1;
573 break;
574 case SDL_HAT_LEFT:
575 remapKeycode = base + 2;
576 break;
577 case SDL_HAT_RIGHT:
578 remapKeycode = base + 3;
579 break;
580 }
581 }
582 break;
583 }
584 case SDL_JOYAXISMOTION:
585 {
586 if (remapDevice &&
587 remapDevice->deviceType == DEVICE_TYPE_JOYSTICK &&
588 remapDevice->joystick &&
589 SDL_JoystickFromInstanceID(ev.jaxis.which) == remapDevice->joystick)
590 {
591 if (ev.jaxis.value < -AXIS_THRESHOLD || ev.jaxis.value > AXIS_THRESHOLD)
592 {
593 remapKeycode = SDL_JoystickNumButtons(remapDevice->joystick) +
594 4 * SDL_JoystickNumHats(remapDevice->joystick) +
595 2 * ev.jaxis.axis + ((ev.jaxis.value < -AXIS_THRESHOLD) ? 0 : 1);
596 }
597 }
598 break;
599 }
600
601 #ifdef ANDROID
602 case SDL_FINGERDOWN:
603 {
604 for (int i = 0; i < MAX_POINTERS; i++)
605 {
606 if (touch_info.pstatus[i] == TOUCH_STATUS_UP)
607 {
608 touch_info.pid[i] = ev.tfinger.fingerId;
609 touch_info.px[i] = ev.tfinger.x * nativeWidth;
610 touch_info.py[i] = ev.tfinger.y * nativeHeight;
611 touch_info.pstatus[i] = TOUCH_STATUS_DOWN;
612 break;
613 }
614 }
615 control_update_android_touch(&touch_info, MAX_POINTERS);
616 break;
617 }
618
619 case SDL_FINGERUP:
620 {
621 for (int i = 0; i < MAX_POINTERS; i++)
622 {
623 if (touch_info.pid[i] == ev.tfinger.fingerId)
624 {
625 touch_info.pstatus[i] = TOUCH_STATUS_UP;
626 break;
627 }
628 }
629 control_update_android_touch(&touch_info, MAX_POINTERS);
630 break;
631 }
632
633 case SDL_FINGERMOTION:
634 {
635 for (int i = 0; i < MAX_POINTERS; i++)
636 {
637 if (touch_info.pid[i] == ev.tfinger.fingerId)
638 {
639 touch_info.px[i] = ev.tfinger.x * nativeWidth;
640 touch_info.py[i] = ev.tfinger.y * nativeHeight;
641 touch_info.pstatus[i] = TOUCH_STATUS_DOWN;
642 break;
643 }
644 }
645 control_update_android_touch(&touch_info, MAX_POINTERS);
646 break;
647 }
648 #endif
649 }
650 }
651 }
652
653 // Returns 1 if key is pressed, 0 if not
is_key_pressed(InputDevice * device,int keycode)654 static unsigned int is_key_pressed(InputDevice *device, int keycode)
655 {
656 if (device->deviceType == DEVICE_TYPE_KEYBOARD)
657 {
658 // If Enter was pressed as part of an Alt+Enter to toggle fullscreen, don't count it as an in-game button press.
659 if (keycode == SDL_SCANCODE_RETURN && altEnterPressed)
660 {
661 return 0;
662 }
663
664 return SDL_GetKeyboardState(NULL)[keycode];
665 }
666 else if (device->deviceType == DEVICE_TYPE_CONTROLLER)
667 {
668 SDL_GameController *controller = device->controller;
669 if (keycode < SDL_CONTROLLER_BUTTON_MAX)
670 {
671 return SDL_GameControllerGetButton(controller, keycode);
672 }
673 else
674 {
675 int axisCode = keycode - SDL_CONTROLLER_BUTTON_MAX;
676 switch (axisCode)
677 {
678 case 0: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) < -AXIS_THRESHOLD);
679 case 1: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) > AXIS_THRESHOLD);
680 case 2: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) < -AXIS_THRESHOLD);
681 case 3: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) > AXIS_THRESHOLD);
682 case 4: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) < -AXIS_THRESHOLD);
683 case 5: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) > AXIS_THRESHOLD);
684 case 6: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) < -AXIS_THRESHOLD);
685 case 7: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) > AXIS_THRESHOLD);
686 case 8: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > AXIS_THRESHOLD);
687 case 9: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > AXIS_THRESHOLD);
688 }
689 return 0;
690 }
691 }
692 else if (device->deviceType == DEVICE_TYPE_JOYSTICK)
693 {
694 SDL_Joystick *joystick = device->joystick;
695 if (keycode < SDL_JoystickNumButtons(joystick))
696 {
697 return SDL_JoystickGetButton(joystick, keycode);
698 }
699
700 keycode -= SDL_JoystickNumButtons(joystick);
701 if (keycode < 4 * SDL_JoystickNumHats(joystick))
702 {
703 const int hatMasks[] = {SDL_HAT_UP, SDL_HAT_DOWN, SDL_HAT_LEFT, SDL_HAT_RIGHT};
704 return !!(SDL_JoystickGetHat(joystick, keycode / 4) & hatMasks[keycode % 4]);
705 }
706
707 keycode -= 4 * SDL_JoystickNumHats(joystick);
708 if (keycode < 2 * SDL_JoystickNumAxes(joystick))
709 {
710 Sint16 axisPosition = SDL_JoystickGetAxis(joystick, keycode / 2);
711 if (keycode & 1)
712 {
713 return (axisPosition > AXIS_THRESHOLD);
714 }
715 else
716 {
717 return (axisPosition < -AXIS_THRESHOLD);
718 }
719 }
720 }
721
722 return 0;
723 }
724
control_update_player(s_playercontrols * playerControls)725 void control_update_player(s_playercontrols *playerControls)
726 {
727 uint32_t keyflags = 0;
728 InputDevice *device = &devices[playerControls->deviceID];
729
730 for (unsigned int i = 0; i < SDID_COUNT; i++)
731 {
732 keyflags |= (is_key_pressed(device, device->mappings[i]) << i);
733 }
734
735 playerControls->newkeyflags = keyflags & (~playerControls->keyflags);
736 playerControls->keyflags = keyflags;
737 }
738
control_update(s_playercontrols ** playerControls,int numPlayers)739 void control_update(s_playercontrols **playerControls, int numPlayers)
740 {
741 handle_events();
742
743 for (int i = 0; i < numPlayers; i++)
744 {
745 control_update_player(playerControls[i]);
746 }
747 }
748
control_remapdevice(int deviceID)749 void control_remapdevice(int deviceID)
750 {
751 if (deviceID < 0)
752 {
753 // done remapping; reset globals to default values
754 remapDevice = NULL;
755 remapKeycode = -1;
756 }
757 else
758 {
759 assert(devices[deviceID].deviceType != DEVICE_TYPE_NONE);
760 remapDevice = &devices[deviceID];
761 remapKeycode = -1;
762 }
763 }
764
control_getremappedkey()765 int control_getremappedkey()
766 {
767 return remapKeycode;
768 }
769
control_getmappings(int deviceID)770 int *control_getmappings(int deviceID)
771 {
772 return devices[deviceID].mappings;
773 }
774
control_getkeyname(int deviceID,int keycode)775 const char *control_getkeyname(int deviceID, int keycode)
776 {
777 if (deviceID < 0) return "None";
778
779 if (devices[deviceID].deviceType == DEVICE_TYPE_KEYBOARD)
780 {
781 return SDL_GetKeyName(SDL_GetKeyFromScancode(keycode));
782 }
783 else if (devices[deviceID].deviceType == DEVICE_TYPE_CONTROLLER)
784 {
785 // These are more readable than the button names we get from SDL
786 const char *buttonNames[] = {
787 "A",
788 "B",
789 "X",
790 "Y",
791 "Back",
792 "Guide",
793 "Start",
794 "Left Stick Button",
795 "Right Stick Button",
796 "LB",
797 "RB",
798 "D-Pad Up",
799 "D-Pad Down",
800 "D-Pad Left",
801 "D-Pad Right",
802 "Left Stick Left",
803 "Left Stick Right",
804 "Left Stick Up",
805 "Left Stick Down",
806 "Right Stick Left",
807 "Right Stick Right",
808 "Right Stick Up",
809 "Right Stick Down",
810 "LT",
811 "RT"
812 };
813
814 if (keycode < sizeof(buttonNames) / sizeof(buttonNames[0]))
815 {
816 return buttonNames[keycode];
817 }
818 }
819 else if (devices[deviceID].deviceType == DEVICE_TYPE_JOYSTICK)
820 {
821 static char buttonName[64];
822 SDL_Joystick *joystick = devices[deviceID].joystick;
823 if (keycode < SDL_JoystickNumButtons(joystick))
824 {
825 snprintf(buttonName, sizeof(buttonName), "Button %u", keycode + 1);
826 return buttonName;
827 }
828
829 keycode -= SDL_JoystickNumButtons(joystick);
830 if (keycode < 4 * SDL_JoystickNumHats(joystick))
831 {
832 // omit the hat number because no real device is going to have more than one d-pad
833 const char *directions[] = {"Up", "Down", "Left", "Right"};
834 snprintf(buttonName, sizeof(buttonName), "D-Pad %s", directions[keycode % 4]);
835 return buttonName;
836 }
837
838 keycode -= 4 * SDL_JoystickNumHats(joystick);
839 if (keycode < 2 * SDL_JoystickNumAxes(joystick))
840 {
841 snprintf(buttonName, sizeof(buttonName), "Axis %i %c", (keycode / 2) + 1, (keycode & 1) ? '+' : '-');
842 return buttonName;
843 }
844 }
845
846 return "None";
847 }
848
control_isvaliddevice(int deviceID)849 bool control_isvaliddevice(int deviceID)
850 {
851 return deviceID >= 0 && devices[deviceID].deviceType != DEVICE_TYPE_NONE;
852 }
853
control_getdevicename(int deviceID)854 const char *control_getdevicename(int deviceID)
855 {
856 return devices[deviceID].deviceType == DEVICE_TYPE_NONE ? "None" : devices[deviceID].name;
857 }
858
control_rumble(int deviceID,int ratio,int msec)859 void control_rumble(int deviceID, int ratio, int msec)
860 {
861 if (msec > 0 && devices[deviceID].haptic)
862 {
863 if (SDL_HapticRumblePlay(devices[deviceID].haptic, ratio, msec) != 0)
864 {
865 printf("Warning: Unable to play rumble! %s\n", SDL_GetError());
866 }
867 }
868 }
869
870 #ifdef ANDROID
871 /*
872 Get if touchscreen vibration is active
873 */
is_touchpad_vibration_enabled()874 bool is_touchpad_vibration_enabled()
875 {
876 return !!(savedata.is_touchpad_vibration_enabled);
877 }
878
879 /*
880 Android touch logic, the rest of the code is in android/jni/video.c,
881 maybe they'll be merged someday.
882 */
883 extern float bx[MAXTOUCHB];
884 extern float by[MAXTOUCHB];
885 extern float br[MAXTOUCHB];
886 extern unsigned touchstates[MAXTOUCHB];
887 int hide_t = 5000;
888
control_update_android_touch(TouchStatus * touch_info,int maxp)889 static void control_update_android_touch(TouchStatus *touch_info, int maxp)
890 {
891 #define pc(x) devices[keyboardDeviceID].mappings[x]
892 int i, j;
893 float tx, ty, tr;
894 float r[MAXTOUCHB];
895 float dirx, diry, circlea, circleb, tan;
896 Uint8* keystate = (Uint8*) SDL_GetKeyboardState(NULL);
897 SDL_Event event;
898
899 memset(touchstates, 0, sizeof(touchstates));
900
901 for(j=0; j<MAXTOUCHB; j++)
902 {
903 r[j] = br[j]*br[j]*(1.5*1.5);
904 }
905 dirx = (bx[SDID_MOVERIGHT]+bx[SDID_MOVELEFT])/2.0;
906 diry = (by[SDID_MOVEUP]+by[SDID_MOVEDOWN])/2.0;
907 circlea = bx[SDID_MOVERIGHT]-dirx-br[SDID_MOVEUP];
908 circleb = bx[SDID_MOVERIGHT]-dirx+br[SDID_MOVEUP]*1.5;
909 circlea *= circlea;
910 circleb *= circleb;
911 #define tana 0.577350f
912 #define tanb 1.732051f
913 for (i=0; i<maxp; i++)
914 {
915 if(touch_info->pstatus[i] == TOUCH_STATUS_UP) continue;
916
917 event.type = SDL_KEYDOWN;
918 event.key.type = SDL_KEYDOWN;
919 event.key.timestamp = SDL_GetTicks();
920 event.key.state = SDL_PRESSED;
921 event.key.repeat = 0;
922
923 tx = touch_info->px[i]-dirx;
924 ty = touch_info->py[i]-diry;
925 tr = tx*tx + ty*ty;
926
927 //direction button logic is different, check a ring instead of individual buttons
928 if(tr>circlea && tr<=circleb)
929 {
930 if(tx<0)
931 {
932 tan = ty/tx;
933 if(tan>=-tana && tan<=tana)
934 {
935 touchstates[SDID_MOVELEFT] = 1;
936 event.key.keysym.scancode = pc(SDID_MOVELEFT);
937 SDL_PushEvent(&event);
938 }
939 else if(tan<-tanb)
940 {
941 touchstates[SDID_MOVEDOWN] = 1;
942 event.key.keysym.scancode = pc(SDID_MOVEDOWN);
943 SDL_PushEvent(&event);
944 }
945 else if(tan>tanb)
946 {
947 touchstates[SDID_MOVEUP] = 1;
948 event.key.keysym.scancode = pc(SDID_MOVEUP);
949 SDL_PushEvent(&event);
950 }
951 else if(ty<0)
952 {
953 touchstates[SDID_MOVEUP] = touchstates[SDID_MOVELEFT] = 1;
954 event.key.keysym.scancode = pc(SDID_MOVEUP);
955 SDL_PushEvent(&event);
956 event.key.keysym.scancode = pc(SDID_MOVELEFT);
957 SDL_PushEvent(&event);
958 }
959 else
960 {
961 touchstates[SDID_MOVELEFT] = touchstates[SDID_MOVEDOWN] = 1;
962 event.key.keysym.scancode = pc(SDID_MOVELEFT);
963 SDL_PushEvent(&event);
964 event.key.keysym.scancode = pc(SDID_MOVEDOWN);
965 SDL_PushEvent(&event);
966 }
967 }
968 else if(tx>0)
969 {
970 tan = ty/tx;
971 if(tan>=-tana && tan<=tana)
972 {
973 touchstates[SDID_MOVERIGHT] = 1;
974 event.key.keysym.scancode = pc(SDID_MOVERIGHT);
975 SDL_PushEvent(&event);
976 }
977 else if(tan<-tanb)
978 {
979 touchstates[SDID_MOVEUP] = 1;
980 event.key.keysym.scancode = pc(SDID_MOVEUP);
981 SDL_PushEvent(&event);
982 }
983 else if(tan>tanb)
984 {
985 touchstates[SDID_MOVEDOWN] = 1;
986 event.key.keysym.scancode = pc(SDID_MOVEDOWN);
987 SDL_PushEvent(&event);
988 }
989 else if(ty<0)
990 {
991 touchstates[SDID_MOVEUP] = touchstates[SDID_MOVERIGHT] = 1;
992 event.key.keysym.scancode = pc(SDID_MOVEUP);
993 SDL_PushEvent(&event);
994 event.key.keysym.scancode = pc(SDID_MOVERIGHT);
995 SDL_PushEvent(&event);
996 }
997 else
998 {
999 touchstates[SDID_MOVERIGHT] = touchstates[SDID_MOVEDOWN] = 1;
1000 event.key.keysym.scancode = pc(SDID_MOVERIGHT);
1001 SDL_PushEvent(&event);
1002 event.key.keysym.scancode = pc(SDID_MOVEDOWN);
1003 SDL_PushEvent(&event);
1004 }
1005 }
1006 else
1007 {
1008 if(ty>0)
1009 {
1010 touchstates[SDID_MOVEDOWN] = 1;
1011 event.key.keysym.scancode = pc(SDID_MOVEDOWN);
1012 SDL_PushEvent(&event);
1013 }
1014 else
1015 {
1016 touchstates[SDID_MOVEUP] = 1;
1017 event.key.keysym.scancode = pc(SDID_MOVEUP);
1018 SDL_PushEvent(&event);
1019 }
1020 }
1021 }
1022
1023 //rest of the buttons
1024 for(j=0; j<MAXTOUCHB; j++)
1025 {
1026 if(j==SDID_MOVERIGHT || j==SDID_MOVEUP ||
1027 j==SDID_MOVELEFT || j==SDID_MOVEDOWN)
1028 continue;
1029 tx = touch_info->px[i]-bx[j];
1030 ty = touch_info->py[i]-by[j];
1031 tr = tx*tx + ty*ty;
1032 if(tr<=r[j])
1033 {
1034 touchstates[j] = 1;
1035 event.key.keysym.scancode = pc(j);
1036 SDL_PushEvent(&event);
1037 }
1038 }
1039 }
1040 #undef tana
1041 #undef tanb
1042
1043 hide_t = timer_gettick() + 5000;
1044
1045 //map to current user settings
1046 assert(keyboardDeviceID >= 0);
1047 keystate[pc(SDID_MOVEUP)] = touchstates[SDID_MOVEUP];
1048 keystate[pc(SDID_MOVEDOWN)] = touchstates[SDID_MOVEDOWN];
1049 keystate[pc(SDID_MOVELEFT)] = touchstates[SDID_MOVELEFT];
1050 keystate[pc(SDID_MOVERIGHT)] = touchstates[SDID_MOVERIGHT];
1051 keystate[pc(SDID_ATTACK)] = touchstates[SDID_ATTACK];
1052 keystate[pc(SDID_ATTACK2)] = touchstates[SDID_ATTACK2];
1053 keystate[pc(SDID_ATTACK3)] = touchstates[SDID_ATTACK3];
1054 keystate[pc(SDID_ATTACK4)] = touchstates[SDID_ATTACK4];
1055 keystate[pc(SDID_JUMP)] = touchstates[SDID_JUMP];
1056 keystate[pc(SDID_SPECIAL)] = touchstates[SDID_SPECIAL];
1057 keystate[pc(SDID_START)] = touchstates[SDID_START];
1058 keystate[pc(SDID_SCREENSHOT)] = touchstates[SDID_SCREENSHOT];
1059 keystate[pc(SDID_SCREENSHOT)] = touchstates[SDID_SCREENSHOT];
1060 keystate[pc(SDID_ESC)] = touchstates[SDID_ESC];
1061
1062 #undef pc
1063 }
1064
is_touch_area(float x,float y)1065 int is_touch_area(float x, float y)
1066 {
1067 int j;
1068 float tx, ty, tr;
1069 float r[MAXTOUCHB];
1070 float dirx, diry, circlea, circleb, tan;
1071
1072 for(j=0; j<MAXTOUCHB; j++)
1073 {
1074 r[j] = br[j]*br[j]*(1.5*1.5);
1075 }
1076 dirx = (bx[SDID_MOVERIGHT]+bx[SDID_MOVELEFT])/2.0;
1077 diry = (by[SDID_MOVEUP]+by[SDID_MOVEDOWN])/2.0;
1078 circlea = bx[SDID_MOVERIGHT]-dirx-br[SDID_MOVEUP];
1079 circleb = bx[SDID_MOVERIGHT]-dirx+br[SDID_MOVEUP]*1.5;
1080 circlea *= circlea;
1081 circleb *= circleb;
1082 #define tana 0.577350f
1083 #define tanb 1.732051f
1084 tx = x-dirx;
1085 ty = y-diry;
1086 tr = tx*tx + ty*ty;
1087 //direction button logic is different, check a ring instead of individual buttons
1088 if(tr>circlea && tr<=circleb)
1089 {
1090 if(tx<0)
1091 {
1092 tan = ty/tx;
1093 if(tan>=-tana && tan<=tana)
1094 {
1095 return 1;
1096 }
1097 else if(tan<-tanb)
1098 {
1099 return 1;
1100 }
1101 else if(tan>tanb)
1102 {
1103 return 1;
1104 }
1105 else if(ty<0)
1106 {
1107 return 1;
1108 }
1109 else
1110 {
1111 return 1;
1112 }
1113 }
1114 else if(tx>0)
1115 {
1116 tan = ty/tx;
1117 if(tan>=-tana && tan<=tana)
1118 {
1119 return 1;
1120 }
1121 else if(tan<-tanb)
1122 {
1123 return 1;
1124 }
1125 else if(tan>tanb)
1126 {
1127 return 1;
1128 }
1129 else if(ty<0)
1130 {
1131 return 1;
1132 }
1133 else
1134 {
1135 return 1;
1136 }
1137 }
1138 else
1139 {
1140 if(ty>0)
1141 {
1142 return 1;
1143 }
1144 else
1145 {
1146 return 1;
1147 }
1148 }
1149 }
1150 //rest buttons
1151 for(j=0; j<MAXTOUCHB; j++)
1152 {
1153 if(j==SDID_MOVERIGHT || j==SDID_MOVEUP ||
1154 j==SDID_MOVELEFT || j==SDID_MOVEDOWN)
1155 continue;
1156 tx = x-bx[j];
1157 ty = y-by[j];
1158 tr = tx*tx + ty*ty;
1159 if(tr<=r[j])
1160 {
1161 return 1;
1162 }
1163 }
1164 #undef tana
1165 #undef tanb
1166
1167 return 0;
1168 }
1169 #endif
1170
1171 #define MAPPINGS_FILE_SENTINEL 0x9cf232d4
1172
control_loadmappings(const char * filename)1173 bool control_loadmappings(const char *filename)
1174 {
1175 FILE *fp = fopen(filename, "rb");
1176 if (!fp)
1177 {
1178 return false;
1179 }
1180
1181 clear_saved_mappings();
1182
1183 while (!feof(fp) && !ferror(fp))
1184 {
1185 char name[CONTROL_DEVICE_NAME_SIZE];
1186 int *mapping = malloc(SDID_COUNT * sizeof(int));
1187 int sentinel;
1188 if (fread(name, 1, sizeof(name), fp) != sizeof(name) ||
1189 fread(mapping, sizeof(int), SDID_COUNT, fp) != SDID_COUNT ||
1190 fread(&sentinel, sizeof(int), 1, fp) != 1)
1191 {
1192 free(mapping);
1193 break;
1194 }
1195 else if (sentinel != MAPPINGS_FILE_SENTINEL)
1196 {
1197 free(mapping);
1198 fclose(fp);
1199 return false;
1200 }
1201
1202 name[sizeof(name)-1] = '\0'; // just in case
1203 printf("Loaded mapping for %s\n", name);
1204 List_InsertAfter(&savedMappings, mapping, name);
1205 }
1206
1207 fclose(fp);
1208
1209 // update all current device mappings with the newly loaded mappings
1210 for (int i = 0; i < MAX_DEVICES; i++)
1211 {
1212 if (devices[i].deviceType != DEVICE_TYPE_NONE)
1213 {
1214 load_from_saved_mapping(i);
1215 }
1216 }
1217
1218 return true;
1219 }
1220
control_savemappings(const char * filename)1221 bool control_savemappings(const char *filename)
1222 {
1223 // update savedMappings with all current device mappings
1224 for (int i = 0; i < MAX_DEVICES; i++)
1225 {
1226 if (devices[i].deviceType != DEVICE_TYPE_NONE)
1227 {
1228 update_saved_mapping(i);
1229 }
1230 }
1231
1232 FILE *fp = fopen(filename, "wb");
1233 if (!fp)
1234 {
1235 return false;
1236 }
1237
1238 int numMappings = List_GetSize(&savedMappings);
1239 List_Reset(&savedMappings);
1240 for (int i = 0; i < numMappings; i++)
1241 {
1242 char name[CONTROL_DEVICE_NAME_SIZE];
1243 snprintf(name, sizeof(name), "%s", List_GetName(&savedMappings));
1244 int *mapping = List_Retrieve(&savedMappings);
1245 const int sentinel = MAPPINGS_FILE_SENTINEL;
1246 if (fwrite(name, 1, sizeof(name), fp) != sizeof(name) ||
1247 fwrite(mapping, sizeof(int), SDID_COUNT, fp) != SDID_COUNT ||
1248 fwrite(&sentinel, sizeof(int), 1, fp) != 1)
1249 {
1250 fclose(fp);
1251 return false;
1252 }
1253
1254 List_GotoNext(&savedMappings);
1255 }
1256
1257 fclose(fp);
1258 return true;
1259 }
1260
control_clearmappings()1261 void control_clearmappings()
1262 {
1263 clear_saved_mappings();
1264
1265 for (int i = 0; i < MAX_DEVICES; i++)
1266 {
1267 if (devices[i].deviceType != DEVICE_TYPE_NONE)
1268 {
1269 control_resetmappings(i);
1270 }
1271 }
1272 }
1273
1274