3

I need to do blocking and non blocking calls to poll on an Direct Input device using IDirectInputDevice8 interface.

In linux to do blocking, we use select ex:

while( ::select(_jdev+1, &set, NULL, NULL, &tv) > 0) 
{
    if( ::read( _jdev, &js, sizeof( js_event ) ) != sizeof( js_event ) )
    {
        perror( "Joystick : read error" );
        return;
    }

    _handleEvent( js );
}

How can I do the same thing using the idirectinputdevice8 interface: https://msdn.microsoft.com/en-us/library/windows/desktop/ee417816(v=vs.85).aspx

Even if I set IDirectInputDevice8::SetEventNotification(), I still have to call poll() everytime to fetch new data and this is not workable solution since it will cause the cpu to spin.

How can I accomplish this?

*** At the moment, I can find,iterate,connect and fetch data from the Joystick Device. I just do not have blocking calls implemented.

...HERE is my experimental/test code... Please Ignore Syntax errors

#include <windows.h>
#include <dinput.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include "joystick.h"


LPDIRECTINPUT8 di;
HRESULT hr;
LPDIRECTINPUTDEVICE8 joystick;
DIDEVCAPS capabilities;

BOOL CALLBACK
enumCallback(const DIDEVICEINSTANCE* instance, VOID* context)
{
    HRESULT hr;
    hr = di->CreateDevice(instance->guidInstance, &joystick, NULL);
    if (FAILED(hr)) {
        return DIENUM_CONTINUE;
    }
    return DIENUM_STOP;
}

int JoyStickProp()
{
    if (FAILED(hr = joystick->SetDataFormat(&c_dfDIJoystick2))) {
        return hr;
    }
    if (FAILED(hr = joystick->SetCooperativeLevel(NULL, DISCL_EXCLUSIVE |
        DISCL_FOREGROUND))) {
        return hr;
    }
    capabilities.dwSize = sizeof(DIDEVCAPS);
    if (FAILED(hr = joystick->GetCapabilities(&capabilities))) {
        return hr;
    }
}

HRESULT JoyStickPoll(DIJOYSTATE2 *js)
{
    HRESULT     hr;

    if (joystick == NULL) {
        return S_OK;
    }

    // Poll the device to read the current state
    hr = joystick->Poll();
    if (FAILED(hr)) {
        hr = joystick->Acquire();
        while (hr == DIERR_INPUTLOST) {
            hr = joystick->Acquire();
        }

        if ((hr == DIERR_INVALIDPARAM) || (hr == DIERR_NOTINITIALIZED)) {
            return E_FAIL;
        }

        // If another application has control of this device, return successfully.
        // We'll just have to wait our turn to use the joystick.
        if (hr == DIERR_OTHERAPPHASPRIO) {
            return S_OK;
        }
    }

    // Get the input's device state
    if (FAILED(hr = joystick->GetDeviceState(sizeof(DIJOYSTATE2), js))) {
        return hr; // The device should have been acquired during the Poll()
    }

    return S_OK;
}

int main()
{


    // Create a DirectInput device
    if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
        IID_IDirectInput8, (VOID**)&di, NULL))) {
        return hr;
    }

    // Look for the first simple joystick we can find.
    if (FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback,
        NULL, DIEDFL_ATTACHEDONLY))) {
        return hr;
    }
    // Make sure we got a joystick
    if (joystick == NULL) {
        printf("Joystick not found.\n");
        return E_FAIL;
    }

    JoyStickProp();
    DIJOYSTATE2 diState;

    HANDLE ghWriteEvent;
    // Create joystick event stuff here
    ghWriteEvent = CreateEvent(
        NULL,               // default security attributes
        FALSE,               // manual-reset event
        FALSE,              // initial state is nonsignaled
        TEXT("WriteEvent")  // object name
        );

    //makesure we can read fromt the joystick before waiting for an event
    JoyStickPoll(&diState);
    printf("x axis %d", diState.lX);
    printf("y axis %d", diState.lY);
    JoyStickPoll(&diState);
    printf("x axis %d", diState.lX);
    printf("y axis %d", diState.lY);
    JoyStickPoll(&diState);
    printf("x axis %d", diState.lX);
    printf("y axis %d", diState.lY);
    JoyStickPoll(&diState);
    printf("x axis %d", diState.lX);
    printf("y axis %d", diState.lY);
    JoyStickPoll(&diState);
    printf("x axis %d", diState.lX);
    printf("y axis %d", diState.lY);
    JoyStickPoll(&diState);
    printf("x axis %d", diState.lX);
    printf("y axis %d", diState.lY);
