XInput is an API that is now
part of the DirectX and XNA SDKs and allows Windows and Xbox 360-based
applications to detect input from Xbox 360 controllers. These
controllers include any device available now or in the future that can
be used on the Xbox 360. Such devices are game pads, guitars, big-button
controllers, drums, and so forth. XInput also supports controller
vibrations (force-feedback) and voice input and output using the Xbox
360 headset.
All
Xbox 360 controllers are compatible with Windows XP and Vista and are
USB devices. These devices can be used like traditional game controllers
(such as in DirectInput), or they can be used using XInput, which is
the recommended API for these controllers.
XInput is the
replacement for DirectInput when it comes to game controllers. XInput
has several benefits over DirectInput, including the following.
XInput is easier to use.
XInput is faster to set up and detect input from.
XInput can be used on both Windows PCs and Xbox 360 consoles.
The vibration functionality of Xbox controllers can only be set using XInput.
Future Xbox controllers that are released will work with the API.
No real setup code is
necessary for getting XInput running in a gaming application. The only
requirement is that the USB controller is plugged into the machine and a
call to XInputGetState() is made. (The XInputGetState() function will be discussed in the next section.) You can, however, enable XInput’s reporting state by calling the function XInputEnable(). By default, XInput’s reporting state is set to true, which means that calls to XInputGetState() will return the state of the device. If the reporting state is set to false,
only natural data is sent. In other words, XInput will ignore the state
of the device, which can be useful, for example, when the window is
minimized but the game is still technically running. The XInputEnable() function is as follows.
void XInputEnable(BOOL enable);
You
can use DirectInput to detect input from Xbox controllers, but
DirectInput will not be able to access the vibration functionality. It
will treat the left and right triggers as a single button instead of
separately, and you cannot access audio from the Xbox 360 headset using
DirectInput.
Setting Up Xbox 360 Controllers
All of the devices
have buttons and so on. You can think of, for example, the guitar
controller as a game pad in the shape of a guitar without the left and
right analog sticks or the left and right triggers. A game pad has four
face buttons, two triggers, two bumper buttons (buttons in front of the
triggers), two analog sticks, each with a digital button (accessed by
pushing the stick inward), a guide button, a directional pad, and start
and back buttons.
The XInput function XInputGetState() is used to get the state of an Xbox controller. The function takes as parameters the index of the player and the address of an XINPUT_STATE
object that stores the state information. The player index can be
between 0 and 3 for players one through four. The return value for the XInputGetState() function can be either ERROR_SUCCESS if a controller is connected to the machine at that player index or ERROR_FAIL if no device is connected. The function prototype for the XInputGetState() function is as follows.
DWORD XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
The XINPUT_STATE
structure has fields that store the state of the controller’s various
buttons, sticks, and so on. The information in this structure is the
state of the device when the XInputGetState() function was called. The structure has the following definition, where wButtons is a flag that can store all information of the buttons, which includes face buttons, bumpers, and the start and back buttons.
typedef struct _XINPUT_GAMEPAD {
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
XInput has flags that correspond to the various input states of an Xbox controller. These flags are as follows.
XINPUT_GAMEPAD_DPAD_UP
XINPUT_GAMEPAD_DPAD_DOWN
XINPUT_GAMEPAD_DPAD_LEFT
XINPUT_GAMEPAD_DPAD_RIGHT
XINPUT_GAMEPAD_START
XINPUT_GAMEPAD_BACK
XINPUT_GAMEPAD_LEFT_THUMB
XINPUT_GAMEPAD_RIGHT_THUMB
XINPUT_GAMEPAD_LEFT_SHOULDER
XINPUT_GAMEPAD_RIGHT_SHOULDER
XINPUT_GAMEPAD_A
XINPUT_GAMEPAD_B
XINPUT_GAMEPAD_X
XINPUT_GAMEPAD_Y
Detecting Button Presses
Once you have the
controller’s state, you can test the individual buttons to see if they
are being pressed or not. The state for each button is stored in the XINPUT_STATE object’s GamePad.wButtons field. The wButtons
field is a short integer whose bits represent each button. You can use
the button flags mentioned in the previous section and the logical AND
operator (&) to test if a bit is set.
If a bit is set, this means the button is being pressed. An example of
obtaining the current input state and testing if the left and right
bumper buttons are being pressed follows.
XINPUT_STATE state;
XInputGetState(0, &state);
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
// Do Something…
If
the conditional statements equal true, the button is currently being
pressed. You can test if the back, start, and face buttons are being
pressed by using their corresponding button flags as shown in the
following.
// Back and start.
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_START)
// Do Something…
// Face buttons (a, b, x, y).
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_A)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_B)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_X)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_Y)
// Do Something…
The game pad
controllers along with a few other controller types (e.g., the guitar)
also have a directional pad on them. These directional pads are
considered buttons, where you can press the up, down, left, and right
arrow buttons independently or at the same time. An example of testing
the controller state for these button presses is shown in the following.
// Arrow pad.
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
// Do Something…
The
last remaining buttons are the left and right thumb stick’s digital
buttons. These buttons are pressed by pushing the thumb stick in. You
can test if these thumb stick digital buttons are pressed independently
of testing for thumb stick movement. An example of testing the thumb
stick digital buttons is as follows.
// Thumb buttons (pushing in left and right joysticks).
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB)
// Do Something…
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB)
// Do Something…
Detecting Triggers
Triggers are not buttons
in the traditional sense. A trigger is more of a pressure-sensitive
button, and XInput allows you to detect just how much pressure is being
applied to these triggers. Currently, there are two triggers on an Xbox
360 controller on the top of the game pad device.
To test if a trigger is being pressed, you test the XINPUT_STATE object’s Gamepad.bLeftTrigger for the left trigger and Gamepad.bRightTrigger for the right trigger. These values are represented by unsigned char
variables and if their value is over 0, the trigger is being pressed.
If these trigger values are 255, the trigger is being held all the way
down, while anything in between 0 (0%) and 255 (100%) determines the
amount of pressure being applied to the trigger. The trigger values are
obtained as follows.
unsigned char lt = state.Gamepad.bLeftTrigger;
unsigned char rt = state.Gamepad.bRightTrigger;
Detecting Thumb Stick Movements
The Xbox 360 game pad has two thumb sticks. The X and Y position information of the left thumb stick is stored in Gamepad.sThumbLX and Gamepad.sThumbLY, while the right thumb stick information is stored in Gamepad.sThumbRX and Gamepad.sThumbRY.
If
the X and Y value of a thumb stick is equal to 0, the stick is centered
along that axis. Therefore, an X and Y value of 0 for each means the
thumb stick has not moved. The minimum value the thumb stick’s axes can
have is –32768, and its maximum value is 32768. This means that if you
are looking at the X axis, a value of –32768 indicates that the thumb
stick is being moved all the way to the left, while a value of 32768
indicates that the stick is being moved all the way to the right. For
the Y axis, a value of –32768 means the stick is being moved all the way
down, while a value of 32768 means the stick is being moved all the way
up. Keep in mind that a value of 0 (or near 0 since the sticks are
highly sensitive) means the stick is not being moved at all. An example
of reading the thumb stick information is shown as follows, where the
values themselves are represented by short integers.
short lx = state.Gamepad.sThumbLX;
short ly = state.Gamepad.sThumbLY;
short rx = state.Gamepad.sThumbRX;
short ry = state.Gamepad.sThumbRY;
Not
all joysticks will read zero when centered, especially for game pads
that have been used frequently over time. One way of accounting for this
is to use what is known as a dead zone. A dead zone is just a range of
values that you will ignore and consider zero. For example, if the
joystick reads a value between –20 and 20 then you can clamp any value
between that range of dead zone values to 0. The same can be done to
account for micro joystick changes from the center where the user might
not be moving the thumb stick intentionally but movement is being
registered. |
Controller Vibrations
The Xbox controller can
have two vibration modes. Some controllers, like the guitar, do not have
vibration support, so setting this would not result in anything
happening when using some non-game pad controllers. Each game pad
controller has a left motor and a right motor. The differences between
the motors are that the left motor is for low frequency vibrations (such
as footsteps) while the right motor is stronger and used for higher
frequency vibrations (such as explosions).
Setting the controller’s vibration is easy. You first create an XINPUT_VIBRATION
object and set its left and right motor speeds from 0 to 65,535. If 0
is used, the controller does not vibrate. If 65,535 is used, the
controller vibrates at 100% of its maximum power. Anything within that
range will be a percentage between no vibration and maximum power. The XINPUT_VIBRATION structure is as follows.
typedef struct _XINPUT_VIBRATION {
WORD wLeftMotorSpeed;
WORD wRightMotorSpeed;
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
Once you’ve created an XINPUT_VIBRATION
object and specified the left and right motor speeds, you are ready to
apply it to any controller attached to the machine. To set the
vibration, you can use XInputSetState(),
and you pass to it the index of the controller to set the vibration
state and the address to the vibration state object. This sets the motor
speed for the specified controller. If you want to turn the vibration
off, you have to call this function again and set both the left and
right motors to 0. The function prototype for the XInputSetState() function is as follows.
DWORD XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
Controller Capabilities
You can obtain the capabilities of the controller (i.e., features) by calling the XInputGetCapabilities() function. This function takes the player index, input flags that can only be XINPUT_FLAG_GAMEPAD at this time, and the output address to the XINPUT_CAPABILITIES object that will store the features of the controller. The function prototype for the XInputGetCapabilities() function is as follows.
DWORD XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags,
XINPUT_CAPABILITIES* pCapabilities);
The XINPUT_CAPABILITIES structure is as follows.
typedef struct _XINPUT_CAPABILITIES {
BYTE Type;
BYTE SubType;
WORD Flags;
XINPUT_GAMEPAD Gamepad;
XINPUT_VIBRATION Vibration;
} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
The Type can only be XINPUT_DEVTYPE_GAMEPAD.
The SubType can be XINPUT_DEVSUBTYPE_ARCADE_STICK if it is an arcade stick controller, XINPUT_DEVSUBTYPE_GAMEPAD if it is a game pad controller, or XINPUT_DEVSUBTYPE_WHEEL if it is a steering wheel. Other controllers such as guitars and so on fall under the game pad type.
The Flags can only be XINPUT_CAPS_VOICE_SUPPORTED. The XINPUT_GAMEPAD stores the controller button/thumb stick and other states for the device, while the XINPUT_VIBRATION stores the current vibration state for the device.