XBOX 360 Controller Input with C++ using XInput.h API

The XBOX 360 has become one of the most popular game consoles in the world, for the past years. Game developers nowadays, develop games for both Playstation 3 and XBOX 360. In this short tutorial and articles, I decided to cover the XBOX 360 controller, in addition, also how to implement your own class with C++ and use the XInput.h API.

The XBOX 360 Controller Layout and Buttons

The XBOX 360 Controller layout and buttons (see the image below), the controller has 2x analog sticks, 2x analog triggers, 11x digital buttons and one digital D-Pad.

As any hardware, the XBOX 360 controller has constant hexadecimal values, these are predefined of course.

//
// Constants for gamepad buttons
//
#define XINPUT_GAMEPAD_DPAD_UP          0x0001
#define XINPUT_GAMEPAD_DPAD_DOWN        0x0002
#define XINPUT_GAMEPAD_DPAD_LEFT        0x0004
#define XINPUT_GAMEPAD_DPAD_RIGHT       0x0008
#define XINPUT_GAMEPAD_START            0x0010
#define XINPUT_GAMEPAD_BACK             0x0020
#define XINPUT_GAMEPAD_LEFT_THUMB       0x0040
#define XINPUT_GAMEPAD_RIGHT_THUMB      0x0080
#define XINPUT_GAMEPAD_LEFT_SHOULDER    0x0100
#define XINPUT_GAMEPAD_RIGHT_SHOULDER   0x0200
#define XINPUT_GAMEPAD_A                0x1000
#define XINPUT_GAMEPAD_B                0x2000
#define XINPUT_GAMEPAD_X                0x4000
#define XINPUT_GAMEPAD_Y                0x8000

The constants can be found in Xinput.h (C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include\Xinput.h), the Xinput.h is a C/C++ header file with the API code, or function declarations, variables and constant values. By including the Xinput.h in our code we can write custom functions that utilize the API to communicate with the XBOX 360 Wireless Controller. In order for you to be able to use the Xinput.h you’ll have to install Windows SDK 7.1.

Time to write the code

The very first function we will program in Win32 C++ is called: IsXBOXControlConnected(); and this function will be a boolean, this is very obvious and straight forward.

bool IsXBOXControlConnected()
{
   //Invoke the memset(); function to zero the XBOX_CONTROLLER_State. 
   memset(&XBOX_CONTROLLER_State, 0, sizeof(XINPUT_STATE)); 

   //We store the XInputGetState value inside result, note that result is a DWORD which is a typedef unsigned long. 
   DWORD result = XInputGetState(XBOX_CONTROLLER_NUM, &XBOX_CONTROLLER_State); 

   //Check if the controller is disconnected using the Ternary Operator. 
   return  result == ERROR_DEVICE_NOT_CONNECTED ? false : true;  
}

It is easy to verify whether our class and function works, we just make a pointer of the XBOXController* and invoke the constructor with the new keyword to allocate memory and set memory address for it.

#include <Windows.h>
#include "XBOXController.h"
#include <iostream>

using namespace std; 

void main()
{
	XBOXController* xctrl = new XBOXController(0); 
	if(xctrl->IsXBOXControlConnected())
	      cout << "The XBOX 360 controller is connected!" << endl; 
	else 
	      cout << "The XBOX 360 controller is disconnected!\nPlease check your XBOX 360 controller again!" << endl; 

	cin.get(); 
}

When we execute the above code in main.cpp we either see “The XBOX 360 Controller is connected!” or “The XBOX 360 controller is disconnected! Please check your controller again!”, see the command screenshot below:

Awesome, let’s move onto the Vibration(); function. According to the MSDN Documentation, the vibration accepts values between 0 and 65,535. Let’s implement the Vibration(); function which is going to be a void, because it will only perform the code inside, and not return something.

void XBOXController::Vibrate(float left, float right)
{
    XINPUT_VIBRATION vibration; 

    //Invoke memset to zero out the XINPUT_VIBRATION. 
    memset(&vibration, 0, sizeof(XINPUT_VIBRATION)); 

    /*
       According to MSDN Documentation on this, 
       speed of the left or right motor. Valid values are 
       in the range 0 to 65,535. Zero signifies no motor 
       use; 65,535 signifies 100 percent motor use.
    */

    vibration.wLeftMotorSpeed = (int)(left*65535.0f); 
    vibration.wRightMotorSpeed = (int)(right*65535.0f); 

    //Vibrate the controller 
    XInputSetState(XBOX_CONTROLLER_NUM, &vibration); 
}

Now, one final, function we should implement is the GetState(); function which allows us to check if the player pressed A or B etc on the XBOX controller. This one is simple to implement.

XINPUT_STATE XBOXController::GetState()
{
    memset(&XBOX_CONTROLLER_State, 0, sizeof(XINPUT_STATE)); 
    XInputGetState(XBOX_CONTROLLER_NUM, &XBOX_CONTROLLER_State); 
    return XBOX_CONTROLLER_State; 
}

Now we’re done with this simple example entirely written in C++ Win32, so how should we use this code in our main.cpp, easy, I have added the code below.

#include <Windows.h>
#include "XBOXController.h"
#include <iostream>

using namespace std; 

void main()
{
   XBOXController* player1 = new XBOXController(1); 

   system("color 0a"); 

    cout << "Instructions:\n";
    cout << "Press [A] to vibrate left only\n";
    cout << "Press [B] to vibrate right only\n";
    cout << "Press [BACK] to exit\n";          

    while(true){ 	
        if(player1->IsXBOXControlConnected()){
	    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_BACK)
		{ break; }
	}
	else{

		cout << "\nERROR! PLAYER 1 - XBOX 360 Controller Not Found!\n";
                cout << "Press Any Key To Exit.";
                cin.get();
                break;
	}

	delete player1; 
     }
}

Finally, let’s run this code, in my case I have no wireless USB adapter or cable to connect the XBOX 360 controller to my laptop, therefore, I receive the error because it returns false when checking for XBOX controller connection status.


 

Wrapping up

I’m done with this, for now. I think it’s fun to play around with this, since it’s so easy to use the provided API. In addition, I think this code can be further expanded, meaning that we can do more checks and add more functionality. However, most of this code is not elegant or perfect, but it should work, the main idea here is for you to understand the concept, the rest is up to you.
 
But for now, happy coding!