Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / game

Joystick Driver Project

4.48/5 (14 votes)
10 Feb 2013CPOL5 min read 79.4K   4.1K  
Need to control something with a Joystick in Windows? Here is an easy to use driver that will help you do it.

Introduction

When I wanted to create a Joystick driver so I could control my robot via a joystick plugged into my computer, one of the first things I did was look for a simple joystick driver that could set up everything for me and give me the readings I wanted without me having to code anything myself or even understand how it works. Unfortunately, despite all the people using joysticks in their programs and projects before me, it seems I couldn’t find anyone had created anything like what I was looking for and shared it online.

So if no one else had done it, I decided I would do it myself. Thus, I began this project to create a portable and reusable universal joystick driver that anyone could use to easily implement joystick control in their programs. This driver uses the Joystick sample program from the DirectX SDK, as its foundation.

If you know what you’re doing, it isn’t that hard to write a simple program to get some readings from a joystick. But if you don’t know what you’re doing, learning all about direct input in order to create your own joystick driver isn’t easy. Given I didn’t and still don’t know what the hell I’m doing, I decided to adapt the sample code from the SDK rather than writing a driver from scratch. This probably ended up being more difficult for me in the long run, however the sample code from the SDK is very comprehensive and robust program that will acquire and accept any joystick device you plug in, giving me what I believe is a better result than I could have produced otherwise.

My driver is meant to handle Joystick stuff only so all the GUI related code from the sample program has been removed making it all considerably smaller and simpler.

This driver packages all your joystick needs into a Joystick class which gets all your joystick readings. You can read 8 possible axis/sliders, four possible POV/hats and 128 possible buttons.

Here is a test GUI showing readings from a twist handle Joystick.

Image 1

An altered version for the test GUI of a steering wheel set.

Image 2

Just Tell Me How to Use It Already!

Step 1

Download the files and add the Joystick_Driver.h, Joystick_Driver.cpp and resource.h to your project

Step 2

Make sure the linker can find all your required external dependencies: windows.h, commctrl.h, dinput.h, dinputd.h, assert.h, and wbemidl.h and additional dependencies. If your project is in Visual Studio, right click on your project and go to properties. In the properties window, go to...

Configuration properties->linker->input->additional dependencies->edit

Then add dxguid.lib, dinput8.lib, comctl32.lib.

At the moment, I am yet to try using this in another IDE but you should need to do for whatever IDE you may be trying to use this in.

Step 3

Now for the easy part.

Declare the following:

C++
Joystick* myJoystick; //pointer to joystick object
HWND hWnd; //window handler

Where appropriate, initialize:

C++
myJoystick = new Joystick();
hWnd = //define a handle to the window of your application with the appropriate syntax

Step 4

Create a timer driven function call to run the joystick.

Using a while loop is a bad idea. Especially, if you have a GUI, that you don’t want to have freezing up on you.

You can check that things work using a while loop but in the end, you are going to need a timer driven function call regardless.

Configure your timer to go off 20-30 times a second or at intervals of 30ms-50ms.

Step 5

In your timer driven function, you may have something as simple as:

C++
Void timerFunct()
{
  myJoystick->runJoystick(hWnd); 
//only update readings while a joystick is available
if(myJoystick->getmsg() == WM_TIMER)
  {
  XAxis = myJoystick->getXAxis();
  YAxis = myJoystick->getYAxis();
  ZRot = myJoystick->getZRot();
  Slider1 = myJoystick->getSlider0();

  POV1 = myJoystick->getPOV0();

  Button0 = myJoystick->getButton(0);
  Button1 = myJoystick->getButton(1);
  Button2 = myJoystick->getButton(2);
  Button3 = myJoystick->getButton(3);
  Button4 = myJoystick->getButton(4);
  }
}

This should give you the gist of how to use it. For a proper working example, consider the next section.

Windows Form Application Example

Design a form application while following this example and add in the following code where needed in your form.h.

C++
#include "Joystick_Driver.h"

public ref class Form1 : public System::Windows::Forms::Form
{
public:
    Form1(void)
    {
        InitializeComponent();
        this->JS = new Joystick();
        this->hWnd = static_cast<HWND>(this->Handle.ToPointer());
    }
    ~Form1()
    {
        if (components)
        {
            delete components;
        }
    }

//***********Here there be lots of************
//private: System::Windows::Forms::Stuff^  stuff;
//********************************************

private:
    Joystick* JS; //pointer to joystick object
private:
    HWND hWnd; //window handler

    #pragma region Windows Form Designer generated code

    void InitializeComponent(void)
    {
        //******** Here there be lots of ********
        //this->stuff->stuff = stuff;
        //***************************************
    }
    #pragma endregion

    //your own functions go here
};

