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