C++ is one of the most powerful programming languages that we use for all sorts of purposes, from regular applications, games, business, industrial infrastructure, robotics, and in the control of IoT devices. The most well-known controllers for those areas where human and computer interaction are important and stretches beyond simple keyboard input are joysticks or gamepads. One of the simplest examples to use them on Windows is using the venerable XInput library which has been around for quite a long time but can still be easily used with the latest C++ Compiler. In this post, we explain how you can use a gamepad or joystick controller in C++ with Xinput library.
Table of Contents
Is there a component for the gamepad or joystick in C++ On Windows?
If you are looking for a ready-to-use component library, there are Delphi and C++ Builder-compatible components built on the XInput library. For example, the Controller library is a Delphi and C++ Builder component that allows applications to receive input from an Xbox Controller. The main features of this library are,
- Uses Windows XInput API.
- Available for Delphi/C++ Builder 6 – 11 and Lazarus 2.0.12.
- Source code included in the registered version.
- Royalty free distribution.
You can download the trial version of the XInput library or you can buy a professional edition from Winsoft.sk.
How can I control a gamepad or joystick in C++ with the Xinput Library?
The XInput
library is deprecated but it still supported by Microsoft. They recommend moving towards the GameInput
library or Windows.Game.Input
for Windows applications.
If we look at these kinds of libraries (i.e GamePad.h
library), like MS’ own DirectXTK
, we can see that the toolkit allows one to define USING_XINPUT
vs. USING_GAMEINPUT
vs. USING_WINDOWS_GAMING_INPUT
to pick which underlying library is used.
If we compare XInput compared to GameInput:
- XInput library is fairly old and easy to implement Windows applications.
- XInput library is limited to 4 controllers.
- XInput library has no uniform interface to other inputs (like mouse/keyboard).
- XInput library input occurs with higher latency.
- XInput library is not friendly with other controllers. i.e. no support for Xbox One Rumble Motors.
So, briefly, DirectInput is a better long-term choice than XInput. If you still want to use XInput, you can read more about https://learn.microsoft.com/en-us/windows/win32/xinput/getting-started-with-xinput
XINPUT_GAMEPAD
structure (declared in <xinput.h>) is explained here : https://learn.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad
As in there, this structure has these members: wButtons
, bLeftTrigger
, bRightTrigger
, sThumbLX
, sThumbLY
, sThumbRX
, sThumbRY
. Here wButtons
member is used as a bitmask of the device digital buttons, it can be used as below,
wButtons Device digital button flags | Gamepad Bitmask |
---|---|
XINPUT_GAMEPAD_DPAD_UP | 0x0001 |
XINPUT_GAMEPAD_DPAD_DOWN | 0x0002 |
XINPUT_GAMEPAD_DPAD_LEFT | 0x0004 |
XINPUT_GAMEPAD_DPAD_RIGHT | 0x0008 |
XINPUT_GAMEPAD_START | 0x0010 |
XINPUT_GAMEPAD_BACK | 0x0020 |
XINPUT_GAMEPAD_LEFT_THUMB | 0x0040 |
XINPUT_GAMEPAD_RIGHT_THUMB | 0x0080 |
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 |
How to use a gamepad or joystick in C++?
If you wonder how XInput library works, you can create a simple example as in given steps below.
First, we need <XInput.h>
library header to use XInput library. This is how you can use XInput library in C++.
1 2 3 4 5 6 7 |
#include <iostream> #include <windows.h> #include <XInput.h> #pragma comment(lib, "XInput.lib") |
Now, lets create a TController
class that have n
for the controller number and state
for it. Here is an example.
1 2 3 4 5 6 7 8 9 10 11 |
class TController { private: int n; XINPUT_STATE state; public: // add controller methods here }; |
Then we need to add some methods for this class, first lets set our private controller number n
in construction like so:
1 2 3 4 5 6 |
TController(int num) { n = num; } |
now let’s get XINPUT_STATE with a method as below.
1 2 3 4 5 6 7 8 |
XINPUT_STATE GetState() { ZeroMemory(&state, sizeof(XINPUT_STATE)); XInputGetState(n, &state); return state; } |
We should check if this controller is connected in our loop, so we can create this check as shown below.
1 2 3 4 5 6 7 8 9 10 11 |
bool IsConnected() { ZeroMemory(&state, sizeof(XINPUT_STATE)); DWORD statenow = XInputGetState(n, &state); if(statenow == ERROR_SUCCESS) return true; return false; } |
Vibration in gamepads is good to measure feedback, if you have a device that has vibration you can set left and right motor speeds as below.
1 2 3 4 5 6 7 8 9 10 11 12 |
void vibrate(int LV=0, int RV=0) { XINPUT_VIBRATION vibration; ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); vibration.wLeftMotorSpeed = LV; vibration.wRightMotorSpeed = RV; XInputSetState(n, &vibration); } |
as a result, if we sum up all, the first part of our code will be we have shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#include <iostream> #include <windows.h> #include <XInput.h> #pragma comment(lib, "XInput.lib") class TController { private: int n; XINPUT_STATE state; public: TController(int num) { n = num; } XINPUT_STATE GetState() { ZeroMemory(&state, sizeof(XINPUT_STATE)); XInputGetState(n, &state); return state; } bool IsConnected() { ZeroMemory(&state, sizeof(XINPUT_STATE)); DWORD statenow = XInputGetState(n, &state); if(statenow == ERROR_SUCCESS) return true; return false; } void vibrate(int LV=0, int RV=0) { XINPUT_VIBRATION vibration; ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); vibration.wLeftMotorSpeed = LV; vibration.wRightMotorSpeed = RV; XInputSetState(n, &vibration); } }; |
I think this is the simplest and most useful controller C++ class that can be used with the XInput library. Now, let’s see how we can use this in the second part of our code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
TController* controller0; int main() { controller0 = new TController(0); if(controller0->IsConnected()) { while(controller0->IsConnected()) { } } } |
In this while
loop we can check the Gamepad button. For example, we can use XINPUT_GAMEPAD_A
for the A button of most generic gamepads. Here is an example below, that prints “A.” and vibrates the left motor of a controller as below,
1 2 3 4 5 6 7 |
if(controller0->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_A) { std::cout << "A."; controller0->vibrate(65535, 0); } |
Is there a full example of to use gamepad or joystick in C++?
The example above works well with my son’s Logitech F710 Wireless on Windows Console application in C++ Builder. This controller class works with FMX app and VCL apps too. I think, this example is compatible with XBOX series too. If you do test this on an XBOX, please let us know in the comments how you got on. Here is a full example that uses the XInput library to communicate with a game controller or joystick in C++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
#include <iostream> #include <windows.h> #include <XInput.h> #pragma comment(lib, "XInput.lib") class TController { private: int n; XINPUT_STATE state; public: TController(int num) { n = num; } XINPUT_STATE GetState() { ZeroMemory(&state, sizeof(XINPUT_STATE)); XInputGetState(n, &state); return state; } bool IsConnected() { ZeroMemory(&state, sizeof(XINPUT_STATE)); DWORD statenow = XInputGetState(n, &state); if(statenow == ERROR_SUCCESS) return true; return false; } void vibrate(int LV=0, int RV=0) { XINPUT_VIBRATION vibration; ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); vibration.wLeftMotorSpeed = LV; vibration.wRightMotorSpeed = RV; XInputSetState(n, &vibration); } }; TController* controller0; int main() { controller0 = new TController(0); if(controller0->IsConnected()) { while(controller0->IsConnected()) { if(controller0->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_A) { std::cout << "A."; controller0->vibrate(65535, 0); } if(controller0->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_B) { std::cout << "B."; controller0->vibrate(0, 65535); } if(controller0->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_X) { std::cout << "X."; controller0->vibrate(65535, 65535); } if(controller0->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_Y) { std::cout << "Y."; controller0->vibrate(); } if(controller0->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_BACK) { std::cout << "EXIT."; controller0->vibrate(); break; } } } else std::cout << "Controller not Found" << std::endl; delete(controller0); system("pause"); return 0; } |
C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs.
There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise version.