Search code examples
c++xbox360

Why isn't the Xbox Controller Responding?


I am following the tutorial at CodeProject with input, and thought I would do some myself. So I have tried to generate the following code, but when I press the D-pad, or other buttons nothing happens. But when I press the Start and Back buttons, it registers. Thanks in advance.

CXBOXController Class

#ifndef _XBOX_CONTROLLER_H_
#define _XBOX_CONTROLLER_H_

// No MFC
#define WIN32_LEAN_AND_MEAN

// We need the Windows Header and the XInput Header
#include <windows.h>
#include <XInput.h>

// Now, the XInput Library
// NOTE: COMMENT THIS OUT IF YOU ARE NOT USING
// A COMPILER THAT SUPPORTS THIS METHOD OF LINKING LIBRARIES
#pragma comment(lib, "XInput.lib")

// XBOX Controller Class Definition
class CXBOXController
{
private:
XINPUT_STATE _controllerState;
int _controllerNum;
public:
CXBOXController(int playerNumber);
XINPUT_STATE GetState();
bool IsConnected();
void Vibrate(int leftVal = 0, int rightVal = 0);
};

#endif

CXBOXController::CXBOXController(int playerNumber)
{
// Set the Controller Number
_controllerNum = playerNumber - 1;
}

XINPUT_STATE CXBOXController::GetState()
{
// Zeroise the state
ZeroMemory(&_controllerState, sizeof(XINPUT_STATE));

// Get the state
XInputGetState(_controllerNum, &_controllerState);

return _controllerState;
}

bool CXBOXController::IsConnected()
{
// Zeroise the state
ZeroMemory(&_controllerState, sizeof(XINPUT_STATE));

// Get the state
DWORD Result = XInputGetState(_controllerNum, &_controllerState);

if(Result == ERROR_SUCCESS)
{
    return true;
}
else
{
    return false;
}
}

void CXBOXController::Vibrate(int leftVal, int rightVal)
{
// Create a Vibraton State
XINPUT_VIBRATION Vibration;

// Zeroise the Vibration
ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION));

// Set the Vibration Values
Vibration.wLeftMotorSpeed = leftVal;
Vibration.wRightMotorSpeed = rightVal;

// Vibrate the controller
XInputSetState(_controllerNum, &Vibration);
}

Code

                Player1 = new CXBOXController(1);

                if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
                {
                    std::cout << "Up";
                }

                if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
                {
                    std::cout << "Down";
                }

                if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
                                    {
                    std::cout << "Right";
                }

                if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
                {
                    std::cout << "Left";
                }

                if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_B)
                {
                    std::cout << "Right-Click";
                }

                if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_A)
                {
                    std::cout << "Click";
                }

Solution

  • I use the following code in my game engine; the trick to differentiate rising and falling keys is to measure the state of the game pad before and after:

    void Nitro::GamePadState::GetState(u32 playerIndex)
    {
        XINPUT_STATE xinputState;
    
        DWORD result = XInputGetState(playerIndex, &xinputState);
    
        if (result == ERROR_SUCCESS)
        {
            Triggers.Left = xinputState.Gamepad.bLeftTrigger;
            Triggers.Right = xinputState.Gamepad.bRightTrigger;
            ThumbSticks.Left = short2 (xinputState.Gamepad.sThumbLX, xinputState.Gamepad.sThumbLY);
            ThumbSticks.Right = short2 (xinputState.Gamepad.sThumbRX, xinputState.Gamepad.sThumbRY);
            mButtonStates.Update(xinputState.Gamepad.wButtons);
        }
    }
    
    class NitroAPI ButtonState
    {
    private:
        u32 mButtonStates;      // Current buttons' state
        u32 mPrevButtonStates;  // Previous buttons' state
        u32 mButtonDowns;       // 1 = button pressed this frame
        u32 mButtonUps;         // 1 = button released this frame
    
    public:
        ButtonState();
        void Update(u32 newState);
    
        bool IsButtonDown(Buttons button) const;
        bool IsButtonFalling(Buttons button) const;
        bool IsButtonUp(Buttons button) const;
        bool IsButtonRising(Buttons button) const;
    };
    

    The important method is Update and the IsButton*. I XOR the previous and current button state to differentiate what changed:

    void Nitro::ButtonState::Update(u32 newState)
    {
        mPrevButtonStates = mButtonStates;
        mButtonStates = newState;
    
        u32 buttonChanges = mButtonStates ^ mPrevButtonStates;
        mButtonDowns = buttonChanges & mButtonStates;
        mButtonUps = buttonChanges & (~mButtonStates);
    }
    

    Then it's a simple comparison to see what button changed:

    bool Nitro::ButtonState::IsButtonFalling(Buttons button) const
    {
        return ((mButtonStates & button) != 0) && ((mPrevButtonStates & button) == 0);
    }
    
    bool Nitro::ButtonState::IsButtonRising(Buttons button) const
    {
        return ((mButtonStates & button) == 0) && ((mPrevButtonStates & button) != 0);
    }
    
    bool Nitro::ButtonState::IsButtonDown(Buttons button) const
    {
        return ((mButtonStates & button) != 0);
    }
    
    bool Nitro::ButtonState::IsButtonUp(Buttons button) const
    {
        return ((mButtonStates & button) == 0);
    }
    

    In your case you could alleviate the problem by placing your code in a while loop, or use something similar to what I posted to keep track of the transients:

    while (true)
    {
        DWORD Result = XInputGetState(_controllerNum, &_controllerState);
        if (result == ERROR_SUCCESS)
        {
            if(_controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
            // ...
        }
    }