Platform SDK: DirectX

Output Data

[C++]

Human Interface Devices can accept output, as well as generating input. The IDirectInputDevice7::SendDeviceData method is used to send packets of data to such devices.

SendDeviceData can be viewed as IDirectInputDevice7::GetDeviceData in reverse. Like that method, it uses the DIDEVICEOBJECTDATA structure as the basic unit of data. In this case, however, the dwOfs member contains the instance ID of the device object associated with the data, rather than its offset in the data format for the device. (Because offset identifiers exist only for device objects that provide input in the selected data format, an object that accepts only output might not even have an offset.) The dwData member contains whatever data is appropriate for the object. The dwTimeStamp and dwSequence members are not used and must be set to 0.

To send data to the device, first set up an array of DIDEVICEOBJECTDATA structures, fill the required number of elements with data, and then pass its address and the number of elements used to SendDeviceData. Data for different device objects is combined into a single packet that is then sent to the device.

The form of the data packet is specific to the device, as is the treatment of unused fields in the packet. Some devices treat fields as optional, meaning that if no data is supplied, the state of the object remains unchanged. More commonly, all fields are significant, even when you do not specifically supply data for them. For example, if you send data to a single keyboard LED, it is assumed that the data for the other two LEDs is 0, and they are turned off. However, you can override this behavior by using the DISDD_CONTINUE flag, in which case the data for the other two LEDs is the value you most recently sent them.

The following code example, when run repeatedly, causes the LEDs on the keyboard, as represented by the IDirectInputDevice7 interface pdev, to flash in a recurring pattern. The device object identifiers, NumLockID, CapsLockID, and ScrollLockID, have previously been obtained from the dwType member of the DIDEVICEOBJECTINSTANCE structure, either during enumeration of device objects or by calling IDirectInputDevice7::GetObjectInfo. It is assumed that the high bit of the data byte determines the state of the LED.

void FlashLEDs(void)
    {
    static int         rgiBits[] = { 1, 2, 4, 2 };
    static int         iLooper = 0; 
    DWORD              cdod = 3;                  // Number of items
    DIDEVICEOBJECTDATA rgdod[3];
    HRESULT            hres;
 
    // Must clear dwTimeStamp and dwSequence
    ZeroMemory(rgdod, sizeof(rgdod));
 
    rgdod[0].dwOfs = NumLockID; 
    rgdod[1].dwOfs = CapsLockID 
    rgdod[2].dwOfs = ScrollLockID;
 
    rgdod[0].dwData = (rgiBits[iLooper] & 1) ? 0x80 : 0; 
                                           // 1,0,0,0,...
    rgdod[1].dwData = (rgiBits[iLooper] & 2) ? 0x80 : 0; 
                                           // 0,1,0,1,...
    rgdod[2].dwData = (rgiBits[iLooper] & 4) ? 0x80 : 0; 
                                           // 0,0,1,0,...
 
    iLooper = (iLooper + 1) % ARRAYSIZE(rgiBits); // Loops from 0 to 3
 
    hres = IDirectInputDevice7_SendDeviceData(pdev,
            sizeof(DIDEVICEOBJECTDATA), 
            rgdod, &cdod, 0);
    }
[Visual Basic]

Human Interface Devices can accept output, as well as generating input. The DirectInputDevice.SendDeviceData method is used to send packets of data to such devices.

SendDeviceData can be viewed as DirectInputDevice.GetDeviceData in reverse. Like that method, it uses the DIDEVICEOBJECTDATA type as the basic unit of data. In this case, however, the lOfs member contains the instance ID of the device object associated with the data, rather than its offset in the data format for the device. This ID can be extracted from the value returned by DirectInputDeviceObjectInstance.GetType after device objects have been enumerated. (Because offset identifiers exist only for device objects that provide input in the selected data format, an object that accepts only output might not even have an offset.) The lData member contains whatever data is appropriate for the object. The lTimeStamp and lSequence members are not used and must be set to 0.

To send data to the device, first set up an array of DIDEVICEOBJECTDATA types, fill the required number of elements with data, and then pass its address and the number of elements used to SendDeviceData. Data for different device objects is combined into a single packet that is then sent to the device.

The form of the data packet is specific to the device, as is the treatment of unused fields in the packet. Some devices treat fields as optional, meaning that if no data is supplied, the state of the object remains unchanged. More commonly, all fields are significant, even when you do not specifically supply data for them. For example, if you send data to a single keyboard LED, it is assumed that the data for the other two LEDs is 0, and they are turned off. However, you can override this behavior by using the DISDD_CONTINUE flag, in which case the data for the other two LEDs is the value you most recently sent them.