joystick->SetEventNotification(ghWriteEvent);
    while (TRUE) {

        DWORD dwResult = WaitForSingleObject(
            ghWriteEvent, // event handle
            INFINITE);

        switch (dwResult) {
        case WAIT_OBJECT_0:
            // Event 1 has been set. If the event was created as
            // autoreset, it has also been reset. 
            int x = 0;
            //ProcessInputEvent1();
            break;
        }
    }
}
luke signh
  • 139
  • 2
  • 13
  • [Watch those underscores.](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) Be really annoying if there is a `_handleEvent` or `_jdev` defined in your compiler's Standard Library implementation that is getting crossed with your code. – user4581301 May 12 '17 at 22:13
  • That's Linux code as an example for what I want o accomplish in windows... it does not have anything to do with windows code or the current issue. – luke signh May 12 '17 at 22:18
  • 1
    Irrelevant. Underscores have special meaning in C++ laid out by the C++ Standard. The rules are the same regardless of whether the code is for Linux or Windows. Only the results will differ. Be careful how you use them. – user4581301 May 12 '17 at 22:28
  • 1
    You handle notification event and poll only if there is a state change. You don't need to poll and _spin CPU_ unless state changes. – Roman R. May 12 '17 at 22:36
  • @Roman Yes! but How do I do that?? Notification events do not get generated until I call directInputdevice8::poll: https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.idirectinputdevice8.idirectinputdevice8.poll(v=vs.85).aspx I added notification events to my code and can see the event does not get triggered until I call poll. – luke signh May 12 '17 at 22:45
  • No, you are to poll as a result of receiving the notification, which in turn is generated by the API. – Roman R. May 12 '17 at 22:54
  • IT WORKS NOW!!!! and THIS is an example of how to do joysticks in using Directinput ..THANKS REMY and ROMAN – luke signh May 15 '17 at 04:12

1 Answers1

2

The MSDN documentation for IDirectInputDevice8::SetEventNotification() gives you relevant code snippets.

You need to call CreateEvent() and provide the returned HANDLE as an argument to SetEventNotification(). The event will be signaled for you when a state change occurs. You can wait on the event, and then once you have the notification, you get new state data using IDirectInputDevice8::GetDeviceState().

All standard Wait Functions are applicable to waiting for the event to be signaled. The following code snippet shows you one way, using MsgWaitForMultipleObjects():

while (TRUE) { 

    dwResult = MsgWaitForMultipleObjects(2, ah, FALSE, INFINITE, QS_ALLINPUT); 
    switch (dwResult) { 
        case WAIT_OBJECT_0: 
            // Event 1 has been set. If the event was created as
            // autoreset, it has also been reset. 
            ProcessInputEvent1();
            break; 

The IDirectInputDevice8::Poll() method is used for devices that do not generate event notifications. You are supposed to poll them because they are not capable of operating the way you want them to.

Some joysticks and other game devices, or particular objects on them, do not generate hardware interrupts and do not return any data or signal any events until you call the IDirectInputDevice8::Poll method.

You poll only when you need to when notifications don't work for a device. The link above explains how to identify whether polling is necessary.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • I have done that and unless I did it incorrectly, the event does not get called until I call poll. What I want to do /and what should happen is wait for a state change event then I can call poll. – luke signh May 12 '17 at 23:08
  • I just realized I created an event and a separate thread for it to run on .. so maybe that is throwing things off.. let me try and get back to you – luke signh May 12 '17 at 23:19
  • 2
    @lukesignh: Events created with `CreateEvent()` are not tied to any particular thread. One or more threads can wait on an event while another thread signals it. So that is not your problem. Please [edit] your question to show the actual code that is not working for you. – Remy Lebeau May 13 '17 at 02:17
  • @lukesignh did you read the [Polling and Event Notification](https://msdn.microsoft.com/en-us/library/windows/desktop/ee418748) documentation that Roman linked you to? "*To find out whether it is necessary to call `IDirectInputDevice8::Poll` each time you want to retrieve data, first set the data format for the device, then call the `IDirectInputDevice8::GetCapabilities` method and check for the `DIDC_POLLEDDATAFORMAT` flag in the `DIDEVCAPS` structure.*" Your code is not checking the output of `GetCapabilities()` to know whether to use `Poll()` or `SetEventNotification()` – Remy Lebeau May 15 '17 at 19:27