src/joystick/SDL_gamecontroller.c
author Edward Rudd <urkle@outoforder.cc>
Thu, 30 May 2013 22:14:24 -0400
changeset 7248 52d3427f8b5a
parent 7247 6a4570f12c20
child 7277 1290cd7f34af
permissions -rw-r--r--
Add trigger value adjustment code to the SDL_GameControllerGetAxis code as well.

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