WinRT: Fixed game controller axis mappings
authorDavid Ludwig <dludwig@pobox.com>
Wed, 25 Jun 2014 22:38:40 -0400
changeset 8958ef544b7b4c4f
parent 8957 6bed922bc4dd
child 8959 9dbfb553c555
WinRT: Fixed game controller axis mappings

SDL/WinRT currently uses a separate XInput backend from SDL/Win32, as WinRT
has no support for DirectInput. This change makes SDL/WinRT's XInput
code snag some recently-changed bits from the Win32-specific,
DirectInput + XInput backend, in order to get the SDL_GameController API
working again on WinRT, insofar that axes map to the correct parts.

TODO:
- test all buttons, making sure WinRT maps buttons the same way that Win32 does
- consider making the Win32 and WinRT codebases share more stuff, minus
the sort of duplication happening via this change. Maybe simulate, or
stub-out, DirectInput calls when on WinRT?
src/joystick/winrt/SDL_xinputjoystick.c
     1.1 --- a/src/joystick/winrt/SDL_xinputjoystick.c	Wed Jun 25 22:03:05 2014 -0400
     1.2 +++ b/src/joystick/winrt/SDL_xinputjoystick.c	Wed Jun 25 22:38:40 2014 -0400
     1.3 @@ -43,6 +43,10 @@
     1.4  #include <Windows.h>
     1.5  #include <Xinput.h>
     1.6  
     1.7 +#ifndef XINPUT_GAMEPAD_GUIDE
     1.8 +#define XINPUT_GAMEPAD_GUIDE 0x0400
     1.9 +#endif
    1.10 +
    1.11  struct joystick_hwdata {
    1.12      //Uint8 bXInputHaptic; // Supports force feedback via XInput.
    1.13      DWORD userIndex;    // The XInput device index, in the range [0, XUSER_MAX_COUNT-1] (probably [0,3]).
    1.14 @@ -377,6 +381,51 @@
    1.15      return ( ButtonsNow & ButtonMask ) != ( ButtonsPrev & ButtonMask );
    1.16  }
    1.17  
    1.18 +/* This is an almost-identical copy of UpdateXInputJoystickState from the
    1.19 +   DirectInput + XInput backend.
    1.20 +
    1.21 +   TODO, WinRT: look into making the DirectInput+Xinput and WinRT/XInput joystick backends share more code, without duplication
    1.22 +   TODO, WinRT: consider adding support for the "old" XInput controller mapping (via SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING)
    1.23 +*/
    1.24 +static void
    1.25 +UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE *pXInputState)
    1.26 +{
    1.27 +    static WORD s_XInputButtons[] = {
    1.28 +        XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y,
    1.29 +        XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_START,
    1.30 +        XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB,
    1.31 +        XINPUT_GAMEPAD_GUIDE
    1.32 +    };
    1.33 +    WORD wButtons = pXInputState->Gamepad.wButtons;
    1.34 +    Uint8 button;
    1.35 +    Uint8 hat = SDL_HAT_CENTERED;
    1.36 +
    1.37 +    SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX);
    1.38 +    SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)));
    1.39 +    SDL_PrivateJoystickAxis(joystick, 2, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger * 65535 / 255) - 32768));
    1.40 +    SDL_PrivateJoystickAxis(joystick, 3, (Sint16)pXInputState->Gamepad.sThumbRX);
    1.41 +    SDL_PrivateJoystickAxis(joystick, 4, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)));
    1.42 +    SDL_PrivateJoystickAxis(joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger * 65535 / 255) - 32768));
    1.43 +
    1.44 +    for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) {
    1.45 +        SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED);
    1.46 +    }
    1.47 +
    1.48 +    if (wButtons & XINPUT_GAMEPAD_DPAD_UP) {
    1.49 +        hat |= SDL_HAT_UP;
    1.50 +    }
    1.51 +    if (wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {
    1.52 +        hat |= SDL_HAT_DOWN;
    1.53 +    }
    1.54 +    if (wButtons & XINPUT_GAMEPAD_DPAD_LEFT) {
    1.55 +        hat |= SDL_HAT_LEFT;
    1.56 +    }
    1.57 +    if (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) {
    1.58 +        hat |= SDL_HAT_RIGHT;
    1.59 +    }
    1.60 +    SDL_PrivateJoystickHat(joystick, 0, hat);
    1.61 +}
    1.62 +
    1.63  /* Function to update the state of a joystick - called as a device poll.
    1.64   * This function shouldn't update the joystick structure directly,
    1.65   * but instead should call SDL_PrivateJoystick*() to deliver events
    1.66 @@ -413,45 +462,7 @@
    1.67          && joystick->hwdata->XInputState.dwPacketNumber != prevXInputState.dwPacketNumber )
    1.68      {
    1.69          XINPUT_STATE *pXInputState = &joystick->hwdata->XInputState;
    1.70 -        XINPUT_STATE *pXInputStatePrev = &prevXInputState;
    1.71 -
    1.72 -        SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX );
    1.73 -        SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-1*pXInputState->Gamepad.sThumbLY-1) );
    1.74 -        SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX );
    1.75 -        SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-1*pXInputState->Gamepad.sThumbRY-1) );
    1.76 -        SDL_PrivateJoystickAxis(joystick, 4, (Sint16)((int)pXInputState->Gamepad.bLeftTrigger*32767/255) );
    1.77 -        SDL_PrivateJoystickAxis(joystick, 5, (Sint16)((int)pXInputState->Gamepad.bRightTrigger*32767/255) );
    1.78 -
    1.79 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP ) )
    1.80 -            SDL_PrivateJoystickButton(joystick, 0, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ? SDL_PRESSED :	SDL_RELEASED );
    1.81 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN ) )
    1.82 -            SDL_PrivateJoystickButton(joystick, 1, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ? SDL_PRESSED :	SDL_RELEASED );
    1.83 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT ) )
    1.84 -            SDL_PrivateJoystickButton(joystick, 2, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ? SDL_PRESSED :	SDL_RELEASED );
    1.85 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ) )
    1.86 -            SDL_PrivateJoystickButton(joystick, 3, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ? SDL_PRESSED :	SDL_RELEASED );
    1.87 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_START ) )
    1.88 -            SDL_PrivateJoystickButton(joystick, 4, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_START ? SDL_PRESSED :	SDL_RELEASED );
    1.89 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_BACK ) )
    1.90 -            SDL_PrivateJoystickButton(joystick, 5, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK ? SDL_PRESSED :	SDL_RELEASED );
    1.91 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB ) )
    1.92 -            SDL_PrivateJoystickButton(joystick, 6, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ? SDL_PRESSED :	SDL_RELEASED );
    1.93 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB ) )
    1.94 -            SDL_PrivateJoystickButton(joystick, 7, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ? SDL_PRESSED :	SDL_RELEASED );
    1.95 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ) )
    1.96 -            SDL_PrivateJoystickButton(joystick, 8, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? SDL_PRESSED :	SDL_RELEASED );
    1.97 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ) )
    1.98 -            SDL_PrivateJoystickButton(joystick, 9, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? SDL_PRESSED :	SDL_RELEASED );
    1.99 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_A ) )
   1.100 -            SDL_PrivateJoystickButton(joystick, 10, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_A ? SDL_PRESSED :	SDL_RELEASED );
   1.101 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_B ) )
   1.102 -            SDL_PrivateJoystickButton(joystick, 11, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_B ? SDL_PRESSED :	SDL_RELEASED );
   1.103 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_X ) )
   1.104 -            SDL_PrivateJoystickButton(joystick, 12, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_X ? SDL_PRESSED :	SDL_RELEASED );
   1.105 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_Y ) )
   1.106 -            SDL_PrivateJoystickButton(joystick, 13, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_Y ? SDL_PRESSED :	SDL_RELEASED );
   1.107 -        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons,  0x400 ) )
   1.108 -            SDL_PrivateJoystickButton(joystick, 14, pXInputState->Gamepad.wButtons & 0x400 ? SDL_PRESSED :	SDL_RELEASED ); // 0x400 is the undocumented code for the guide button
   1.109 +        UpdateXInputJoystickState(joystick, pXInputState);
   1.110      }
   1.111  
   1.112      SDL_UnlockMutex(g_DeviceInfoLock);