Introduction
When trying to find some code to use my joystick through C#, I found a sad lack of articles. There were a few posts on forums with bits and pieces of code, but no solid code on how you can use it. The scenario of a 6-axis, 20+ buttoned joystick does not seem to have occured in any C# articles before - much less on CodeProject. I intend to demonstrate how to acquire and use a full 6-axis joystick, plus all the buttons availiable.
Managed DirectX
As Managed DirectX (MDX) 2.0 is not yet released and will be included in XNA, this article uses Managed DirectX 1.1, which is fully compatible with .NET 2.0. However, you will need to change a setting within Visual Studio 2005 or a Loader Lock exception will be thrown as soon as you attempt to get a device list. The setting you need to change in VS 2005 is under the Debug menu, in Exceptions. In Managed Debugging Asssitants, uncheck "Thrown" on Loader Lock. This will allow you to debug your application. Once you have downloaded and installed the SDK, you can add a reference to Microsoft.DirectX.DirectInput
to your project. To use Managed DirectX, you will have to download the DirectX Software Developers Kit. At the time of writing, the October 2006 SDK is the latest version availiable. You can download the SDK at the DirectX SDK website. It is about 500 MB, so if you are not on a fast connection, it could take some time.
Finding Your Device
To locate a joystick, a list of all game controllers that are attached to the system needs to be obtained; the DeviceList
method does this. Once a list of devices has been found, the first controller in the list will be acquired. You could display a list of controllers to the user and allow for them to select the correct one if you wished.
The variable joystickDevice
is a Device
object declared as a private member of the class, this will be required in other methods later on.
DeviceList gameControllerList = Manager.GetDevices(DeviceClass.GameControl,
EnumDevicesFlags.AttachedOnly);
if (gameControllerList.Count > 0)
{
gameControllerList.MoveNext();
DeviceInstance deviceInstance = (DeviceInstance)
gameControllerList.Current;
joystickDevice = new Device(deviceInstance.InstanceGuid);
joystickDevice.SetCooperativeLevel(this,
CooperativeLevelFlags.Background |
CooperativeLevelFlags.NonExclusive);
}
joystickDevice.SetDataFormat(DeviceDataFormat.Joystick);
joystickDevice.Acquire();
The joystickDevice
variable should now be usable.
What is the Joystick Capable of?
This device can now be queried to find out what it is capable of. The DeviceCaps
class is able to find out how many axes, buttons and points of view hats the joystick has.
DeviceCaps cps = joystickDevice.Caps;
Debug.WriteLine("Joystick Axis: " + cps.NumberAxes);
Debug.WriteLine("Joystick Buttons: " + cps.NumberButtons);
Debug.WriteLine("Joystick PoV hats: " + cps.NumberPointOfViews);
These numbers will probably play an important role when writing an application implementing the joystick.
Getting Device Input
Each time the current state of the joystick is required, the Poll
method needs to be called to update the joystickDevice
object. Once this is done, the joystick state is updated, allowing current axis positions and button states to be found. The following private method will poll the joystick and update the state. This method updates a JoystickState
object called state
, which is a private field in the class.
private void Poll ( )
{
try
{
joystickDevice.Poll();
state = joystickDevice.CurrentJoystickState;
}
catch (Exception err)
{
Debug.WriteLine(err.Message);
}
}
The exception should probably be dealt with a little smarter, but at the moment, it doesn't matter. This method will need to be called each time we want to retrieve anything from the joystick.
Once the device has been polled for its current state, the axes positions and button state can be retrieved from the state
object. The state
object only has properties for four axes. The next section demonstrates retrieving the final two that are availiable if a six-axis joystick is in use. An axis' value is between 0 and 65535.
int axisA = state.Rz;
int axisB = state.Rx;
int axisC = state.X;
int axisD = state.Y;
The GetButtons()
method on the state
object returns a byte
array for each of the buttons. When the value is 128, the button has been pressed. A button is read as follows:
bool buttonA = buttons[0] >= 128;
You can do this for each of your joystick's buttons. Additionally, PoV hats also show up in the buttons
collection.
Finding Additional Inputs
If the joystick has additional axes that are not availiable as properties on the state
object, you can use the GetSliders
method to obtain an additional two axes. The GetSliders
method returns an array of two int
s; just like the other axis, these are values from 0 to 65535.
int[] extraAxis = state.GetSlider();
int axisE = extraAxis[0];
int axisF = extraAxis[1];
Conclusion
Hopefully, this information will be useful to you and you'll be able to use your joystick without any issues. This article only covers the basics and you may wish to implement Force Feedback or PoV hats or other technologies that are availiable.
History
- Friday, 8 December 2006 - First version