Step 6: Retrieving Data from the Joystick

Since your application is more likely concerned with the position of the joystick axes than with their movement, you will probably want to retrieve immediate rather than buffered data from the device. You can do this by polling with IDirectInputDevice::GetDeviceState. Remember, not all device drivers will notify DirectInput when the state of the device changes, so it's always good policy to call the IDirectInputDevice2::Poll method before checking the device state.

The Space Donuts application calls the following function on each pass through the rendering loop, provided the joystick is the active input device.

DWORD ReadJoystickInput(void) 
{ 
    DWORD                   dwKeyState; 
    HRESULT                 hRes; 
    DIJOYSTATE              js; 
 
    // poll the joystick to read the current state
    hRes = IDirectInputDevice2_Poll(g_pdevCurrent);
 
    // get data from the joystick 
    hRes = IDirectInputDevice_GetDeviceState(g_pdevCurrent, 
                                            sizeof(DIJOYSTATE), &js); 
 
    if (hRes != DI_OK) 
    { 
        // did the read fail because we lost input for some reason? 
        // if so, then attempt to reacquire. If the second acquire 
        // fails, then the error from GetDeviceData will be 
        // DIERR_NOTACQUIRED, so we won't get stuck an infinite loop. 
        if(hRes == DIERR_INPUTLOST) 
            ReacquireInput(); 
 
        // return the fact that we did not read any data 
        return 0; 
    } 
 
    // Now study the position of the stick and the buttons. 
 
    dwKeyState = 0; 
    if (js.lX < 0) { 
        dwKeyState |= KEY_LEFT; 
    } else if (js.lX > 0) { 
        dwKeyState |= KEY_RIGHT; 
    } 
 
    if (js.lY < 0) { 
        dwKeyState |= KEY_UP; 
    } else if (js.lY > 0) { 
          dwKeyState |= KEY_DOWN; 
   } 
 
    if (js.rgbButtons[0] & 0x80) { 
        dwKeyState |= KEY_FIRE; 
    } 
 
    if (js.rgbButtons[1] & 0x80) { 
        dwKeyState |= KEY_SHIELD; 
    } 
 
    if (js.rgbButtons[2] & 0x80) { 
        dwKeyState |= KEY_STOP; 
    } 
 
    return dwKeyState; 
} 
 

Note the calls to IDirectInputDevice2_Poll and IDirectInputDevice_GetDeviceState. These are macros that expand to C calls to the corresponding methods, similar to the macro in the previous step of this tutorial. The parameters to the macro are the same as those you would pass to the method. Here is what the call to GetDeviceState looks like:

    hRes = IDirectInputDevice_GetDeviceState(g_pdevCurrent, 
                                             sizeof(DIJOYSTATE), &js); 
 

The first parameter is the this pointer; that is, a pointer to the calling object. The second parameter is the size of the structure in which the data will be returned, and the last parameter is the address of this structure, which is of type DIJOYSTATE. This structure holds data for up to six axes, 32 buttons, and a point-of-view hat. The sample program looks at the state of two axes and three buttons.

If the position of an axis is reported as nonzero, that axis is outside the dead zone, and the function responds by setting the dwKeyState variable appropriately. This variable holds the current set of user commands as entered with either the keyboard or the joystick. For example, if the x-axis of the stick is greater than zero, that is considered the same as the RIGHT ARROW key being down.

Joystick buttons work just like keys or mouse buttons: if the high bit of the returned byte is set, the button is down.