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_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <XInput.h>
#pragma comment(lib, "XInput.lib")
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)
{
_controllerNum = playerNumber - 1;
}
XINPUT_STATE CXBOXController::GetState()
{
ZeroMemory(&_controllerState, sizeof(XINPUT_STATE));
XInputGetState(_controllerNum, &_controllerState);
return _controllerState;
}
bool CXBOXController::IsConnected()
{
ZeroMemory(&_controllerState, sizeof(XINPUT_STATE));
DWORD Result = XInputGetState(_controllerNum, &_controllerState);
if(Result == ERROR_SUCCESS)
{
return true;
}
else
{
return false;
}
}
void CXBOXController::Vibrate(int leftVal, int rightVal)
{
XINPUT_VIBRATION Vibration;
ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION));
Vibration.wLeftMotorSpeed = leftVal;
Vibration.wRightMotorSpeed = rightVal;
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.