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
This structure carries information that describes a device’s data format. The first member should be set to the size of the TDIDataFormat structure. The second member is set to the size of a TDIObjectDataFormat structure. The third member is a series of flags that describe certain attributes of the data format. For our purposes, we can set this member to DIDF_ABSAXIS to indicate that axes measurements are absolute. The fourth member indicates the size of the data packet returned from the driver. This value must be a multiple of 4, and must exceed the largest offset value for an object’s data in the packet. For our purposes, we’ll set this to the size of the TDIJoyState2 structure. The fifth member indicates the number of objects that are in the sixth member, which is a pointer to an array of TDIObjectDataFormat structures. The TDIObjectDataFormat structure is defined as:
    TDIObjectDataFormat = packed record

      pguid: ^TGUID;                      // object GUID

      dwOfs: DWORD;                       // object offset

      dwType: DWORD;                      // object type

      dwFlags: DWORD;                     // attribute flags

    end;
The TDIObjectDataFormat structure contains information about a specific object on the input device, such as an individual axis or button. The first member is the object’s unique identifying GUID. The second member is the object’s offset within the data packet. This is also the object identifier that we have used in other methods. The third member indicates the object type (such as a button or axis), and the final member contains attribute flags for the object. After we initialize the first four members of the TDIDataFormat structure, we must begin building the array of TDIObjectDataFormat structures for each object on the device. To do this, we must employ the EnumObjects method. EnumObjects works the same as all other enumeration functions in that it calls a callback function once for each object on the input device. The EnumObjects method is defined as:
    function EnumObjects(

    lpCallback: TDIEnumDeviceObjectsCallbackA;     // the callback function

    pvRef: Pointer;                                // application-defined value

    dwFlags: DWORD                                 // enumeration flags

    ): HResult;                                    // returns a DirectX error code
The first parameter is a pointer to the callback function, the second parameter is a pointer to an application-defined value, and the final parameter is a series of flags that control the scope of enumeration. For our purposes, we’ll set this final parameter to DIDFT_ALL to indicate we wish to enumerate all devices. The callback function itself must be defined as:
    function TDIEnumDeviceObjectsCallbackA(

    var lpddoi: TDIDeviceObjectInstance;      // a TDIDeviceObjectInstance structure

    pvRef: Pointer                            // the application-defined data

    ): BOOL; stdcall;                         // returns TRUE or FALSE
The first parameter is an initialized TDIDeviceObjectInstance structure containing all the information we need about this specific object. The only other parameter is a pointer to the application-defined value. This callback function should return TRUE to continue enumeration or FALSE otherwise. As we are enumerating, for each object, we can save the GUID, offset, and type as reported from the TDIDeviceObjectInstance structure into our array of TDIObjectDataFormat structures. We also must keep a count of the number of objects found. When enumeration completes, we will have a correctly initialized TDIDataFormat structure, complete with an array of correctly initialized TDIObjectDataFormat structures. This entire data structure is then sent to the SetDataFormat method to finally set the correct data format for the game controller. This is illustrated in the following example. Listing 7-13: Setting the data format
    procedure SetDataFormat;

      function DIEnumDeviceObjectsProc(const peff: TDIDeviceObjectInstance;

                                       pvRef: Pointer): HRESULT; stdcall;

      begin

        {if the offset is not beyond the indicated data size... (useful if

         we were to use the TDIJoyState data structure instead) }

        if peff.dwOfs<FDataFormat.dwDataSize then

        begin

          {save the type GUID for this object}

          FDataFormatGUIDs[FDataFormat.dwNumObjs] := peff.guidType;

          {add the object information to our custom made data format}

          with FDataFormatObjects[FDataFormat.dwNumObjs] do

          begin

            pguid := @FDataFormatGUIDs[FDataFormat.dwNumObjs];

            dwOfs := peff.dwOfs;

            dwType := peff.dwType;

            dwFlags := 0;

          end;

          {if this object is an axis, store it in our axis list}

          if (peff.dwType and DIDFT_AXIS) > 0 then

          begin

            FAxisList[NumAxes] := peff.dwOfs;

            Inc(NumAxes);

          end;

          {increment the number of objects found}

          Inc(FDataFormat.dwNumObjs);

        end;

        {continue enumeration}

        Result := DIENUM_CONTINUE;

      end;

    begin

      {enumerate all objects on this input device. this will build our custom data

       structure programmatically with the correct information for each object}

      FDirectInputDevice.EnumObjects(@DIEnumDeviceObjectsProc, nil, DIDFT_ALL);

      {set the data format for the input device}

      DXCheck( FDirectInputDevice.SetDataFormat(FDataFormat) );

    end;

    procedure TfrmJoyTestBed.FormActivate(Sender: TObject);

    var

        .

        .

        .

    begin

        .

        .

        .

      {initialize our axis tracking variable}

      NumAxes := 0;

      {now we need to begin creating the data format structure and setting the

       data format, so we must initialize the overall data format structure}

      with FDataFormat do

      begin

        dwFlags := DIDF_ABSAXIS;

        dwDataSize := SizeOf(TDIJoyState2);

        dwSize := SizeOf(FDataFormat);

        dwObjSize := SizeOf(TDIObjectDataFormat);

        dwNumObjs := 0;

        rgodf := @FDataFormatObjects;

      end;

      {create and set a data format specifically made for this device}

      SetDataFormat;

        .

        .

        .

    end;
Setting Axis Properties With the data format set, we are now ready to start setting various properties for all of the axes. As discussed above, we must set the range, deadzone, and saturation for each axis. To accomplish this task, we’ll need variables of type TDIPropRange for the range and TDIPropDWord for the deadzone and saturation. As we illustrated in the mouse example, we must initialize the various size members of this structure. Unlike the mouse example, however, we will set the dwObj members of both structures to the object identifier for each individual axis. We could set this to DIPH_DEVICE, setting the properties for all axes on the device, but we may want to set different ranges, deadzones, and saturations for each device. For the TDIPropRange structure, we’ll set the lMin and lMax members to 1,000 and 1,000, respectively. For the TDIPropDWord structure, we’ll set the dwData member to 1,000 for deadzone properties (indicating 10 percent deadzone), and 9,000 for saturation properties (indicating that the last 10 percent is saturation). We can then call the SetProperty method once for each axis and each property. Once this is complete, we can finally set our cooperative level and acquire the device so we can start retrieving input. This is illustrated in the following listing.
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.