zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_gamecontroller.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 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_config.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 
37 /* a list of currently opened game controllers */
39 
40 /* keep track of the hat and mask value that transforms this hat movement into a button/axis press */
41 struct _SDL_HatMapping
42 {
43  int hat;
44  Uint8 mask;
45 };
46 
47 #define k_nMaxReverseEntries 20
48 
53 #define k_nMaxHatEntries 0x3f + 1
54 
55 /* our in memory mapping db between joystick objects and controller mappings */
56 struct _SDL_ControllerMapping
57 {
58  SDL_JoystickGUID guid;
59  const char *name;
60 
61  /* mapping of axis/button id to controller version */
62  int axes[SDL_CONTROLLER_AXIS_MAX];
63  int buttonasaxis[SDL_CONTROLLER_AXIS_MAX];
64 
65  int buttons[SDL_CONTROLLER_BUTTON_MAX];
66  int axesasbutton[SDL_CONTROLLER_BUTTON_MAX];
67  struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX];
68 
69  /* reverse mapping, joystick indices to buttons */
72 
76 
77 };
78 
79 
80 /* our hard coded list of mapping support */
81 typedef struct _ControllerMapping_t
82 {
83  SDL_JoystickGUID guid;
84  char *name;
85  char *mapping;
86  struct _ControllerMapping_t *next;
88 
90 #ifdef SDL_JOYSTICK_DINPUT
91 static ControllerMapping_t *s_pXInputMapping = NULL;
92 #endif
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 
107 
108 /*
109  * Event filter to fire controller events from joystick ones
110  */
112 {
113  switch( event->type )
114  {
115  case SDL_JOYAXISMOTION:
116  {
117  SDL_GameController *controllerlist;
118 
119  if ( event->jaxis.axis >= k_nMaxReverseEntries ) break;
120 
121  controllerlist = SDL_gamecontrollers;
122  while ( controllerlist )
123  {
124  if ( controllerlist->joystick->instance_id == event->jaxis.which )
125  {
126  if ( controllerlist->mapping.raxes[event->jaxis.axis] >= 0 ) /* simple axis to axis, send it through */
127  {
128  SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis];
129  Sint16 value = event->jaxis.value;
130  switch (axis)
131  {
134  /* Shift it to be 0 - 32767. */
135  value = value / 2 + 16384;
136  default:
137  break;
138  }
139  SDL_PrivateGameControllerAxis( controllerlist, axis, value );
140  }
141  else if ( controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0 ) /* simulate an axis as a button */
142  {
143  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED );
144  }
145  break;
146  }
147  controllerlist = controllerlist->next;
148  }
149  }
150  break;
151  case SDL_JOYBUTTONDOWN:
152  case SDL_JOYBUTTONUP:
153  {
154  SDL_GameController *controllerlist;
155 
156  if ( event->jbutton.button >= k_nMaxReverseEntries ) break;
157 
158  controllerlist = SDL_gamecontrollers;
159  while ( controllerlist )
160  {
161  if ( controllerlist->joystick->instance_id == event->jbutton.which )
162  {
163  if ( controllerlist->mapping.rbuttons[event->jbutton.button] >= 0 ) /* simple button as button */
164  {
165  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state );
166  }
167  else if ( controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0 ) /* an button pretending to be an axis */
168  {
169  SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0 );
170  }
171  break;
172  }
173  controllerlist = controllerlist->next;
174  }
175  }
176  break;
177  case SDL_JOYHATMOTION:
178  {
179  SDL_GameController *controllerlist;
180 
181  if ( event->jhat.hat >= 4 ) break;
182 
183  controllerlist = SDL_gamecontrollers;
184  while ( controllerlist )
185  {
186  if ( controllerlist->joystick->instance_id == event->jhat.which )
187  {
188  Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value;
189  /* Get list of removed bits (button release) */
190  Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame;
191  /* the hat idx in the high nibble */
192  int bHighHat = event->jhat.hat << 4;
193 
194  if ( bChanged & SDL_HAT_DOWN )
195  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED );
196  if ( bChanged & SDL_HAT_UP )
197  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED );
198  if ( bChanged & SDL_HAT_LEFT )
199  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED );
200  if ( bChanged & SDL_HAT_RIGHT )
201  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED );
202 
203  /* Get list of added bits (button press) */
204  bChanged = event->jhat.value ^ bSame;
205 
206  if ( bChanged & SDL_HAT_DOWN )
207  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED );
208  if ( bChanged & SDL_HAT_UP )
209  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED );
210  if ( bChanged & SDL_HAT_LEFT )
211  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED );
212  if ( bChanged & SDL_HAT_RIGHT )
213  SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED );
214 
215  /* update our state cache */
216  controllerlist->hatState[event->jhat.hat] = event->jhat.value;
217 
218  break;
219  }
220  controllerlist = controllerlist->next;
221  }
222  }
223  break;
224  case SDL_JOYDEVICEADDED:
225  {
226  if ( SDL_IsGameController(event->jdevice.which ) )
227  {
228  SDL_Event deviceevent;
229  deviceevent.type = SDL_CONTROLLERDEVICEADDED;
230  deviceevent.cdevice.which = event->jdevice.which;
231  SDL_PushEvent(&deviceevent);
232  }
233  }
234  break;
236  {
237  SDL_GameController *controllerlist = SDL_gamecontrollers;
238  while ( controllerlist )
239  {
240  if ( controllerlist->joystick->instance_id == event->jdevice.which )
241  {
242  SDL_Event deviceevent;
243  deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
244  deviceevent.cdevice.which = event->jdevice.which;
245  SDL_PushEvent(&deviceevent);
246  break;
247  }
248  controllerlist = controllerlist->next;
249  }
250  }
251  break;
252  default:
253  break;
254  }
255 
256  return 1;
257 }
258 
259 /*
260  * Helper function to scan the mappings database for a controller with the specified GUID
261  */
263 {
264  ControllerMapping_t *pSupportedController = s_pSupportedControllers;
265  while ( pSupportedController )
266  {
267  if ( !SDL_memcmp( guid, &pSupportedController->guid, sizeof(*guid) ) )
268  {
269  return pSupportedController;
270  }
271  pSupportedController = pSupportedController->next;
272  }
273  return NULL;
274 }
275 
276 /*
277  * Helper function to determine pre-calculated offset to certain joystick mappings
278  */
280 {
281 #ifdef SDL_JOYSTICK_DINPUT
282  if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping )
283  {
284  return s_pXInputMapping;
285  }
286  else
287 #endif
288  {
289  SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
291  }
292 
293  return NULL;
294 }
295 
296 static const char* map_StringForControllerAxis[] = {
297  "leftx",
298  "lefty",
299  "rightx",
300  "righty",
301  "lefttrigger",
302  "righttrigger",
303  NULL
304 };
305 
306 /*
307  * convert a string to its enum equivalent
308  */
310 {
311  int entry;
312  if ( !pchString || !pchString[0] )
314 
315  for ( entry = 0; map_StringForControllerAxis[entry]; ++entry)
316  {
317  if ( !SDL_strcasecmp( pchString, map_StringForControllerAxis[entry] ) )
318  return entry;
319  }
321 }
322 
323 /*
324  * convert an enum to its string equivalent
325  */
327 {
329  {
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  */
358 {
359  int entry;
360  if ( !pchString || !pchString[0] )
362 
363  for ( entry = 0; map_StringForControllerButton[entry]; ++entry)
364  {
365  if ( !SDL_strcasecmp( pchString, map_StringForControllerButton[entry] ) )
366  return entry;
367  }
369 }
370 
371 /*
372  * convert an enum to its string equivalent
373  */
375 {
377  {
378  return map_StringForControllerButton[axis];
379  }
380  return NULL;
381 }
382 
383 /*
384  * given a controller button name and a joystick name update our mapping structure with it
385  */
386 void SDL_PrivateGameControllerParseButton( const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping )
387 {
388  int iSDLButton = 0;
391  button = SDL_GameControllerGetButtonFromString( szGameButton );
392  axis = SDL_GameControllerGetAxisFromString( szGameButton );
393  iSDLButton = SDL_atoi( &szJoystickButton[1] );
394 
395  if ( szJoystickButton[0] == 'a' )
396  {
397  if ( iSDLButton >= k_nMaxReverseEntries )
398  {
399  SDL_SetError("Axis index too large: %d", iSDLButton );
400  return;
401  }
402  if ( axis != SDL_CONTROLLER_AXIS_INVALID )
403  {
404  pMapping->axes[ axis ] = iSDLButton;
405  pMapping->raxes[ iSDLButton ] = axis;
406  }
407  else if ( button != SDL_CONTROLLER_BUTTON_INVALID )
408  {
409  pMapping->axesasbutton[ button ] = iSDLButton;
410  pMapping->raxesasbutton[ iSDLButton ] = button;
411  }
412  else
413  {
414  SDL_assert( !"How did we get here?" );
415  }
416 
417  }
418  else if ( szJoystickButton[0] == 'b' )
419  {
420  if ( iSDLButton >= k_nMaxReverseEntries )
421  {
422  SDL_SetError("Button index too large: %d", iSDLButton );
423  return;
424  }
425  if ( button != SDL_CONTROLLER_BUTTON_INVALID )
426  {
427  pMapping->buttons[ button ] = iSDLButton;
428  pMapping->rbuttons[ iSDLButton ] = button;
429  }
430  else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
431  {
432  pMapping->buttonasaxis[ axis ] = iSDLButton;
433  pMapping->rbuttonasaxis[ iSDLButton ] = axis;
434  }
435  else
436  {
437  SDL_assert( !"How did we get here?" );
438  }
439  }
440  else if ( szJoystickButton[0] == 'h' )
441  {
442  int hat = SDL_atoi( &szJoystickButton[1] );
443  int mask = SDL_atoi( &szJoystickButton[3] );
444  if (hat >= 4) {
445  SDL_SetError("Hat index too large: %d", iSDLButton );
446  }
447 
448  if ( button != SDL_CONTROLLER_BUTTON_INVALID )
449  {
450  int ridx;
451  pMapping->hatasbutton[ button ].hat = hat;
452  pMapping->hatasbutton[ button ].mask = mask;
453  ridx = (hat << 4) | mask;
454  pMapping->rhatasbutton[ ridx ] = button;
455  }
456  else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
457  {
458  SDL_assert( !"Support hat as axis" );
459  }
460  else
461  {
462  SDL_assert( !"How did we get here?" );
463  }
464  }
465 }
466 
467 
468 /*
469  * given a controller mapping string update our mapping object
470  */
471 static void
472 SDL_PrivateGameControllerParseControllerConfigString( struct _SDL_ControllerMapping *pMapping, const char *pchString )
473 {
474  char szGameButton[20];
475  char szJoystickButton[20];
476  SDL_bool bGameButton = SDL_TRUE;
477  int i = 0;
478  const char *pchPos = pchString;
479 
480  SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
481  SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
482 
483  while ( pchPos && *pchPos )
484  {
485  if ( *pchPos == ':' )
486  {
487  i = 0;
488  bGameButton = SDL_FALSE;
489  }
490  else if ( *pchPos == ' ' )
491  {
492 
493  }
494  else if ( *pchPos == ',' )
495  {
496  i = 0;
497  bGameButton = SDL_TRUE;
498  SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
499  SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
500  SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
501 
502  }
503  else if ( bGameButton )
504  {
505  if ( i >= sizeof(szGameButton))
506  {
507  SDL_SetError( "Button name too large: %s", szGameButton );
508  return;
509  }
510  szGameButton[i] = *pchPos;
511  i++;
512  }
513  else
514  {
515  if ( i >= sizeof(szJoystickButton))
516  {
517  SDL_SetError( "Joystick button name too large: %s", szJoystickButton );
518  return;
519  }
520  szJoystickButton[i] = *pchPos;
521  i++;
522  }
523  pchPos++;
524  }
525 
526  SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
527 
528 }
529 
530 /*
531  * Make a new button mapping struct
532  */
533 void SDL_PrivateLoadButtonMapping( struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping )
534 {
535  int j;
536 
537  pMapping->guid = guid;
538  pMapping->name = pchName;
539 
540  /* set all the button mappings to non defaults */
541  for ( j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++ )
542  {
543  pMapping->axes[j] = -1;
544  pMapping->buttonasaxis[j] = -1;
545  }
546  for ( j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++ )
547  {
548  pMapping->buttons[j] = -1;
549  pMapping->axesasbutton[j] = -1;
550  pMapping->hatasbutton[j].hat = -1;
551  }
552 
553  for ( j = 0; j < k_nMaxReverseEntries; j++ )
554  {
555  pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
556  pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
557  pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
558  pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
559  }
560 
561  for (j = 0; j < k_nMaxHatEntries; j++)
562  {
563  pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
564  }
565 
567 }
568 
569 
570 /*
571  * grab the guid string from a mapping string
572  */
574 {
575  const char *pFirstComma = SDL_strchr( pMapping, ',' );
576  if ( pFirstComma )
577  {
578  char *pchGUID = SDL_malloc( pFirstComma - pMapping + 1 );
579  if ( !pchGUID )
580  {
581  SDL_OutOfMemory();
582  return NULL;
583  }
584  SDL_memcpy( pchGUID, pMapping, pFirstComma - pMapping );
585  pchGUID[ pFirstComma - pMapping ] = 0;
586  return pchGUID;
587  }
588  return NULL;
589 }
590 
591 
592 /*
593  * grab the name string from a mapping string
594  */
596 {
597  const char *pFirstComma, *pSecondComma;
598  char *pchName;
599 
600  pFirstComma = SDL_strchr( pMapping, ',' );
601  if ( !pFirstComma )
602  return NULL;
603 
604  pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
605  if ( !pSecondComma )
606  return NULL;
607 
608  pchName = SDL_malloc( pSecondComma - pFirstComma );
609  if ( !pchName )
610  {
611  SDL_OutOfMemory();
612  return NULL;
613  }
614  SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma );
615  pchName[ pSecondComma - pFirstComma - 1 ] = 0;
616  return pchName;
617 }
618 
619 
620 /*
621  * grab the button mapping string from a mapping string
622  */
624 {
625  const char *pFirstComma, *pSecondComma;
626 
627  pFirstComma = SDL_strchr( pMapping, ',' );
628  if ( !pFirstComma )
629  return NULL;
630 
631  pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
632  if ( !pSecondComma )
633  return NULL;
634 
635  return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
636 }
637 
639 {
640  SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
641  while ( gamecontrollerlist )
642  {
643  if ( !SDL_memcmp( &gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid) ) )
644  {
646  event.type = SDL_CONTROLLERDEVICEREMAPPED;
647  event.cdevice.which = gamecontrollerlist->joystick->instance_id;
648  SDL_PushEvent(&event);
649 
650  /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
651  SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
652  }
653 
654  gamecontrollerlist = gamecontrollerlist->next;
655  }
656 }
657 
658 /*
659  * Add or update an entry into the Mappings Database
660  */
661 int
662 SDL_GameControllerAddMapping( const char *mappingString )
663 {
664  char *pchGUID;
665  char *pchName;
666  char *pchMapping;
667  SDL_JoystickGUID jGUID;
668  ControllerMapping_t *pControllerMapping;
669 #ifdef SDL_JOYSTICK_DINPUT
670  SDL_bool is_xinput_mapping = SDL_FALSE;
671 #endif
672 
673  pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( mappingString );
674  if (!pchGUID) {
675  return -1;
676  }
677 #ifdef SDL_JOYSTICK_DINPUT
678  if ( !SDL_strcasecmp( pchGUID, "xinput" ) ) {
679  is_xinput_mapping = SDL_TRUE;
680  }
681 #endif
682  jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
683  SDL_free(pchGUID);
684 
685  pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
686 
687  pchName = SDL_PrivateGetControllerNameFromMappingString( mappingString );
688  if (!pchName) return -1;
689 
690  pchMapping = SDL_PrivateGetControllerMappingFromMappingString( mappingString );
691  if (!pchMapping) {
692  SDL_free( pchName );
693  return -1;
694  }
695 
696  if (pControllerMapping) {
697  /* Update existing mapping */
698  SDL_free( pControllerMapping->name );
699  pControllerMapping->name = pchName;
700  SDL_free( pControllerMapping->mapping );
701  pControllerMapping->mapping = pchMapping;
702  /* refresh open controllers */
703  SDL_PrivateGameControllerRefreshMapping( pControllerMapping );
704  return 0;
705  } else {
706  pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
707  if (!pControllerMapping) {
708  SDL_free( pchName );
709  SDL_free( pchMapping );
710  return SDL_OutOfMemory();
711  }
712 #ifdef SDL_JOYSTICK_DINPUT
713  if ( is_xinput_mapping )
714  {
715  s_pXInputMapping = pControllerMapping;
716  }
717 #endif
718  pControllerMapping->guid = jGUID;
719  pControllerMapping->name = pchName;
720  pControllerMapping->mapping = pchMapping;
721  pControllerMapping->next = s_pSupportedControllers;
722  s_pSupportedControllers = pControllerMapping;
723  return 1;
724  }
725 }
726 
727 /*
728  * Get the mapping string for this GUID
729  */
730 char *
732 {
733  char *pMappingString = NULL;
735  if (mapping) {
736  char pchGUID[33];
737  size_t needed;
738  SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
739  /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
740  needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
741  pMappingString = SDL_malloc( needed );
742  SDL_snprintf( pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping );
743  }
744  return pMappingString;
745 }
746 
747 /*
748  * Get the mapping string for this device
749  */
750 char *
752 {
753  return SDL_GameControllerMappingForGUID( gamecontroller->mapping.guid );
754 }
755 
756 static void
758 {
759  const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
760  if ( hint && hint[0] ) {
761  int nchHints = SDL_strlen( hint );
762  char *pUserMappings = SDL_malloc( nchHints + 1 );
763  char *pTempMappings = pUserMappings;
764  SDL_memcpy( pUserMappings, hint, nchHints );
765  while ( pUserMappings ) {
766  char *pchNewLine = NULL;
767 
768  pchNewLine = SDL_strchr( pUserMappings, '\n' );
769  if ( pchNewLine )
770  *pchNewLine = '\0';
771 
772  SDL_GameControllerAddMapping( pUserMappings );
773 
774  if ( pchNewLine )
775  pUserMappings = pchNewLine + 1;
776  else
777  pUserMappings = NULL;
778  }
779  SDL_free(pTempMappings);
780  }
781 }
782 
783 /*
784  * Initialize the game controller system, mostly load our DB of controller config mappings
785  */
786 int
788 {
789  int i = 0;
790  const char *pMappingString = NULL;
792  pMappingString = s_ControllerMappings[i];
793  while ( pMappingString )
794  {
795  SDL_GameControllerAddMapping( pMappingString );
796 
797  i++;
798  pMappingString = s_ControllerMappings[i];
799  }
800 
801  /* load in any user supplied config */
803 
804  /* watch for joy events and fire controller ones if needed */
806 
807  return (0);
808 }
809 
810 
811 /*
812  * Get the implementation dependent name of a controller
813  */
814 const char *
816 {
817  ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
818  if ( pSupportedController )
819  {
820  return pSupportedController->name;
821  }
822  return NULL;
823 }
824 
825 
826 /*
827  * Return 1 if the joystick at this device index is a supported controller
828  */
829 SDL_bool
830 SDL_IsGameController(int device_index)
831 {
832  ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
833  if ( pSupportedController )
834  {
835  return SDL_TRUE;
836  }
837 
838  return SDL_FALSE;
839 }
840 
841 /*
842  * Open a controller for use - the index passed as an argument refers to
843  * the N'th controller on the system. This index is the value which will
844  * identify this controller in future controller events.
845  *
846  * This function returns a controller identifier, or NULL if an error occurred.
847  */
849 SDL_GameControllerOpen(int device_index)
850 {
851  SDL_GameController *gamecontroller;
852  SDL_GameController *gamecontrollerlist;
853  ControllerMapping_t *pSupportedController = NULL;
854 
855  if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
856  SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
857  return (NULL);
858  }
859 
860  gamecontrollerlist = SDL_gamecontrollers;
861  /* If the controller is already open, return it */
862  while ( gamecontrollerlist )
863  {
864  if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) {
865  gamecontroller = gamecontrollerlist;
866  ++gamecontroller->ref_count;
867  return (gamecontroller);
868  }
869  gamecontrollerlist = gamecontrollerlist->next;
870  }
871 
872  /* Find a controller mapping */
873  pSupportedController = SDL_PrivateGetControllerMapping(device_index);
874  if ( !pSupportedController ) {
875  SDL_SetError("Couldn't find mapping for device (%d)", device_index );
876  return (NULL);
877  }
878 
879  /* Create and initialize the joystick */
880  gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
881  if (gamecontroller == NULL) {
882  SDL_OutOfMemory();
883  return NULL;
884  }
885 
886  SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
887  gamecontroller->joystick = SDL_JoystickOpen(device_index);
888  if ( !gamecontroller->joystick ) {
889  SDL_free(gamecontroller);
890  return NULL;
891  }
892 
893  SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping );
894 
895  /* Add joystick to list */
896  ++gamecontroller->ref_count;
897  /* Link the joystick in the list */
898  gamecontroller->next = SDL_gamecontrollers;
899  SDL_gamecontrollers = gamecontroller;
900 
901  SDL_SYS_JoystickUpdate( gamecontroller->joystick );
902 
903  return (gamecontroller);
904 }
905 
906 /*
907  * Manually pump for controller updates.
908  */
909 void
911 {
912  /* Just for API completeness; the joystick API does all the work. */
914 }
915 
916 
917 /*
918  * Get the current state of an axis control on a controller
919  */
920 Sint16
922 {
923  if ( !gamecontroller )
924  return 0;
925 
926  if (gamecontroller->mapping.axes[axis] >= 0 )
927  {
928  Sint16 value = ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) );
929  switch (axis)
930  {
933  /* Shift it to be 0 - 32767. */
934  value = value / 2 + 16384;
935  default:
936  break;
937  }
938  return value;
939  }
940  else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
941  {
942  Uint8 value;
943  value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] );
944  if ( value > 0 )
945  return 32767;
946  return 0;
947  }
948  return 0;
949 }
950 
951 
952 /*
953  * Get the current state of a button on a controller
954  */
955 Uint8
957 {
958  if ( !gamecontroller )
959  return 0;
960 
961  if ( gamecontroller->mapping.buttons[button] >= 0 )
962  {
963  return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) );
964  }
965  else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
966  {
967  Sint16 value;
968  value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] );
969  if ( ABS(value) > 32768/2 )
970  return 1;
971  return 0;
972  }
973  else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
974  {
975  Uint8 value;
976  value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat );
977 
978  if ( value & gamecontroller->mapping.hatasbutton[button].mask )
979  return 1;
980  return 0;
981  }
982 
983  return 0;
984 }
985 
986 /*
987  * Return if the joystick in question is currently attached to the system,
988  * \return 0 if not plugged in, 1 if still present.
989  */
990 SDL_bool
992 {
993  if ( !gamecontroller )
994  return SDL_FALSE;
995 
996  return SDL_JoystickGetAttached(gamecontroller->joystick);
997 }
998 
999 
1000 /*
1001  * Get the number of multi-dimensional axis controls on a joystick
1002  */
1003 const char *
1005 {
1006  if ( !gamecontroller )
1007  return NULL;
1008 
1009  return (gamecontroller->mapping.name);
1010 }
1011 
1012 
1013 /*
1014  * Get the joystick for this controller
1015  */
1017 {
1018  if ( !gamecontroller )
1019  return NULL;
1020 
1021  return gamecontroller->joystick;
1022 }
1023 
1028 {
1030  SDL_memset( &bind, 0x0, sizeof(bind) );
1031 
1032  if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID )
1033  return bind;
1034 
1035  if (gamecontroller->mapping.axes[axis] >= 0 )
1036  {
1038  bind.value.button = gamecontroller->mapping.axes[axis];
1039  }
1040  else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
1041  {
1043  bind.value.button = gamecontroller->mapping.buttonasaxis[axis];
1044  }
1045 
1046  return bind;
1047 }
1048 
1049 
1054 {
1056  SDL_memset( &bind, 0x0, sizeof(bind) );
1057 
1058  if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID )
1059  return bind;
1060 
1061  if ( gamecontroller->mapping.buttons[button] >= 0 )
1062  {
1064  bind.value.button = gamecontroller->mapping.buttons[button];
1065  }
1066  else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
1067  {
1069  bind.value.axis = gamecontroller->mapping.axesasbutton[button];
1070  }
1071  else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
1072  {
1074  bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
1075  bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
1076  }
1077 
1078  return bind;
1079 }
1080 
1081 
1082 /*
1083  * Close a joystick previously opened with SDL_JoystickOpen()
1084  */
1085 void
1087 {
1088  SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
1089 
1090  if ( !gamecontroller )
1091  return;
1092 
1093  /* First decrement ref count */
1094  if (--gamecontroller->ref_count > 0) {
1095  return;
1096  }
1097 
1098  SDL_JoystickClose( gamecontroller->joystick );
1099 
1100  gamecontrollerlist = SDL_gamecontrollers;
1101  gamecontrollerlistprev = NULL;
1102  while ( gamecontrollerlist )
1103  {
1104  if (gamecontroller == gamecontrollerlist)
1105  {
1106  if ( gamecontrollerlistprev )
1107  {
1108  /* unlink this entry */
1109  gamecontrollerlistprev->next = gamecontrollerlist->next;
1110  }
1111  else
1112  {
1113  SDL_gamecontrollers = gamecontroller->next;
1114  }
1115 
1116  break;
1117  }
1118  gamecontrollerlistprev = gamecontrollerlist;
1119  gamecontrollerlist = gamecontrollerlist->next;
1120  }
1121 
1122  SDL_free(gamecontroller);
1123 }
1124 
1125 
1126 /*
1127  * Quit the controller subsystem
1128  */
1129 void
1131 {
1132  ControllerMapping_t *pControllerMap;
1133  while ( SDL_gamecontrollers )
1134  {
1135  SDL_gamecontrollers->ref_count = 1;
1137  }
1138 
1139  while ( s_pSupportedControllers )
1140  {
1141  pControllerMap = s_pSupportedControllers;
1143  SDL_free( pControllerMap->name );
1144  SDL_free( pControllerMap );
1145  }
1146 
1148 
1149 }
1150 
1151 /*
1152  * Event filter to transform joystick events into appropriate game controller ones
1153  */
1154 int
1156 {
1157  int posted;
1158 
1159  /* translate the event, if desired */
1160  posted = 0;
1161 #if !SDL_EVENTS_DISABLED
1163  SDL_Event event;
1164  event.type = SDL_CONTROLLERAXISMOTION;
1165  event.caxis.which = gamecontroller->joystick->instance_id;
1166  event.caxis.axis = axis;
1167  event.caxis.value = value;
1168  posted = SDL_PushEvent(&event) == 1;
1169  }
1170 #endif /* !SDL_EVENTS_DISABLED */
1171  return (posted);
1172 }
1173 
1174 
1175 /*
1176  * Event filter to transform joystick events into appropriate game controller ones
1177  */
1178 int
1180 {
1181  int posted;
1182 #if !SDL_EVENTS_DISABLED
1183  SDL_Event event;
1184 
1185  if ( button == SDL_CONTROLLER_BUTTON_INVALID )
1186  return (0);
1187 
1188  switch (state) {
1189  case SDL_PRESSED:
1190  event.type = SDL_CONTROLLERBUTTONDOWN;
1191  break;
1192  case SDL_RELEASED:
1193  event.type = SDL_CONTROLLERBUTTONUP;
1194  break;
1195  default:
1196  /* Invalid state -- bail */
1197  return (0);
1198  }
1199 #endif /* !SDL_EVENTS_DISABLED */
1200 
1201  /* translate the event, if desired */
1202  posted = 0;
1203 #if !SDL_EVENTS_DISABLED
1204  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
1205  event.cbutton.which = gamecontroller->joystick->instance_id;
1206  event.cbutton.button = button;
1207  event.cbutton.state = state;
1208  posted = SDL_PushEvent(&event) == 1;
1209  }
1210 #endif /* !SDL_EVENTS_DISABLED */
1211  return (posted);
1212 }
1213 
1214 /*
1215  * Turn off controller events
1216  */
1217 int
1219 {
1220 #if SDL_EVENTS_DISABLED
1221  return SDL_IGNORE;
1222 #else
1223  const Uint32 event_list[] = {
1226  };
1227  unsigned int i;
1228 
1229  switch (state) {
1230  case SDL_QUERY:
1231  state = SDL_IGNORE;
1232  for (i = 0; i < SDL_arraysize(event_list); ++i) {
1233  state = SDL_EventState(event_list[i], SDL_QUERY);
1234  if (state == SDL_ENABLE) {
1235  break;
1236  }
1237  }
1238  break;
1239  default:
1240  for (i = 0; i < SDL_arraysize(event_list); ++i) {
1241  SDL_EventState(event_list[i], state);
1242  }
1243  break;
1244  }
1245  return (state);
1246 #endif /* SDL_EVENTS_DISABLED */
1247 }
1248 
1249 /* vi: set ts=4 sw=4 expandtab: */
static const char * map_StringForControllerAxis[]
SDL_JoystickID which
Definition: SDL_events.h:320
char * SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping)
DECLSPEC void SDLCALL SDL_GameControllerClose(SDL_GameController *gamecontroller)
DECLSPEC void SDLCALL SDL_JoystickUpdate(void)
Definition: SDL_joystick.c:657
DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event *event)
Add an event to the event queue.
Definition: SDL_events.c:457
SDL_JoyDeviceEvent jdevice
Definition: SDL_events.h:510
void SDL_PrivateGameControllerParseButton(const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping)
DECLSPEC void SDLCALL SDL_GameControllerUpdate(void)
DECLSPEC SDL_GameControllerAxis SDLCALL SDL_GameControllerGetAxisFromString(const char *pchString)
struct _ControllerMapping_t ControllerMapping_t
SDL_ControllerDeviceEvent cdevice
Definition: SDL_events.h:513
struct _SDL_GameController SDL_GameController
#define NULL
Definition: ftobjs.h:61
DECLSPEC int SDLCALL SDL_snprintf(char *text, size_t maxlen, const char *fmt,...)
Definition: SDL_string.c:1277
SDL_JoyButtonEvent jbutton
Definition: SDL_events.h:509
SDL_bool
Definition: SDL_stdinc.h:116
DECLSPEC SDL_bool SDLCALL SDL_JoystickGetAttached(SDL_Joystick *joystick)
Definition: SDL_joystick.c:359
DECLSPEC void SDLCALL SDL_JoystickClose(SDL_Joystick *joystick)
Definition: SDL_joystick.c:398
DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerOpen(int joystick_index)
ControllerMapping_t * SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
SDL_JoystickID which
Definition: SDL_events.h:268
DECLSPEC void SDLCALL SDL_free(void *mem)
DECLSPEC SDL_JoystickGUID SDLCALL SDL_JoystickGetDeviceGUID(int device_index)
Definition: SDL_joystick.c:752
int32_t j
Definition: e_log.c:102
#define SDL_ENABLE
Definition: SDL_events.h:688
#define k_nMaxHatEntries
DECLSPEC SDL_JoystickGUID SDLCALL SDL_JoystickGetGUIDFromString(const char *pchGUID)
Definition: SDL_joystick.c:824
union SDL_GameControllerButtonBind::@64 value
EGLImageKHR EGLint * name
Definition: eglext.h:284
DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index)
DECLSPEC Uint8 SDLCALL SDL_EventState(Uint32 type, int state)
Definition: SDL_events.c:555
DECLSPEC int SDLCALL SDL_GameControllerEventState(int state)
int SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state)
DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len)
Definition: SDL_string.c:370
#define ABS(_x)
DECLSPEC Sint16 SDLCALL SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
Definition: SDL_joystick.c:270
SDL_GameControllerButton
static void SDL_GameControllerLoadHints()
DECLSPEC char *SDLCALL SDL_strchr(const char *str, int c)
Definition: SDL_string.c:575
DECLSPEC SDL_GameControllerButtonBind SDLCALL SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick *joystick, int button)
Definition: SDL_joystick.c:338
DECLSPEC SDL_bool SDLCALL SDL_IsGameController(int joystick_index)
DECLSPEC const char *SDLCALL SDL_GameControllerGetStringForButton(SDL_GameControllerButton button)
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
int SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
DECLSPEC SDL_GameControllerButton SDLCALL SDL_GameControllerGetButtonFromString(const char *pchString)
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:193
DECLSPEC const char *SDLCALL SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis)
#define SDL_GetEventState(type)
Definition: SDL_events.h:701
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:195
static SDL_GameController * SDL_gamecontrollers
static ControllerMapping_t * s_pSupportedControllers
SDL_JoyAxisEvent jaxis
Definition: SDL_events.h:506
void SDL_GameControllerQuit(void)
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
Definition: SDL_string.c:511
SDL_GameControllerBindType bindType
void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
void SDL_PrivateLoadButtonMapping(struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping)
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
DECLSPEC Sint16 SDLCALL SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
ControllerMapping_t * SDL_PrivateGetControllerMapping(int device_index)
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
DECLSPEC SDL_GameControllerButtonBind SDLCALL SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
static const char * map_StringForControllerButton[]
DECLSPEC const char *SDLCALL SDL_GetHint(const char *name)
Get a hint.
Definition: SDL_hints.c:104
DECLSPEC char *SDLCALL SDL_GameControllerMapping(SDL_GameController *gamecontroller)
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
DECLSPEC void SDLCALL SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
Definition: SDL_events.c:504
#define SDL_assert(condition)
Definition: SDL_assert.h:159
DECLSPEC size_t SDLCALL SDL_strlen(const char *str)
Definition: SDL_string.c:389
DECLSPEC void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
Definition: SDL_joystick.c:770
GLuint GLfloat x0
Definition: glew.h:11582
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:83
static const char * s_ControllerMappings[]
EGLSurface EGLint void ** value
Definition: eglext.h:301
DECLSPEC void SDLCALL SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
Definition: SDL_events.c:521
char * SDL_PrivateGetControllerNameFromMappingString(const char *pMapping)
DECLSPEC void *SDLCALL SDL_memcpy(void *dst, const void *src, size_t len)
Definition: SDL_string.c:293
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
DECLSPEC int SDLCALL SDL_atoi(const char *str)
Definition: SDL_string.c:774
DECLSPEC SDL_bool SDLCALL SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
DECLSPEC char *SDLCALL SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
Definition: gl2ext.h:961
int16_t Sint16
A signed 16-bit integer type.
Definition: SDL_stdinc.h:133
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickOpen(int device_index)
Definition: SDL_joystick.c:101
GLenum GLenum GLenum GLenum mapping
Definition: glew.h:12631
DECLSPEC int SDLCALL SDL_GameControllerAddMapping(const char *mappingString)
#define SDL_HINT_GAMECONTROLLERCONFIG
A variable that lets you manually hint extra gamecontroller db entries.
Definition: SDL_hints.h:226
General event structure.
Definition: SDL_events.h:495
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_QUERY
Definition: SDL_events.h:685
SDL_JoyHatEvent jhat
Definition: SDL_events.h:508
int i
Definition: pngrutil.c:1377
int SDL_GameControllerInit(void)
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_HAT_UP
Definition: SDL_joystick.h:192
#define k_nMaxReverseEntries
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:194
DECLSPEC SDL_Joystick *SDLCALL SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller)
SDL_JoystickID which
Definition: SDL_events.h:300
DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
SDL_GameControllerAxis
int SDL_GameControllerEventWatcher(void *userdata, SDL_Event *event)
DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str2)
Definition: SDL_string.c:946
static void SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMapping *pMapping, const char *pchString)
char * SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping)
DECLSPEC Uint8 SDLCALL SDL_JoystickGetHat(SDL_Joystick *joystick, int hat)
Definition: SDL_joystick.c:290
Uint32 type
Definition: SDL_events.h:497
#define SDL_IGNORE
Definition: SDL_events.h:686
cl_event event
Definition: glew.h:3556
DECLSPEC int SDLCALL SDL_NumJoysticks(void)
Definition: SDL_joystick.c:75
DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller)