1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22
23 /* This is the game controller API for Simple DirectMedia Layer */
24
25 #include "SDL_events.h"
26 #include "SDL_assert.h"
27 #include "SDL_sysjoystick.h"
28 #include "SDL_hints.h"
29 #include "SDL_gamecontrollerdb.h"
30
31 #if !SDL_EVENTS_DISABLED
32 #include "../events/SDL_events_c.h"
33 #endif
34 #define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
35
36 #define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
37
38 /* a list of currently opened game controllers */
39 static SDL_GameController *SDL_gamecontrollers = NULL;
40
41 /* keep track of the hat and mask value that transforms this hat movement into a button/axis press */
42 struct _SDL_HatMapping
43 {
44 int hat;
45 Uint8 mask;
46 };
47
48 /* We need 36 entries for Android (as of SDL v2.0.4) */
49 #define k_nMaxReverseEntries 48
50
51 /**
52 * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask
53 * MAX 4 hats supported
54 */
55 #define k_nMaxHatEntries 0x3f + 1
56
57 /* our in memory mapping db between joystick objects and controller mappings */
58 struct _SDL_ControllerMapping
59 {
60 SDL_JoystickGUID guid;
61 const char *name;
62
63 /* mapping of axis/button id to controller version */
64 int axes[SDL_CONTROLLER_AXIS_MAX];
65 int buttonasaxis[SDL_CONTROLLER_AXIS_MAX];
66
67 int buttons[SDL_CONTROLLER_BUTTON_MAX];
68 int axesasbutton[SDL_CONTROLLER_BUTTON_MAX];
69 struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX];
70
71 /* reverse mapping, joystick indices to buttons */
72 SDL_GameControllerAxis raxes[k_nMaxReverseEntries];
73 SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries];
74
75 SDL_GameControllerButton rbuttons[k_nMaxReverseEntries];
76 SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries];
77 SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries];
78
79 };
80
81
82 /* our hard coded list of mapping support */
83 typedef struct _ControllerMapping_t
84 {
85 SDL_JoystickGUID guid;
86 char *name;
87 char *mapping;
88 struct _ControllerMapping_t *next;
89 } ControllerMapping_t;
90
91 static ControllerMapping_t *s_pSupportedControllers = NULL;
92 static ControllerMapping_t *s_pXInputMapping = NULL;
93 static ControllerMapping_t *s_pEmscriptenMapping = NULL;
94
95 /* The SDL game controller structure */
96 struct _SDL_GameController
97 {
98 SDL_Joystick *joystick; /* underlying joystick device */
99 int ref_count;
100 Uint8 hatState[4]; /* the current hat state for this controller */
101 struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */
102 struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
103 };
104
105
106 int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
107 int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
108
109 /*
110 * If there is an existing add event in the queue, it needs to be modified
111 * to have the right value for which, because the number of controllers in
112 * the system is now one less.
113 */
UpdateEventsForDeviceRemoval()114 static void UpdateEventsForDeviceRemoval()
115 {
116 int i, num_events;
117 SDL_Event *events;
118
119 num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
120 if (num_events <= 0) {
121 return;
122 }
123
124 events = SDL_stack_alloc(SDL_Event, num_events);
125 if (!events) {
126 return;
127 }
128
129 num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
130 for (i = 0; i < num_events; ++i) {
131 --events[i].cdevice.which;
132 }
133 SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
134
135 SDL_stack_free(events);
136 }
137
138 /*
139 * Event filter to fire controller events from joystick ones
140 */
SDL_GameControllerEventWatcher(void * userdata,SDL_Event * event)141 int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
142 {
143 switch(event->type) {
144 case SDL_JOYAXISMOTION:
145 {
146 SDL_GameController *controllerlist;
147
148 if (event->jaxis.axis >= k_nMaxReverseEntries)
149 {
150 SDL_SetError("SDL_GameControllerEventWatcher: Axis index %d too large, ignoring motion", (int)event->jaxis.axis);
151 break;
152 }
153
154 controllerlist = SDL_gamecontrollers;
155 while (controllerlist) {
156 if (controllerlist->joystick->instance_id == event->jaxis.which) {
157 if (controllerlist->mapping.raxes[event->jaxis.axis] >= 0) /* simple axis to axis, send it through */ {
158 SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis];
159 Sint16 value = event->jaxis.value;
160 switch (axis) {
161 case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
162 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
163 value = value / 2 + 16384;
164 break;
165 default:
166 break;
167 }
168 SDL_PrivateGameControllerAxis(controllerlist, axis, value);
169 } else if (controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0) { /* simulate an axis as a button */
170 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED);
171 }
172 break;
173 }
174 controllerlist = controllerlist->next;
175 }
176 }
177 break;
178 case SDL_JOYBUTTONDOWN:
179 case SDL_JOYBUTTONUP:
180 {
181 SDL_GameController *controllerlist;
182
183 if (event->jbutton.button >= k_nMaxReverseEntries)
184 {
185 SDL_SetError("SDL_GameControllerEventWatcher: Button index %d too large, ignoring update", (int)event->jbutton.button);
186 break;
187 }
188
189 controllerlist = SDL_gamecontrollers;
190 while (controllerlist) {
191 if (controllerlist->joystick->instance_id == event->jbutton.which) {
192 if (controllerlist->mapping.rbuttons[event->jbutton.button] >= 0) { /* simple button as button */
193 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state);
194 } else if (controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0) { /* an button pretending to be an axis */
195 SDL_PrivateGameControllerAxis(controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0);
196 }
197 break;
198 }
199 controllerlist = controllerlist->next;
200 }
201 }
202 break;
203 case SDL_JOYHATMOTION:
204 {
205 SDL_GameController *controllerlist;
206
207 if (event->jhat.hat >= 4) break;
208
209 controllerlist = SDL_gamecontrollers;
210 while (controllerlist) {
211 if (controllerlist->joystick->instance_id == event->jhat.which) {
212 Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value;
213 /* Get list of removed bits (button release) */
214 Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame;
215 /* the hat idx in the high nibble */
216 int bHighHat = event->jhat.hat << 4;
217
218 if (bChanged & SDL_HAT_DOWN)
219 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED);
220 if (bChanged & SDL_HAT_UP)
221 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED);
222 if (bChanged & SDL_HAT_LEFT)
223 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED);
224 if (bChanged & SDL_HAT_RIGHT)
225 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED);
226
227 /* Get list of added bits (button press) */
228 bChanged = event->jhat.value ^ bSame;
229
230 if (bChanged & SDL_HAT_DOWN)
231 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED);
232 if (bChanged & SDL_HAT_UP)
233 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED);
234 if (bChanged & SDL_HAT_LEFT)
235 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED);
236 if (bChanged & SDL_HAT_RIGHT)
237 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED);
238
239 /* update our state cache */
240 controllerlist->hatState[event->jhat.hat] = event->jhat.value;
241
242 break;
243 }
244 controllerlist = controllerlist->next;
245 }
246 }
247 break;
248 case SDL_JOYDEVICEADDED:
249 {
250 if (SDL_IsGameController(event->jdevice.which)) {
251 SDL_Event deviceevent;
252 deviceevent.type = SDL_CONTROLLERDEVICEADDED;
253 deviceevent.cdevice.which = event->jdevice.which;
254 SDL_PushEvent(&deviceevent);
255 }
256 }
257 break;
258 case SDL_JOYDEVICEREMOVED:
259 {
260 SDL_GameController *controllerlist = SDL_gamecontrollers;
261 while (controllerlist) {
262 if (controllerlist->joystick->instance_id == event->jdevice.which) {
263 SDL_Event deviceevent;
264
265 deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
266 deviceevent.cdevice.which = event->jdevice.which;
267 SDL_PushEvent(&deviceevent);
268
269 UpdateEventsForDeviceRemoval();
270 break;
271 }
272 controllerlist = controllerlist->next;
273 }
274 }
275 break;
276 default:
277 break;
278 }
279
280 return 1;
281 }
282
283 /*
284 * Helper function to scan the mappings database for a controller with the specified GUID
285 */
SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID * guid)286 ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
287 {
288 ControllerMapping_t *pSupportedController = s_pSupportedControllers;
289 while (pSupportedController) {
290 if (SDL_memcmp(guid, &pSupportedController->guid, sizeof(*guid)) == 0) {
291 return pSupportedController;
292 }
293 pSupportedController = pSupportedController->next;
294 }
295 return NULL;
296 }
297
298 static const char* map_StringForControllerAxis[] = {
299 "leftx",
300 "lefty",
301 "rightx",
302 "righty",
303 "lefttrigger",
304 "righttrigger",
305 NULL
306 };
307
308 /*
309 * convert a string to its enum equivalent
310 */
SDL_GameControllerGetAxisFromString(const char * pchString)311 SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString)
312 {
313 int entry;
314 if (!pchString || !pchString[0])
315 return SDL_CONTROLLER_AXIS_INVALID;
316
317 for (entry = 0; map_StringForControllerAxis[entry]; ++entry) {
318 if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry]))
319 return entry;
320 }
321 return SDL_CONTROLLER_AXIS_INVALID;
322 }
323
324 /*
325 * convert an enum to its string equivalent
326 */
SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)327 const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
328 {
329 if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) {
330 return map_StringForControllerAxis[axis];
331 }
332 return NULL;
333 }
334
335 static const char* map_StringForControllerButton[] = {
336 "a",
337 "b",
338 "x",
339 "y",
340 "back",
341 "guide",
342 "start",
343 "leftstick",
344 "rightstick",
345 "leftshoulder",
346 "rightshoulder",
347 "dpup",
348 "dpdown",
349 "dpleft",
350 "dpright",
351 NULL
352 };
353
354 /*
355 * convert a string to its enum equivalent
356 */
SDL_GameControllerGetButtonFromString(const char * pchString)357 SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString)
358 {
359 int entry;
360 if (!pchString || !pchString[0])
361 return SDL_CONTROLLER_BUTTON_INVALID;
362
363 for (entry = 0; map_StringForControllerButton[entry]; ++entry) {
364 if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0)
365 return entry;
366 }
367 return SDL_CONTROLLER_BUTTON_INVALID;
368 }
369
370 /*
371 * convert an enum to its string equivalent
372 */
SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)373 const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis)
374 {
375 if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) {
376 return map_StringForControllerButton[axis];
377 }
378 return NULL;
379 }
380
381 /*
382 * given a controller button name and a joystick name update our mapping structure with it
383 */
SDL_PrivateGameControllerParseButton(const char * szGameButton,const char * szJoystickButton,struct _SDL_ControllerMapping * pMapping)384 void SDL_PrivateGameControllerParseButton(const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping)
385 {
386 int iSDLButton = 0;
387 SDL_GameControllerButton button;
388 SDL_GameControllerAxis axis;
389 button = SDL_GameControllerGetButtonFromString(szGameButton);
390 axis = SDL_GameControllerGetAxisFromString(szGameButton);
391 iSDLButton = SDL_atoi(&szJoystickButton[1]);
392
393 if (szJoystickButton[0] == 'a') {
394 if (iSDLButton >= k_nMaxReverseEntries) {
395 SDL_SetError("Axis index too large: %d", iSDLButton);
396 return;
397 }
398 if (axis != SDL_CONTROLLER_AXIS_INVALID) {
399 pMapping->axes[ axis ] = iSDLButton;
400 pMapping->raxes[ iSDLButton ] = axis;
401 } else if (button != SDL_CONTROLLER_BUTTON_INVALID) {
402 pMapping->axesasbutton[ button ] = iSDLButton;
403 pMapping->raxesasbutton[ iSDLButton ] = button;
404 } else {
405 SDL_assert(!"How did we get here?");
406 }
407
408 } else if (szJoystickButton[0] == 'b') {
409 if (iSDLButton >= k_nMaxReverseEntries) {
410 SDL_SetError("Button index too large: %d", iSDLButton);
411 return;
412 }
413 if (button != SDL_CONTROLLER_BUTTON_INVALID) {
414 pMapping->buttons[ button ] = iSDLButton;
415 pMapping->rbuttons[ iSDLButton ] = button;
416 } else if (axis != SDL_CONTROLLER_AXIS_INVALID) {
417 pMapping->buttonasaxis[ axis ] = iSDLButton;
418 pMapping->rbuttonasaxis[ iSDLButton ] = axis;
419 } else {
420 SDL_assert(!"How did we get here?");
421 }
422 } else if (szJoystickButton[0] == 'h') {
423 int hat = SDL_atoi(&szJoystickButton[1]);
424 int mask = SDL_atoi(&szJoystickButton[3]);
425 if (hat >= 4) {
426 SDL_SetError("Hat index too large: %d", iSDLButton);
427 }
428
429 if (button != SDL_CONTROLLER_BUTTON_INVALID) {
430 int ridx;
431 pMapping->hatasbutton[ button ].hat = hat;
432 pMapping->hatasbutton[ button ].mask = mask;
433 ridx = (hat << 4) | mask;
434 pMapping->rhatasbutton[ ridx ] = button;
435 } else if (axis != SDL_CONTROLLER_AXIS_INVALID) {
436 SDL_assert(!"Support hat as axis");
437 } else {
438 SDL_assert(!"How did we get here?");
439 }
440 }
441 }
442
443
444 /*
445 * given a controller mapping string update our mapping object
446 */
447 static void
SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMapping * pMapping,const char * pchString)448 SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMapping *pMapping, const char *pchString)
449 {
450 char szGameButton[20];
451 char szJoystickButton[20];
452 SDL_bool bGameButton = SDL_TRUE;
453 int i = 0;
454 const char *pchPos = pchString;
455
456 SDL_memset(szGameButton, 0x0, sizeof(szGameButton));
457 SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton));
458
459 while (pchPos && *pchPos) {
460 if (*pchPos == ':') {
461 i = 0;
462 bGameButton = SDL_FALSE;
463 } else if (*pchPos == ' ') {
464
465 } else if (*pchPos == ',') {
466 i = 0;
467 bGameButton = SDL_TRUE;
468 SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping);
469 SDL_memset(szGameButton, 0x0, sizeof(szGameButton));
470 SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton));
471
472 } else if (bGameButton) {
473 if (i >= sizeof(szGameButton)) {
474 SDL_SetError("Button name too large: %s", szGameButton);
475 return;
476 }
477 szGameButton[i] = *pchPos;
478 i++;
479 } else {
480 if (i >= sizeof(szJoystickButton)) {
481 SDL_SetError("Joystick button name too large: %s", szJoystickButton);
482 return;
483 }
484 szJoystickButton[i] = *pchPos;
485 i++;
486 }
487 pchPos++;
488 }
489
490 SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping);
491
492 }
493
494 /*
495 * Make a new button mapping struct
496 */
SDL_PrivateLoadButtonMapping(struct _SDL_ControllerMapping * pMapping,SDL_JoystickGUID guid,const char * pchName,const char * pchMapping)497 void SDL_PrivateLoadButtonMapping(struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
498 {
499 int j;
500
501 pMapping->guid = guid;
502 pMapping->name = pchName;
503
504 /* set all the button mappings to non defaults */
505 for (j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++) {
506 pMapping->axes[j] = -1;
507 pMapping->buttonasaxis[j] = -1;
508 }
509 for (j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++) {
510 pMapping->buttons[j] = -1;
511 pMapping->axesasbutton[j] = -1;
512 pMapping->hatasbutton[j].hat = -1;
513 }
514
515 for (j = 0; j < k_nMaxReverseEntries; j++) {
516 pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
517 pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
518 pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
519 pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
520 }
521
522 for (j = 0; j < k_nMaxHatEntries; j++) {
523 pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
524 }
525
526 SDL_PrivateGameControllerParseControllerConfigString(pMapping, pchMapping);
527 }
528
529
530 /*
531 * grab the guid string from a mapping string
532 */
SDL_PrivateGetControllerGUIDFromMappingString(const char * pMapping)533 char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
534 {
535 const char *pFirstComma = SDL_strchr(pMapping, ',');
536 if (pFirstComma) {
537 char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1);
538 if (!pchGUID) {
539 SDL_OutOfMemory();
540 return NULL;
541 }
542 SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping);
543 pchGUID[ pFirstComma - pMapping ] = 0;
544 return pchGUID;
545 }
546 return NULL;
547 }
548
549
550 /*
551 * grab the name string from a mapping string
552 */
SDL_PrivateGetControllerNameFromMappingString(const char * pMapping)553 char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
554 {
555 const char *pFirstComma, *pSecondComma;
556 char *pchName;
557
558 pFirstComma = SDL_strchr(pMapping, ',');
559 if (!pFirstComma)
560 return NULL;
561
562 pSecondComma = SDL_strchr(pFirstComma + 1, ',');
563 if (!pSecondComma)
564 return NULL;
565
566 pchName = SDL_malloc(pSecondComma - pFirstComma);
567 if (!pchName) {
568 SDL_OutOfMemory();
569 return NULL;
570 }
571 SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma);
572 pchName[ pSecondComma - pFirstComma - 1 ] = 0;
573 return pchName;
574 }
575
576
577 /*
578 * grab the button mapping string from a mapping string
579 */
SDL_PrivateGetControllerMappingFromMappingString(const char * pMapping)580 char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
581 {
582 const char *pFirstComma, *pSecondComma;
583
584 pFirstComma = SDL_strchr(pMapping, ',');
585 if (!pFirstComma)
586 return NULL;
587
588 pSecondComma = SDL_strchr(pFirstComma + 1, ',');
589 if (!pSecondComma)
590 return NULL;
591
592 return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
593 }
594
595 /*
596 * Helper function to refresh a mapping
597 */
SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t * pControllerMapping)598 void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
599 {
600 SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
601 while (gamecontrollerlist) {
602 if (!SDL_memcmp(&gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) {
603 SDL_Event event;
604 event.type = SDL_CONTROLLERDEVICEREMAPPED;
605 event.cdevice.which = gamecontrollerlist->joystick->instance_id;
606 SDL_PushEvent(&event);
607
608 /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
609 SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
610 }
611
612 gamecontrollerlist = gamecontrollerlist->next;
613 }
614 }
615
616 /*
617 * Helper function to add a mapping for a guid
618 */
619 static ControllerMapping_t *
SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID,const char * mappingString,SDL_bool * existing)620 SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing)
621 {
622 char *pchName;
623 char *pchMapping;
624 ControllerMapping_t *pControllerMapping;
625
626 pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
627 if (!pchName) {
628 SDL_SetError("Couldn't parse name from %s", mappingString);
629 return NULL;
630 }
631
632 pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString);
633 if (!pchMapping) {
634 SDL_free(pchName);
635 SDL_SetError("Couldn't parse %s", mappingString);
636 return NULL;
637 }
638
639 pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
640 if (pControllerMapping) {
641 /* Update existing mapping */
642 SDL_free(pControllerMapping->name);
643 pControllerMapping->name = pchName;
644 SDL_free(pControllerMapping->mapping);
645 pControllerMapping->mapping = pchMapping;
646 /* refresh open controllers */
647 SDL_PrivateGameControllerRefreshMapping(pControllerMapping);
648 *existing = SDL_TRUE;
649 } else {
650 pControllerMapping = SDL_malloc(sizeof(*pControllerMapping));
651 if (!pControllerMapping) {
652 SDL_free(pchName);
653 SDL_free(pchMapping);
654 SDL_OutOfMemory();
655 return NULL;
656 }
657 pControllerMapping->guid = jGUID;
658 pControllerMapping->name = pchName;
659 pControllerMapping->mapping = pchMapping;
660 pControllerMapping->next = s_pSupportedControllers;
661 s_pSupportedControllers = pControllerMapping;
662 *existing = SDL_FALSE;
663 }
664 return pControllerMapping;
665 }
666
667 /*
668 * Helper function to determine pre-calculated offset to certain joystick mappings
669 */
SDL_PrivateGetControllerMapping(int device_index)670 ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
671 {
672 SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
673 ControllerMapping_t *mapping;
674
675 mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
676 #if SDL_JOYSTICK_XINPUT
677 if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
678 mapping = s_pXInputMapping;
679 }
680 #endif
681 #if defined(SDL_JOYSTICK_EMSCRIPTEN)
682 if (!mapping && s_pEmscriptenMapping) {
683 mapping = s_pEmscriptenMapping;
684 }
685 #endif
686 #ifdef __LINUX__
687 if (!mapping) {
688 const char *name = SDL_JoystickNameForIndex(device_index);
689 if (name) {
690 if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
691 /* The Linux driver xpad.c maps the wireless dpad to buttons */
692 SDL_bool existing;
693 mapping = SDL_PrivateAddMappingForGUID(jGUID,
694 "none,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
695 &existing);
696 }
697 }
698 }
699 #endif /* __LINUX__ */
700
701 if (!mapping) {
702 const char *name = SDL_JoystickNameForIndex(device_index);
703 if (name) {
704 if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) {
705 mapping = s_pXInputMapping;
706 }
707 }
708 }
709 return mapping;
710 }
711
712 /*
713 * Add or update an entry into the Mappings Database
714 */
715 int
SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw,int freerw)716 SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw)
717 {
718 const char *platform = SDL_GetPlatform();
719 int controllers = 0;
720 char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
721 size_t db_size, platform_len;
722
723 if (rw == NULL) {
724 return SDL_SetError("Invalid RWops");
725 }
726 db_size = (size_t)SDL_RWsize(rw);
727
728 buf = (char *)SDL_malloc(db_size + 1);
729 if (buf == NULL) {
730 if (freerw) {
731 SDL_RWclose(rw);
732 }
733 return SDL_SetError("Could not allocate space to read DB into memory");
734 }
735
736 if (SDL_RWread(rw, buf, db_size, 1) != 1) {
737 if (freerw) {
738 SDL_RWclose(rw);
739 }
740 SDL_free(buf);
741 return SDL_SetError("Could not read DB");
742 }
743
744 if (freerw) {
745 SDL_RWclose(rw);
746 }
747
748 buf[db_size] = '\0';
749 line = buf;
750
751 while (line < buf + db_size) {
752 line_end = SDL_strchr(line, '\n');
753 if (line_end != NULL) {
754 *line_end = '\0';
755 } else {
756 line_end = buf + db_size;
757 }
758
759 /* Extract and verify the platform */
760 tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD);
761 if (tmp != NULL) {
762 tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD);
763 comma = SDL_strchr(tmp, ',');
764 if (comma != NULL) {
765 platform_len = comma - tmp + 1;
766 if (platform_len + 1 < SDL_arraysize(line_platform)) {
767 SDL_strlcpy(line_platform, tmp, platform_len);
768 if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 &&
769 SDL_GameControllerAddMapping(line) > 0) {
770 controllers++;
771 }
772 }
773 }
774 }
775
776 line = line_end + 1;
777 }
778
779 SDL_free(buf);
780 return controllers;
781 }
782
783 /*
784 * Add or update an entry into the Mappings Database
785 */
786 int
SDL_GameControllerAddMapping(const char * mappingString)787 SDL_GameControllerAddMapping(const char *mappingString)
788 {
789 char *pchGUID;
790 SDL_JoystickGUID jGUID;
791 SDL_bool is_xinput_mapping = SDL_FALSE;
792 SDL_bool is_emscripten_mapping = SDL_FALSE;
793 SDL_bool existing = SDL_FALSE;
794 ControllerMapping_t *pControllerMapping;
795
796 if (!mappingString) {
797 return SDL_InvalidParamError("mappingString");
798 }
799
800 pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString);
801 if (!pchGUID) {
802 return SDL_SetError("Couldn't parse GUID from %s", mappingString);
803 }
804 if (!SDL_strcasecmp(pchGUID, "xinput")) {
805 is_xinput_mapping = SDL_TRUE;
806 }
807 if (!SDL_strcasecmp(pchGUID, "emscripten")) {
808 is_emscripten_mapping = SDL_TRUE;
809 }
810 jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
811 SDL_free(pchGUID);
812
813 pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing);
814 if (!pControllerMapping) {
815 return -1;
816 }
817
818 if (existing) {
819 return 0;
820 } else {
821 if (is_xinput_mapping) {
822 s_pXInputMapping = pControllerMapping;
823 }
824 if (is_emscripten_mapping) {
825 s_pEmscriptenMapping = pControllerMapping;
826 }
827 return 1;
828 }
829 }
830
831 /*
832 * Get the mapping string for this GUID
833 */
834 char *
SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)835 SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
836 {
837 char *pMappingString = NULL;
838 ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
839 if (mapping) {
840 char pchGUID[33];
841 size_t needed;
842 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
843 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
844 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
845 pMappingString = SDL_malloc(needed);
846 if (!pMappingString) {
847 SDL_OutOfMemory();
848 return NULL;
849 }
850 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
851 }
852 return pMappingString;
853 }
854
855 /*
856 * Get the mapping string for this device
857 */
858 char *
SDL_GameControllerMapping(SDL_GameController * gamecontroller)859 SDL_GameControllerMapping(SDL_GameController * gamecontroller)
860 {
861 if (!gamecontroller) {
862 return NULL;
863 }
864
865 return SDL_GameControllerMappingForGUID(gamecontroller->mapping.guid);
866 }
867
868 static void
SDL_GameControllerLoadHints()869 SDL_GameControllerLoadHints()
870 {
871 const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
872 if (hint && hint[0]) {
873 size_t nchHints = SDL_strlen(hint);
874 char *pUserMappings = SDL_malloc(nchHints + 1);
875 char *pTempMappings = pUserMappings;
876 SDL_memcpy(pUserMappings, hint, nchHints);
877 pUserMappings[nchHints] = '\0';
878 while (pUserMappings) {
879 char *pchNewLine = NULL;
880
881 pchNewLine = SDL_strchr(pUserMappings, '\n');
882 if (pchNewLine)
883 *pchNewLine = '\0';
884
885 SDL_GameControllerAddMapping(pUserMappings);
886
887 if (pchNewLine) {
888 pUserMappings = pchNewLine + 1;
889 } else {
890 pUserMappings = NULL;
891 }
892 }
893 SDL_free(pTempMappings);
894 }
895 }
896
897 /*
898 * Initialize the game controller system, mostly load our DB of controller config mappings
899 */
900 int
SDL_GameControllerInit(void)901 SDL_GameControllerInit(void)
902 {
903 int i = 0;
904 const char *pMappingString = NULL;
905 pMappingString = s_ControllerMappings[i];
906 while (pMappingString) {
907 SDL_GameControllerAddMapping(pMappingString);
908
909 i++;
910 pMappingString = s_ControllerMappings[i];
911 }
912
913 /* load in any user supplied config */
914 SDL_GameControllerLoadHints();
915
916 /* watch for joy events and fire controller ones if needed */
917 SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL);
918
919 /* Send added events for controllers currently attached */
920 for (i = 0; i < SDL_NumJoysticks(); ++i) {
921 if (SDL_IsGameController(i)) {
922 SDL_Event deviceevent;
923 deviceevent.type = SDL_CONTROLLERDEVICEADDED;
924 deviceevent.cdevice.which = i;
925 SDL_PushEvent(&deviceevent);
926 }
927 }
928
929 return (0);
930 }
931
932
933 /*
934 * Get the implementation dependent name of a controller
935 */
936 const char *
SDL_GameControllerNameForIndex(int device_index)937 SDL_GameControllerNameForIndex(int device_index)
938 {
939 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
940 if (pSupportedController) {
941 return pSupportedController->name;
942 }
943 return NULL;
944 }
945
946
947 /*
948 * Return 1 if the joystick at this device index is a supported controller
949 */
950 SDL_bool
SDL_IsGameController(int device_index)951 SDL_IsGameController(int device_index)
952 {
953 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
954 if (pSupportedController) {
955 return SDL_TRUE;
956 }
957
958 return SDL_FALSE;
959 }
960
961 /*
962 * Open a controller for use - the index passed as an argument refers to
963 * the N'th controller on the system. This index is the value which will
964 * identify this controller in future controller events.
965 *
966 * This function returns a controller identifier, or NULL if an error occurred.
967 */
968 SDL_GameController *
SDL_GameControllerOpen(int device_index)969 SDL_GameControllerOpen(int device_index)
970 {
971 SDL_GameController *gamecontroller;
972 SDL_GameController *gamecontrollerlist;
973 ControllerMapping_t *pSupportedController = NULL;
974
975 if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
976 SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
977 return (NULL);
978 }
979
980 gamecontrollerlist = SDL_gamecontrollers;
981 /* If the controller is already open, return it */
982 while (gamecontrollerlist) {
983 if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
984 gamecontroller = gamecontrollerlist;
985 ++gamecontroller->ref_count;
986 return (gamecontroller);
987 }
988 gamecontrollerlist = gamecontrollerlist->next;
989 }
990
991 /* Find a controller mapping */
992 pSupportedController = SDL_PrivateGetControllerMapping(device_index);
993 if (!pSupportedController) {
994 SDL_SetError("Couldn't find mapping for device (%d)", device_index);
995 return (NULL);
996 }
997
998 /* Create and initialize the joystick */
999 gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
1000 if (gamecontroller == NULL) {
1001 SDL_OutOfMemory();
1002 return NULL;
1003 }
1004
1005 SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
1006 gamecontroller->joystick = SDL_JoystickOpen(device_index);
1007 if (!gamecontroller->joystick) {
1008 SDL_free(gamecontroller);
1009 return NULL;
1010 }
1011
1012 SDL_PrivateLoadButtonMapping(&gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
1013
1014 /* The triggers are mapped from -32768 to 32767, where -32768 is the 'unpressed' value */
1015 {
1016 int leftTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT];
1017 int rightTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT];
1018 if (leftTriggerMapping >= 0) {
1019 gamecontroller->joystick->axes[leftTriggerMapping] =
1020 gamecontroller->joystick->axes_zero[leftTriggerMapping] = (Sint16)-32768;
1021 }
1022 if (rightTriggerMapping >= 0) {
1023 gamecontroller->joystick->axes[rightTriggerMapping] =
1024 gamecontroller->joystick->axes_zero[rightTriggerMapping] = (Sint16)-32768;
1025 }
1026 }
1027
1028 /* Add joystick to list */
1029 ++gamecontroller->ref_count;
1030 /* Link the joystick in the list */
1031 gamecontroller->next = SDL_gamecontrollers;
1032 SDL_gamecontrollers = gamecontroller;
1033
1034 SDL_SYS_JoystickUpdate(gamecontroller->joystick);
1035
1036 return (gamecontroller);
1037 }
1038
1039 /*
1040 * Manually pump for controller updates.
1041 */
1042 void
SDL_GameControllerUpdate(void)1043 SDL_GameControllerUpdate(void)
1044 {
1045 /* Just for API completeness; the joystick API does all the work. */
1046 SDL_JoystickUpdate();
1047 }
1048
1049
1050 /*
1051 * Get the current state of an axis control on a controller
1052 */
1053 Sint16
SDL_GameControllerGetAxis(SDL_GameController * gamecontroller,SDL_GameControllerAxis axis)1054 SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
1055 {
1056 if (!gamecontroller)
1057 return 0;
1058
1059 if (gamecontroller->mapping.axes[axis] >= 0) {
1060 Sint16 value = (SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axes[axis]));
1061 switch (axis) {
1062 case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
1063 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
1064 /* Shift it to be 0 - 32767 */
1065 value = value / 2 + 16384;
1066 default:
1067 break;
1068 }
1069 return value;
1070 } else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) {
1071 Uint8 value;
1072 value = SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis]);
1073 if (value > 0)
1074 return 32767;
1075 return 0;
1076 }
1077 return 0;
1078 }
1079
1080
1081 /*
1082 * Get the current state of a button on a controller
1083 */
1084 Uint8
SDL_GameControllerGetButton(SDL_GameController * gamecontroller,SDL_GameControllerButton button)1085 SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
1086 {
1087 if (!gamecontroller)
1088 return 0;
1089
1090 if (gamecontroller->mapping.buttons[button] >= 0) {
1091 return (SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttons[button]));
1092 } else if (gamecontroller->mapping.axesasbutton[button] >= 0) {
1093 Sint16 value;
1094 value = SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button]);
1095 if (ABS(value) > 32768/2)
1096 return 1;
1097 return 0;
1098 } else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) {
1099 Uint8 value;
1100 value = SDL_JoystickGetHat(gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat);
1101
1102 if (value & gamecontroller->mapping.hatasbutton[button].mask)
1103 return 1;
1104 return 0;
1105 }
1106
1107 return 0;
1108 }
1109
1110 /*
1111 * Return if the joystick in question is currently attached to the system,
1112 * \return 0 if not plugged in, 1 if still present.
1113 */
1114 SDL_bool
SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)1115 SDL_GameControllerGetAttached(SDL_GameController * gamecontroller)
1116 {
1117 if (!gamecontroller)
1118 return SDL_FALSE;
1119
1120 return SDL_JoystickGetAttached(gamecontroller->joystick);
1121 }
1122
1123
1124 const char *
SDL_GameControllerName(SDL_GameController * gamecontroller)1125 SDL_GameControllerName(SDL_GameController * gamecontroller)
1126 {
1127 if (!gamecontroller)
1128 return NULL;
1129
1130 return (gamecontroller->mapping.name);
1131 }
1132
1133
1134 /*
1135 * Get the joystick for this controller
1136 */
SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)1137 SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
1138 {
1139 if (!gamecontroller)
1140 return NULL;
1141
1142 return gamecontroller->joystick;
1143 }
1144
1145
1146 /*
1147 * Find the SDL_GameController that owns this instance id
1148 */
1149 SDL_GameController *
SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)1150 SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
1151 {
1152 SDL_GameController *gamecontroller = SDL_gamecontrollers;
1153 while (gamecontroller) {
1154 if (gamecontroller->joystick->instance_id == joyid) {
1155 return gamecontroller;
1156 }
1157 gamecontroller = gamecontroller->next;
1158 }
1159
1160 return NULL;
1161 }
1162
1163
1164 /**
1165 * Get the SDL joystick layer binding for this controller axis mapping
1166 */
SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller,SDL_GameControllerAxis axis)1167 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
1168 {
1169 SDL_GameControllerButtonBind bind;
1170 SDL_memset(&bind, 0x0, sizeof(bind));
1171
1172 if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID)
1173 return bind;
1174
1175 if (gamecontroller->mapping.axes[axis] >= 0) {
1176 bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
1177 bind.value.button = gamecontroller->mapping.axes[axis];
1178 } else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) {
1179 bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
1180 bind.value.button = gamecontroller->mapping.buttonasaxis[axis];
1181 }
1182
1183 return bind;
1184 }
1185
1186
1187 /**
1188 * Get the SDL joystick layer binding for this controller button mapping
1189 */
SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller,SDL_GameControllerButton button)1190 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
1191 {
1192 SDL_GameControllerButtonBind bind;
1193 SDL_memset(&bind, 0x0, sizeof(bind));
1194
1195 if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID)
1196 return bind;
1197
1198 if (gamecontroller->mapping.buttons[button] >= 0) {
1199 bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
1200 bind.value.button = gamecontroller->mapping.buttons[button];
1201 } else if (gamecontroller->mapping.axesasbutton[button] >= 0) {
1202 bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
1203 bind.value.axis = gamecontroller->mapping.axesasbutton[button];
1204 } else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) {
1205 bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
1206 bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
1207 bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
1208 }
1209
1210 return bind;
1211 }
1212
1213
1214 void
SDL_GameControllerClose(SDL_GameController * gamecontroller)1215 SDL_GameControllerClose(SDL_GameController * gamecontroller)
1216 {
1217 SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
1218
1219 if (!gamecontroller)
1220 return;
1221
1222 /* First decrement ref count */
1223 if (--gamecontroller->ref_count > 0) {
1224 return;
1225 }
1226
1227 SDL_JoystickClose(gamecontroller->joystick);
1228
1229 gamecontrollerlist = SDL_gamecontrollers;
1230 gamecontrollerlistprev = NULL;
1231 while (gamecontrollerlist) {
1232 if (gamecontroller == gamecontrollerlist) {
1233 if (gamecontrollerlistprev) {
1234 /* unlink this entry */
1235 gamecontrollerlistprev->next = gamecontrollerlist->next;
1236 } else {
1237 SDL_gamecontrollers = gamecontroller->next;
1238 }
1239
1240 break;
1241 }
1242 gamecontrollerlistprev = gamecontrollerlist;
1243 gamecontrollerlist = gamecontrollerlist->next;
1244 }
1245
1246 SDL_free(gamecontroller);
1247 }
1248
1249
1250 /*
1251 * Quit the controller subsystem
1252 */
1253 void
SDL_GameControllerQuit(void)1254 SDL_GameControllerQuit(void)
1255 {
1256 ControllerMapping_t *pControllerMap;
1257 while (SDL_gamecontrollers) {
1258 SDL_gamecontrollers->ref_count = 1;
1259 SDL_GameControllerClose(SDL_gamecontrollers);
1260 }
1261
1262 while (s_pSupportedControllers) {
1263 pControllerMap = s_pSupportedControllers;
1264 s_pSupportedControllers = s_pSupportedControllers->next;
1265 SDL_free(pControllerMap->name);
1266 SDL_free(pControllerMap->mapping);
1267 SDL_free(pControllerMap);
1268 }
1269
1270 SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL);
1271
1272 }
1273
1274 /*
1275 * Event filter to transform joystick events into appropriate game controller ones
1276 */
1277 int
SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller,SDL_GameControllerAxis axis,Sint16 value)1278 SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
1279 {
1280 int posted;
1281
1282 /* translate the event, if desired */
1283 posted = 0;
1284 #if !SDL_EVENTS_DISABLED
1285 if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
1286 SDL_Event event;
1287 event.type = SDL_CONTROLLERAXISMOTION;
1288 event.caxis.which = gamecontroller->joystick->instance_id;
1289 event.caxis.axis = axis;
1290 event.caxis.value = value;
1291 posted = SDL_PushEvent(&event) == 1;
1292 }
1293 #endif /* !SDL_EVENTS_DISABLED */
1294 return (posted);
1295 }
1296
1297
1298 /*
1299 * Event filter to transform joystick events into appropriate game controller ones
1300 */
1301 int
SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller,SDL_GameControllerButton button,Uint8 state)1302 SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
1303 {
1304 int posted;
1305 #if !SDL_EVENTS_DISABLED
1306 SDL_Event event;
1307
1308 if (button == SDL_CONTROLLER_BUTTON_INVALID)
1309 return (0);
1310
1311 switch (state) {
1312 case SDL_PRESSED:
1313 event.type = SDL_CONTROLLERBUTTONDOWN;
1314 break;
1315 case SDL_RELEASED:
1316 event.type = SDL_CONTROLLERBUTTONUP;
1317 break;
1318 default:
1319 /* Invalid state -- bail */
1320 return (0);
1321 }
1322 #endif /* !SDL_EVENTS_DISABLED */
1323
1324 /* translate the event, if desired */
1325 posted = 0;
1326 #if !SDL_EVENTS_DISABLED
1327 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
1328 event.cbutton.which = gamecontroller->joystick->instance_id;
1329 event.cbutton.button = button;
1330 event.cbutton.state = state;
1331 posted = SDL_PushEvent(&event) == 1;
1332 }
1333 #endif /* !SDL_EVENTS_DISABLED */
1334 return (posted);
1335 }
1336
1337 /*
1338 * Turn off controller events
1339 */
1340 int
SDL_GameControllerEventState(int state)1341 SDL_GameControllerEventState(int state)
1342 {
1343 #if SDL_EVENTS_DISABLED
1344 return SDL_IGNORE;
1345 #else
1346 const Uint32 event_list[] = {
1347 SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
1348 SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
1349 };
1350 unsigned int i;
1351
1352 switch (state) {
1353 case SDL_QUERY:
1354 state = SDL_IGNORE;
1355 for (i = 0; i < SDL_arraysize(event_list); ++i) {
1356 state = SDL_EventState(event_list[i], SDL_QUERY);
1357 if (state == SDL_ENABLE) {
1358 break;
1359 }
1360 }
1361 break;
1362 default:
1363 for (i = 0; i < SDL_arraysize(event_list); ++i) {
1364 SDL_EventState(event_list[i], state);
1365 }
1366 break;
1367 }
1368 return (state);
1369 #endif /* SDL_EVENTS_DISABLED */
1370 }
1371
1372 /* vi: set ts=4 sw=4 expandtab: */
1373