So you have that Xbox360 controller laying around and want to connect it to your game?
On XNA this is an out of the box option but if you’re using C++ you have a bit more work to do first.
First of all, you will need the DirecX 9.0+ sdk.
The includes.
#define WIN32_LEAN_AND_MEAN // We don't want the extra stuff like MFC and such
#include <windows>
#include <XInput.h> // XInput API
#pragma comment(lib, "XInput.lib") // Library. If your compiler doesn't support this type of lib include change to the corresponding one
Let’s define the buttons
typedef enum
{
GamePad_Button_DPAD_UP = 0,
GamePad_Button_DPAD_DOWN = 1,
GamePad_Button_DPAD_LEFT = 2,
GamePad_Button_DPAD_RIGHT = 3,
GamePad_Button_START = 4,
GamePad_Button_BACK = 5,
GamePad_Button_LEFT_THUMB = 6,
GamePad_Button_RIGHT_THUMB = 7,
GamePad_Button_LEFT_SHOULDER = 8,
GamePad_Button_RIGHT_SHOULDER = 9,
GamePad_Button_A = 10,
GamePad_Button_B = 11,
GamePad_Button_X = 12,
GamePad_Button_Y = 13,
GamePadButton_Max = 14
}GamePadButton;
After some digging I don’t think Microsoft exposes access to the Guide button, let me know if you find anything. Anyway it’s not something we need on Windows.
Now the GamePadIndexes
// GamePad Indexes
typedef enum
{
GamePadIndex_One = 0,
GamePadIndex_Two = 1,
GamePadIndex_Three =2,
GamePadIndex_Four = 3,
}GamePadIndex;
The GamePadIndex is to define the player position. Like on the Xbox360, this way we can control up to 4 controllers.
We need something to store the GamePad state
// The GamePad State Stuct, were we store the buttons positions
struct GamePadState
{
bool _buttons[GamePadButton_Max];
Vector2 _left_thumbstick; // <= I'm using a Vector2 (floats) class but you can replaced it with a float X and Y or whatever your Vector2 class is
Vector2 _right_thumbstick;
float _left_trigger;
float _right_trigger;
// Just to clear all values to default
void reset()
{
for (int i=0;i<(int)GamePadButton_Max;++i) _buttons[i] = false;
_left_thumbstick.set(0.0f);
_right_thumbstick.set(0.0f);
_left_trigger = _right_trigger = 0.0f;
}
};
Now a small class
class GamePadXbox
{
public:
GamePadXbox(GamePadIndex player)
{
_playerIndex = player;
State.reset();
}
virtual ~GamePadXbox(void)
{
// We don't want the controller to be vibrating accidentally when we exit the app
if(is_connected()) vibrate(0.0f,0.0f);
}
bool is_connected();
void vibrate(float leftmotor = 0.0f, float rightmotor = 0.0f);
void update();
public:
GamePadState State;
private:
XINPUT_STATE _controllerState;
GamePadIndex _playerIndex;
};
Now, onto the GamePadXbox::is_connected()
bool is_connected()
{
// clean the state
memset(&_controllerState,0, sizeof(XINPUT_STATE));
// Get the state
DWORD Result = XInputGetState(_controllerNum, &_controllerState);
if(Result == ERROR_SUCCESS) return true;
else return false;
}
Documentation for the XInputGetState is here.
Onto the vibrate function. Now, the Vibration accepts values between 0 and 65535. But we don’t want to be typing that every time so the vibrate accepts from a range of 0.0f (0) to 1.0f (65535);
void vibrate(float leftmotor = 0.0f, float rightmotor = 0.0f)
{
// Create a new Vibraton
XINPUT_VIBRATION Vibration;
memset(&Vibration, 0, sizeof(XINPUT_VIBRATION));
int leftVib = (int)(leftmotor*65535.0f);
int rightVib = (int)(rightmotor*65535.0f);
// Set the Vibration Values
Vibration.wLeftMotorSpeed = leftVib;
Vibration.wRightMotorSpeed = rightVib;
// Vibrate the controller
XInputSetState((int)_controllerNum, &Vibration);
}
On the destructor I’ve placed the vibrate at 0.0f otherwise the controller may be left vibrating after your game exits until the user unplugs it.
Finally, the update() function. Now this one is more out of convenience, since you could get the state straight out of XINPUT_STATE but I think this is a more consistent way of doing it. You can decide how you want on yours.
void update()
{
State.reset();
// The values of the Left and Right Triggers go from 0 to 255. We just convert them to 0.0f=>1.0f
if(_controllerState.Gamepad.bRightTrigger && _controllerState.Gamepad.bRightTrigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
{
State._right_trigger = _controllerState.Gamepad.bRightTrigger/255.0f;
}
if(_controllerState.Gamepad.bLeftTrigger && _controllerState.Gamepad.bLeftTrigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
{
State._left_trigger = _controllerState.Gamepad.bLeftTrigger/255.0f;
}
// Get the Buttons
if(_controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_A) State._buttons[GamePad_Button_A] = true;
if(_controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_B) State._buttons[GamePad_Button_B] = true;
if(_controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_X) State._buttons[GamePad_Button_X] = true;
if(_controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_Y) State._buttons[GamePad_Button_Y] = true;
if(_controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) State._buttons[GamePad_Button_DPAD_DOWN] = true;
// The Rest is missing, you can figure out the rest :)
....
(ThumbSticks code below)
}
For getting all buttons here are the official flags according to msdn
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
The ThumbSticks are a bit more tricky. They return 2 axis each but you have to make sure they are not in the deadzone. The deadzone pretty much are values !=0 but that are not relevant and can lead to errors.
// Check to make sure we are not moving during the dead zone
// Let's check the Left DeadZone
if( (_controllerState.Gamepad.sThumbLX -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) &&
(_controllerState.Gamepad.sThumbLY -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) )
{
_controllerState.Gamepad.sThumbLX = 0;
_controllerState.Gamepad.sThumbLY = 0;
}
// Check left thumbStick
float leftThumbY = _controllerState.Gamepad.sThumbLY;
if(leftThumbY)
{
State._left_thumbstick.Y = leftThumbY;
}
float leftThumbX = _controllerState.Gamepad.sThumbLX;
if(leftThumbX)
{
State._left_thumbstick.X = leftThumbX;
}
// For the rightThumbstick it's pretty much the same.
So how would we use this then?
int main()
{
GamePadXbox* pad = new GamePadXbox(GamePadIndex_One);
while(1)
{
if(pad->is_connected())
{
pad->update();
if(pad->State._buttons[GamePad_Button_BACK]==true) break;
}
}
delete pad;
}
Anyway, most of this code is not elegant or “pretty” but it should work, the idea is for you to understand the concept, the rest is up to you.