PrefaceThis is just a short tutorial for using an XBOX 360 Controller in your C++ Application. I assume that you have an intermediate knowledge with C++, because I will not be breaking every step down Barney-style for you. I am writing using Microsoft Visual C++ 2008, and will assume that you are doing the same. If you are not, please add the XInput library (from the Microsoft DirectX SDK) to your project in the manner specific to your development environment, and please overlook the line "#pragma comment(lib, "XInput.lib"). This is also assuming that you are starting with an empty console project, and that it is set up to be able to use windows.h and associated headers, as well as XInput and its' associated headers.
RequirementsMicrosoft DirectX SDK (October 2005 or later)
XBOX 360 Controller for Windows (Obviously.)
DownloadWin32 Binaries:
http://files.minalien.com/XBOX360Test_Bin.rarSource (Including VC++ 2008 Solution File):
http://files.minalien.com/XBOX360Test_Src.rarStep 1 - Setting UpTo start off, we are going to create two files: CXBOXController.h and CXBOXController.cpp. We'll start by editing XBOXController.h.
Step 2 - Class Definition#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
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 (silly Microsoft) if successful. The Vibrate function simply provides us with a quick and easy method of vibrating the controller.
Step 3 - Making it Happen#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);
}
Breakdown:This is where the code is actually fleshed out and provides functionality.
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 zeroise the pointer to the game state, so that we can ensure no artifacts exist, due to how 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 zeroise 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 zeroise 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.
Step 4 - TestingNow, it's time to write a small program to test this.
#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 detail over most of the contents of this last chunk of code, because it should be quite obvious what it does.
However, I will go over the following parts:
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 gamepad state. To check for button inputs, you must use a logical AND to check if the butotn was pressed.
here are the hexadecimal values of the different buttons:
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. More information on doing that can be found here:
http://msdn.microsoft.com/en-us/library/bb174832(VS.85).aspxConclusionThat concludes my XBOX 360 Conroller tutorial. I hope you've learned from it, and perhaps can make some good use of it.