Human Interface Devices may accept output as well as generating input. The IDirectInputDevice2::SendDeviceData method is used to send packets of data to such devices.
SendDeviceData may be viewed as IDirectInputDevice::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 only accepts output may 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 zero.
To send data to the device, you first set up an array of DIDEVICEOBJECTDATA structures, fill the required number of elements with data, 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 may 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 zero and they will be turned off. However, you can override this behavior by using the DISDD_CONTINUE flag, in which case the data for the other two LEDs will be the value you most recently sent them.
The following function, when called repeatedly, causes the LEDs on the keyboard, as represented by the IDirectInputDevice2 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 IDirectInputDevice::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 = IDirectInputDevice2_SendDeviceData(pdev,
sizeof(DIDEVICEOBJECTDATA),
rgdod, &cdod, 0);
}