Tricks of the Windows Game Programming Gurus:Uplinking with DirectInput and Force Feedback

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

#### The Components of DirectInput

DirectInput consists of a number of COM interfaces, as do any of the DirectX subsystems. Take a look at Figure 9.4. You can see that there is the main interface, `IDirectInput`, and then only one other main interface, `IDirectInputDevice` (and the new version `IDirectInputDevice2`).

Figure 9.4 The interfaces of DirectInput.

Let’s take a look at these interfaces:

  • `IDirectInput`—This is the main COM object that you must create to start up DirectInput. Luckily there is a wrapper to do `DirectInputCreate()` that does all the COM stuff for you. Once you have created the `IDirectInput` interface, you will make calls to it to set up the properties of DirectInput and to create and acquire any input devices that you may want to work with.
  • `IDirectInputDevice`—This interface is created from the main `IDirectInput` interface and is the conduit that you use to communicate with a device, whether it be a mouse, keyboard, joystick, or whatever. They are all `IDirectInput` devices.
  • `IDirectInputDevice2`—This is the updated version of `IDirectInputDevice` and was created during DirectX 5.0. This new interface contains all the functionality of the older `IDirectInputDevice` interface, but adds support for joysticks and force feedback devices. In addition, it allows polled devices to be plugged; some joysticks need to be polled.

  Previous to DirectX 5.0 and the `IDirectInputDevice2` interface, the joystick support for DirectInput was limited to the Win32 driver; that is, there was no support! If you want to use this interface, query for it from a previously created `IDirectInputDevice` interface with `QueryInterface()`. (Can you remember that? I’ll show you again when we get there.)

#### The General Steps for Setting Up DirectInput

There are a number of steps involved in getting DirectInput up and running, connecting to one or more devices, and finally getting data from the device(s). First is the setup of DirectInput, and next is the setup of each input device. The second part is almost identical for each device, so we can generalize it. That’s cool, huh? Here’s what you have to do:

  1. Create the main DirectInput interface `IDirectInput` with a call to `DirectInputCreate()`. This returns the `IDirectInput` interface.
  2. (Optional) Query for device `GUID`s. During this step, you will query DirectInput for input devices belonging to the class keyboard, mouse, joystick, or generic device (one that doesn’t fall into the previous list). This is accomplished with (get ready to throw up) a callback function and an enumeration. Basically, you request DirectInput to enumerate all devices of some type/subtype. DirectInput filters them through a callback, which you then build up with a database of `GUID`s. Disgusting, huh? Well, luckily this is really only an issue for joystick-like devices, because you can usually bank on a generic mouse and keyboard and there are stock `GUID`s for them. I’ll show you how this step works when I cover joysticks a little later.
  3. For each device that you want to use in your application, you must create it with a call to `CreateDevice()` passing a `GUID`. `CreateDevice()` is an interface function of `IDirectInput`, so you must obtain the `IDirectInput` interface before making this call. Also, this step will come after step 2 if you don’t know the `GUID` of the device that you are trying to create. There are two built-in `GUID`s, one for the keyboard and one for the mouse:
    `GUID_SysKeyboard`—This is globally defined and will always work as the primary keyboard device `GUID`.
    `GUID_SysMouse`—This is globally defined and will always work as the primary mouse device `GUID`.

  > Tip: A while ago, an astute reader sent me an email asking about how to detect and use more than one mouse. I hadn’t really thought about it, but if the driver supports more than one mouse, you should be able to use it under DirectInput. In this case, you would have to query for the secondary mouse `GUID` to create it.

  Finally, if you want the `IDirectInputDevice2` interface, this would be the time to query for it. You would query for `IDirectInputDevice2` from the `IDirectInputDevice::` interface if you wanted the improved interface with the call `IDirectInputDevice::QueryInterface(...)`. This must be done before you set the cooperative level.

  4. Once you have created the device, you must set the cooperative level for each. This is accomplished with the call `IDirectInputDevice::SetCooperativeLevel()`. Note the C++ syntax here—it simply means that this `SetCooperativeLevel()` is an interface method or function of `IDirectInputDevice`. The cooperation levels are much like those in DirectDraw, but there are fewer of them. We will take a closer look at them when we walk through the keyboard example.
  5. Set the data format of each device with a call to `SetDataFormat()` from the `IDirectInputDevice` interface. This is a bit confusing in practice, but not that bad conceptually. The data format is how you want the data packet for each device event to be formatted. That was nice of DirectInput! This just gives you more flexibility, that’s all. Thank goodness, there are some globally predefined data formats that you can use that are reasonably intelligent, so you don’t have to set one up yourself.
  6. Set any properties of the device that you desire with `IDirectInputDevice::SetProperty()`. This is device context-sensitive, meaning that some devices have some properties and some don’t. Thus, you have to know what you’re trying to set. In this case, you’ll only use this to set some of the range properties of the joystick device, but be aware that in most cases, anything that is configurable on a device is configured with a call to `SetProperty()`. As usual, the call is fairly horrific, but I’ll show you exactly how to do it when we cover the joystick example.
  7. Acquire each device with a call to `IDirectInputDevice::Acquire()`. This basically attaches or associates the device(s) with your application and tells DirectInput that in the future you’ll be requesting data from the device.
  8. (Optional) Poll the device(s) with a call to `IDirectInputDevice2::Poll()` (note that I used the `IDirectInputDevice2` interface in this example to illustrate that polling only works with `IDirectInput2`). Some input devices need to be polled rather than you generating interrupts and keeping the input state current. Many joysticks fall into this class, so it’s always a good idea to poll joysticks whether they need it or not. Polling doesn’t hurt and costs nothing if it isn’t needed (the function just returns). However, as I mentioned, you can only poll from version 2 of the interface.
  9. Read the device data for each device with a call to `IDirectInputDevice::GetDeviceState()`. The data returned from the call will be different for each device, but the call is exactly the same. This call retrieves the data from the device and places it into a buffer so you can read it.

That’s all there is to it! Seems like a lot, but it’s really a small price to pay to access any input device without having to worry about the device driver for it!

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.