Gamepads and joysticks
So i went toying around with my old sixaxis gamepad on my pc and decided to add gamepad support to one of my apps, turns out it’s not that hard so i thought i would add a quick tutorial about it.
First of all it’s worth noting that a gamepad and a joystick is the same thing from a technical perspective. secondly the specific setup is using windows own built in joystick interface which means that we are limited to 6 analog axis and 32 buttons, which is plenty as the classic playstation dualshock controller (which almost every other controller is based on in some way) only has 4 analog axis and 17 buttons (gyros and accelerometers does not count as we can’t use them).
So first step as always is some setup, first the defines we are going to use to locate our buttons, i also included what they bind to on the dualshock, but it should be the same for most other gamepads.
[stextbox id=”grey”]#define JOY_BUTTON_1 0x00001 //triangle
#define JOY_BUTTON_2 0x00002 //circle
#define JOY_BUTTON_3 0x00004 //cross
#define JOY_BUTTON_4 0x00008 //square
#define JOY_BUTTON_5 0x00010 //l2
#define JOY_BUTTON_6 0x00020 //r2
#define JOY_BUTTON_7 0x00040 //l1
#define JOY_BUTTON_8 0x00080 //r1
#define JOY_BUTTON_9 0x00100 //select
#define JOY_BUTTON_10 0x00200 //start
#define JOY_BUTTON_11 0x00400 //l3
#define JOY_BUTTON_12 0x00800 //r3
#define JOY_BUTTON_13 0x01000 //ps home
#define JOY_BUTTON_14 0x02000 //dpad-up
#define JOY_BUTTON_15 0x04000 //dpad-right
#define JOY_BUTTON_16 0x08000 //dpad-down
#define JOY_BUTTON_17 0x10000 //dpad-left[/stextbox]
Then we add some variables
[stextbox id=”grey”]BOOL JoyPresent=false;
JOYCAPS joyCaps;[/stextbox]
step 2 is to initialize the joystick, all of this is only called once in the init function.
[stextbox id=”grey”]JOYINFOEX joyInfoEx;
joyInfoEx.dwSize = sizeof(joyInfoEx);
joyGetDevCaps(JOYSTICKID1, &joyCaps, sizeof(joyCaps));
JoyPresent = (joyGetPosEx(JOYSTICKID1, &joyInfoEx) == JOYERR_NOERROR);[/stextbox]
now joyCaps is where we list all the capabilities of the joystick, though in particular we are going to need the max values of all the axis on the analog sticks as that value can vary depending on calibration and gamepad.
Third step is to read the current state of the joystick, this is done for every frame you want to read the input.
[stextbox id=”grey”]JOYINFOEX joyInfoEx;
if (JoyPresent)
{
joyInfoEx.dwSize = sizeof(joyInfoEx);
joyInfoEx.dwFlags = JOY_RETURNALL;
joyGetPosEx(JOYSTICKID1, &joyInfoEx);
}[/stextbox]
First we check if there actually is a gamepad attached, then we set JOY_RETURNALL as a flag in joyInfoEx, this will cause the next function joyGetPosEx to return all values, it can be set to only return some values or to return raw data, but for our purposes we want it all, if you would like more then consult MSDN.
The last step is to read the data which is also sort of simple, however all the buttons are clumped together in the same integer (technically unsigned long) so to read a single one we call something like this
[stextbox id=”grey”]if (joyInfoEx.dwButtons & JOY_BUTTON_1) //then do whatever[/stextbox]
Secondly the analog sticks are also integers (again unsigned long) that range from 0 to the max of that axis, and the centered stick is usually in the middle (though if you want it’s possible to get the actual center by setting another flag in joyGetPosEx).
This data is pretty useless in this form, especially if you use floats which are centered at 0.0f and has a much more sensible range at lets say -30.0f to +30.0f, in that case i use this formula.
[stextbox id=”grey”]x=(float)(joyInfoEx.dwXpos/(joyCaps.wXmax/2.0f)-1.0f)*30;
y=(float)(joyInfoEx.dwYpos/(joyCaps.wYmax/2.0f)-1.0f)*30;[/stextbox]
Pretty straightforward IMO.
A small advice though, some gamepads are pretty sensitive and they do degrade with use which makes them unable to stay centered, and that can cause the stick to start drifting slightly even though it’s properly calibrated, so add a bit of deadzone with this formula.
[stextbox id=”grey”]float dzx=abs(x*5.0f); //this value depends on your setup
if (dzx>1.0) dzx=1.0f;
x*=dzx;[/stextbox]
That’s it for this time, have fun coding.