In the design view, add a timer to your form:

Image 3

Don’t forget to set the timer properties:

Image 4

You will now have a function in your form:

C++
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
}

In the design view, double click the Run and Stop buttons and use these button click event functions to enable and disable the timer.

C++
private: System::Void Run_Click(System::Object^  sender, System::EventArgs^  e)
{
    this->timer1->Enabled = true;
}

private: System::Void Stop_Click(System::Object^  sender, System::EventArgs^  e)
{
    this->timer1->Enabled = false;
}

Add the following to the timer tick function:

C++
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e)
{
    this->JS->runJoystick(this->hWnd);
    //only update readings on GUI while a joystick is available
    if(this->JS->getmsg() == WM_TIMER)
    {
        this->XAxis->Text = (this->JS->getXAxis()).ToString();
        this->YAxis->Text = (this->JS->getYAxis()).ToString();
        this->ZAxis->Text = (this->JS->getZAxis()).ToString();
        this->XRot->Text = (this->JS->getXRot()).ToString();
        this->YRot->Text = (this->JS->getYRot()).ToString();
        this->ZRot->Text = (this->JS->getZRot()).ToString();

        this->Slider1->Text = (this->JS->getSlider0()).ToString();
        this->Slider2->Text = (this->JS->getSlider1()).ToString();

        this->POV1->Text = (this->JS->getPOV0()).ToString();
        this->POV2->Text = (this->JS->getPOV1()).ToString();
        this->POV3->Text = (this->JS->getPOV2()).ToString();
        this->POV4->Text = (this->JS->getPOV3()).ToString();

        this->Button0->Checked = this->JS->getButton(0);
        this->Button1->Checked = this->JS->getButton(1);
        this->Button2->Checked = this->JS->getButton(2);
        this->Button3->Checked = this->JS->getButton(3);
        this->Button4->Checked = this->JS->getButton(4);
        this->Button5->Checked = this->JS->getButton(5);
        this->Button6->Checked = this->JS->getButton(6);
        this->Button7->Checked = this->JS->getButton(7);
        this->Button8->Checked = this->JS->getButton(8);
        this->Button9->Checked = this->JS->getButton(9);
        this->Button10->Checked = this->JS->getButton(10);
        this->Button11->Checked = this->JS->getButton(11);
        this->Button12->Checked = this->JS->getButton(12);
        this->Button13->Checked = this->JS->getButton(13);
        this->Button14->Checked = this->JS->getButton(14);
        this->Button15->Checked = this->JS->getButton(15);
        this->Button16->Checked = this->JS->getButton(16);
        this->Button17->Checked = this->JS->getButton(17);
        this->Button18->Checked = this->JS->getButton(18);
    }
}

Running the Program

All Axis and Sliders should read within the range of -1000 to 1000. The POV will give 8 different values for all 8 directions and all buttons will simply read true or false.

Notes on Functionality

You may need to delve into the driver and add your own code to it in order to do certain things. Depending on your application, you are going to have to consider...

What happens when you disconnect the joystick?

At this time, the diver will automatically look for another joystick and will accept any joystick it finds, whether it be the same joystick once it’s plugged back in or another joystick that is already plugged in or is to be plugged in.

What happens to the readings when you disconnect the joystick?

Do you want them to freeze at the last updated value or do you want everything to go back to its default zero position?

At this time, the driver freezes the readings at the last read value if the joystick disconnects.

What happens when you have two or more joysticks plugged in?

You may want to be able to choose a joystick device, or you may want to switch between joysticks while your program is running, or you may wish to have two or more joysticks working at the same time.

At this time, the driver doesn’t support multiple joysticks, but it could be adapted to do so. What it will do is create a list of joystick devices and pick one of them automatically. So you can’t choose which joystick.

You can switch devices while the program is running but this means you need to physically unplug them and plug them in.

What if you want to accept inputs only from a specific type of joystick?

The driver has the capacity to recognize the Axis and Buttons that the connected joystick has available so to some degree, you could implement this.

History

  • 10th February, 2013: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)