Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Xbox 360 Controller Input in C++ with XInput

0.00/5 (No votes)
13 Jun 2008 1  
A small tutorial on how to use XInput (requires the DX SDK) to handle input from an Xbox 360 Controller for Windows.

Introduction

By the end of this tutorial, you should understand the basics of how to implement the Xbox 360 Controller for Windows in your C++ program, whether it be a game or some other random project that requires the use of the controller.

Class Definition (CXBOXController)

This is our class definition code for the Xbox Controller:

#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

Code Breakdown

This defines a simple C++ class that manages an Xbox 360 Controller.

_controllerState holds the state of the Xbox 360 Controller, _controllerNum holds a reference to which controller (0-3) is being stored by the class. GetState() updates the Controller's state and returns the state information to the caller so that checks can be made on the input (which will be done later when we flesh out the program). IsConnected() checks to ensure that the controller is connected, and will return ERROR_SUCCESS if successful. The Vibrate() function simply provides us with a quick and easy method for vibrating the controller.

Fleshing It Out

#include "CXBOXController.h"

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 Breakdown

This is where the CXBOXController class is fleshed out and given life.

First, the CXBOXController constructor assigns the controller number based on the player number (player 1 = 0, player 2 = 1, player 3 = 2, player 4 = 3).

Next, we flesh out the function that gets the state of the controller. First, we must zero-out the pointer to the game state, so that we can ensure no artifacts exist, by way of which the input is checked. We then make a call to XInputGetState, and pass the controller number and the address of the controller state variable to store the state of the controller into. This will ensure that _controllerState is always up-to-date. We then return the state of the controller.

After this, we implement IsConnected(), which returns true if the controller is connected and has no errors, or false if something is wrong. As in the GetState() function, we need to zero-out the memory and update the state, so that we can keep on top of the controller's state in case of a sudden disconnection. If the controller is connected and has no problems, XInputGetState() will return ERROR_SUCCESS, stating that everything is okay.

And finally, we implement a feature to allow for vibration. The Xbox 360 has two vibration motors in it; one on the left, and one on the right. We take this into account by allowing a value for the left motor and a value for the right motor. Each of these can range from 0 to 65535, indicating the strength of the motor's vibration, 65535 being the strongest. We first define an instance of the XINPUT_VIBRATION struct, which allows us to store the vibration speeds into one structure. Just as a precaution, we zero-out this memory, then set the vibration speeds, and finally set the vibration state with XInputSetState. Due to our use of 0 as the default values for leftVal and rightVal, we can call controller->Vibrate() alone to stop all vibration on the controller.

Test Application

This small bit will allow us to test the controller class:

#include "CXBOXController.h"
#include <iostream>

CXBOXController* Player1;
int main(int argc, char* argv[])
{
    Player1 = new CXBOXController(1);

    std::cout << "Instructions:\n";
    std::cout << "[A] Vibrate Left Only\n";
    std::cout << "[B] Vibrate Right Only\n";
    std::cout << "[X] Vibrate Both\n";
    std::cout << "[Y] Vibrate Neither\n";
    std::cout << "[BACK] Exit\n";

    while(true)
    {
        if(Player1->IsConnected())
        {
            if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_A)
            {
                Player1->Vibrate(65535, 0);
            }

            if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_B)
            {
                Player1->Vibrate(0, 65535);
            }

            if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_X)
            {
                Player1->Vibrate(65535, 65535);
            }

            if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_Y)
            {
                Player1->Vibrate();
            }

            if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_BACK)
            {
                break;
            }
        }
        else
        {
            std::cout << "\n\tERROR! PLAYER 1 - XBOX 360 Controller Not Found!\n";
            std::cout << "Press Any Key To Exit.";
            std::cin.get();
            break;
        }
    }

    delete(Player1);

    return( 0 );
}

I'm not going to go into details over most of the contents of this last chunk of code, because it should be quite obvious what it does.

I will, however, go over the following points of interest:

CXBOXController* Player1;
...
Player1 = new CXBOXController(1);

I chose to define it this way because I like pointers when it comes to things such as controllers. It allows me to easily pass them if I want to send them in a form other than as global variables. The 1 in the constructor indicates that it will be player 1's controller (or controller #0, according to XInput).

if(Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_A)

This is the code that checks for the gamepad state. To check for button inputs, you must use a logical AND to check if the button was pressed.

Hex Values for Controller State Buttons Checking

(Note: Obtained from the MSDN website)

XINPUT_GAMEPAD_DPAD_UP          0x00000001
XINPUT_GAMEPAD_DPAD_DOWN        0x00000002
XINPUT_GAMEPAD_DPAD_LEFT        0x00000004
XINPUT_GAMEPAD_DPAD_RIGHT       0x00000008
XINPUT_GAMEPAD_START            0x00000010
XINPUT_GAMEPAD_BACK             0x00000020
XINPUT_GAMEPAD_LEFT_THUMB       0x00000040
XINPUT_GAMEPAD_RIGHT_THUMB      0x00000080
XINPUT_GAMEPAD_LEFT_SHOULDER    0x0100
XINPUT_GAMEPAD_RIGHT_SHOULDER   0x0200
XINPUT_GAMEPAD_A                0x1000
XINPUT_GAMEPAD_B                0x2000
XINPUT_GAMEPAD_X                0x4000
XINPUT_GAMEPAD_Y                0x8000

You can also use GetState() to get the values of the Thumbstick Positions and right and left triggers through bLeftTrigger, bRightTrigger, sThumbLX, sThumbLY, sThumbRX, and sThumbRY. More information can be found on MSDN.

XINPUT_GAMEPAD Struct

(Note: Obtained from the MSDN website)

typedef struct _XINPUT_GAMEPAD {
    WORD wButtons;
    BYTE bLeftTrigger;
    BYTE bRightTrigger;
    SHORT sThumbLX;
    SHORT sThumbLY;
    SHORT sThumbRX;
    SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;

History

  • June 13, 2008: Tutorial written.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here