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