Search Tips Advanced Search |
| Delphi Graphics and Game Programming Exposed with DirectX 7.0 by John Ayres Wordware Publishing, Inc. ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous | Table of Contents | Next
The TDIDeviceInstance structure passed into this callback function contains everything necessary for presenting the user with a list of choices, as well as creating an input object of the desired type. The TDIDeviceInstance structure is defined as:
    TDIDeviceInstance = packed record

      dwSize: DWORD;                                      // size of structure

      guidInstance: TGUID;                                // object instance GUID

      guidProduct: TGUID;                                 // object product GUID

      dwDevType: DWORD;                                   // device type flag

      tszInstanceName: Array [0..MAX_PATH-1] of WideChar; // instance name string

      tszProductName: Array [0..MAX_PATH-1] of WideChar;  // product name string

      guidFFDriver: TGUID;                                // force feedback driver

      wUsagePage: WORD;                                   // HID usage page code

      wUsage: WORD;                                       // HID usage page

    end;
An application could display a list of available input devices based on the instance name and product name available from the TDIDeviceInstance structure. If the instance GUID was stored along with this information, the application could create an input device using the GUID of the associated device that the user selected. The following example demonstrates creating an IDirectInput object and enumerating all attached game controllers. Listing 7-1: Creating an IDirectInput object and enumerating game controllers
    var

      Form1: TForm1;

      FDirectInput: IDirectInput;

    implementation

    function EnumInputDevs(var lpddi: TDIDeviceInstance; pvRef: Pointer): Integer;

             stdcall;

    begin

      {display the instance name and product name of the enumerated game device}

      TStringList(pvRef).Add(lpddi.tszInstanceName+’ - +lpddi.tszProductName);

      {continue enumeration}

      Result := 1;

    end;

    procedure TForm1.FormActivate(Sender: TObject);

    begin

      {create the DirectInput object}

      DirectInputCreate(hInstance, DIRECTINPUT_VERSION, FDirectInput, nil);

      {enumerate all attached game devices}

      FDirectInput.EnumDevices(DIDEVTYPE_JOYSTICK, EnumInputDevs,

                               lbxJoysticks.Items, DIEDFL_ATTACHEDONLY);

    end;
At this point, the method calls for creating and initializing input device objects are the same, but the arguments passed into these methods are different depending on the input device itself. We will cover them briefly here, but we will wait to demonstrate any examples until we get to the sections where we demonstrate reading input data from various devices. Figure 7-1: Attached game devices Creating the Input Device The DirectInput object has been created, and we’ve presented the user with a list of input devices from which one device has been selected. Given this device’s instance GUID, we can now create an IDirectInputDevice object representing the device. We create this object by calling IDirectInput’s CreateDevice method. The CreateDevice method is defined as:
    function CreateDevice(

    rguid: PGUID;                                   // the device instance GUID

    var lplpDirectInputDevice: IDirectInputDevice;  // the IDirectInputDevice object

    pUnkOuter: IUnknown                             // unused, set to nil

    ): HResult;                                     // returns a DirectX error code
The first parameter is the instance GUID for the desired input device. For game controllers, this should be a GUID retrieved from device enumeration. For the primary keyboard, you can use GUID_SysKeyboard, and for the primary mouse, you can use GUID_SysMouse. The second parameter is a pointer to the IDirectInputDevice object. When this function returns, this object will be instantiated. The final parameter is used for COM aggregation and should be set to nil. This function will only return an instantiated IDirectInputDevice object, but if we wish to use force feedback devices, we need to get an instantiated IDirectInputDevice2 object. We should probably retrieve an IDirectInputDevice2 object anyway, as some game controllers have a special requirement for retrieving data, as explained below. Thus, we should create a temporary IDirectInputDevice object, and once this is instantiated, we can use the QueryInterface method of the object to retrieve an instantiated IDirectInputDevice2 object. The temporary object can then be released by setting it to nil. Setting the Data Format Once the device has been created, you must instruct DirectInput as to the format in which input data should be reported. This step is required, as input data from a mouse, for example, would be completely different than that retrieved from the keyboard or a joystick. You may be asking, why should we do this if DirectInput knows what kind of device we just created? Again, this is part of DirectInput’s open architecture. Setting the data format in this manner allows the developer to declare a custom data format for new devices not yet created. We’ll see an example of this later when we cover game controllers. Actually, setting the data format is quite easy, and requires calling the IDirectInputDevice’s SetDataFormat method. The SetDataFormat method is defined as:
    function SetDataFormat(

    var lpdf: TDIDataFormat                  // a data format structure

    ): HResult;                              // returns a DirectX error code
The only parameter to this method is a variable of type TDIDataFormat. The TDIDataFormat structure is a complicated beast due to this open architecture. Fortunately, there are several standard, predefined data formats that we can use for communicating with just about any input device. For the keyboard, we can set this parameter to c_dfDIKeyboard; the mouse uses c_dfDIMouse. Joysticks supposedly could use either c_dfDIJoystick or c_dfDIJoystick2 (for advanced game controllers and force feedback). However, in practice, we have found that neither of these data structures seem to work correctly. Game controllers come in all shapes and sizes and can have a wide variety of buttons, axes, sliders, POV hats, etc. Therefore, creating a custom data structure on the fly based on the type of objects available on the device usually provides better results. We’ll see an example of this later in the chapter when we discuss game controllers.
| POV hat: The point-of-view (POV) hat is a device that typically rests on the top of a joystick, and can be used to indicate a viewing direction separate from movement direction.
The value passed to this function ultimately determines the data structure used when retrieving immediate data from any particular device. The parameters of the GetDeviceState method (covered below in the individual sections for each different device) are directly affected by the value passed to SetDataFormat. Each of the predefined values for SetDataFormat correspond to the following data structures that must be subsequently used in the call to GetDeviceState when retrieving immediate data.
Table 7-2: Data formats and their data structures
Format | Structure
--- | ---
c_dfDIKeyboard c_dfDIMouse c_dfDIJoystick * c_dfDIJoystick2 * | TDIKeyboardState TDIMouseState TDIJoyState TDIJoyState2
* Don’t use these; use the technique for building a custom data format later in the chapter.
Previous | Table of Contents | Next

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 whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.