Как предотвратить сбой неподключенного джойстика в моем приложении на основе DirectInput API? - PullRequest
2 голосов
/ 03 августа 2020

Джойстики работают, как ожидалось, за исключением того, что, если они не подключены, мое приложение вылетает. Интересная вещь, я использовал его на компьютере, на котором я занимаюсь разработкой, он не трескает sh, когда он не подключен, только на других компьютерах. Так что нужно иметь в виду

Я использовал API следующим образом:

Я настраиваю глобальные переменные

LPDIRECTINPUTDEVICE8 JoystickDriver::joystick;
LPDIRECTINPUT8 JoystickDriver::di;
DIDEVCAPS JoystickDriver::capabilities;
HRESULT JoystickDriver::hr;
DIJOYSTATE2 JoystickDriver::jstate;

В функции обратного вызова, которая выполняется в фиксированный временной шаг

Основной обратный вызов:

if (*isInitialized != 1 )
{
    js->initialize();
    js->selectJoystick();
    js->setProperties();
    js->enumAxes();     
    *isInitialized = 1;     
}

if (js->PollData(&Joystick::jstate) == S_OK)
{
    slider[0] = (real_T)(1000 - Joystick::jstate.rglSlider[0]) / 20;

    pov[0] = (real_T)Joystick::jstate.lX;
    pov[1] = (real_T)Joystick::jstate.lY;
    pov[2] = (real_T)Joystick::jstate.lRz;

    Buttons[0] = (uint8_T)(Joystick::jstate.rgbButtons[0] & 0x80);
    Buttons[1] = (uint8_T)(Joystick::jstate.rgbButtons[1] & 0x80);
    Buttons[2] = (uint8_T)(Joystick::jstate.rgbButtons[2] & 0x80);
    Buttons[3] = (uint8_T)(Joystick::jstate.rgbButtons[3] & 0x80);
    Buttons[4] = (uint8_T)(Joystick::jstate.rgbButtons[4] & 0x80);

}

В определении / реализации класса

Joystick.h



class Joystick
{
public:
    Joystick();
    ~Joystick();

    HRESULT initialize();
    HRESULT selectJoystick();
    static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE* instance, VOID* context);
    HRESULT setProperties();
    HRESULT enumAxes();
    static BOOL CALLBACK enumAxesCallback(const DIDEVICEOBJECTINSTANCE* instance, VOID* context);
    HRESULT PollData(DIJOYSTATE2 *js);
    void disConnectJoystick();

    static LPDIRECTINPUTDEVICE8 joystick;
    static LPDIRECTINPUT8 di;
    static DIDEVCAPS capabilities;
    static HRESULT hr;
    static DIJOYSTATE2 jstate;
};

Джойстик. cpp

#include "Joystick.h"


Joystick::Joystick()
{
}


Joystick::~Joystick()
{
}


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


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



BOOL CALLBACK Joystick::enumCallback(const DIDEVICEINSTANCE* instance, VOID* context)
{

    // Obtain an interface to the enumerated joystick.
    Joystick::hr = (Joystick::di)->CreateDevice(instance->guidInstance, &Joystick::joystick, NULL);

    // If it failed, then we can't use this joystick. (Maybe the user unplugged
    // it while we were in the middle of enumerating it.)
    if (FAILED(Joystick::hr)) {
        return DIENUM_CONTINUE;
    }

    // Stop enumeration. Note: we're just taking the first joystick we get. You
    // could store all the enumerated joysticks and let the user pick.
    return DIENUM_STOP;
}


HRESULT Joystick::setProperties()
{
    if (FAILED(Joystick::hr = Joystick::joystick->SetDataFormat(&c_dfDIJoystick2)))
    {
        return Joystick::hr;
    }

    // Set the cooperative level to let DInput know how this device should
    // interact with the system and with other DInput applications.
    if (FAILED(Joystick::hr = Joystick::joystick->SetCooperativeLevel(NULL, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))
    {
        return Joystick::hr;
    }

    // Determine how many axis the joystick has (so we don't error out setting
    // properties for unavailable axis)
    Joystick::capabilities.dwSize = sizeof(DIDEVCAPS);
    if (FAILED(Joystick::hr = Joystick::joystick->GetCapabilities(&Joystick::capabilities)))
    {
        return Joystick::hr;
    }
    return E_FAIL;
}


HRESULT Joystick::enumAxes()
{
    if (FAILED(Joystick::hr = Joystick::joystick->EnumObjects(Joystick::enumAxesCallback, NULL, DIDFT_AXIS)))
    {
        return Joystick::hr;
    }
    else
        return Joystick::hr;
}


BOOL CALLBACK Joystick::enumAxesCallback(const DIDEVICEOBJECTINSTANCE* instance, VOID* context)
{
    HWND hDlg = (HWND)context;

    DIPROPRANGE propRange;
    propRange.diph.dwSize = sizeof(DIPROPRANGE);
    propRange.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    propRange.diph.dwHow = DIPH_BYID;
    propRange.diph.dwObj = instance->dwType;
    propRange.lMin = -1000;
    propRange.lMax = +1000;

    // Set the range for the axis
    if (FAILED(Joystick::joystick->SetProperty(DIPROP_RANGE, &propRange.diph)))
    {
        return DIENUM_STOP;
    }

    return DIENUM_CONTINUE;
}

HRESULT Joystick::PollData(DIJOYSTATE2 *js)
{

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


    // Poll the device to read the current state
    Joystick::hr = Joystick::joystick->Poll();
    if (FAILED(Joystick::hr))
    {
        // DInput is telling us that the input stream has been
        // interrupted. We aren't tracking any state between polls, so
        // we don't have any special reset that needs to be done. We
        // just re-acquire and try again.
        Joystick::hr = Joystick::joystick->Acquire();
        while (Joystick::hr == DIERR_INPUTLOST)
        {
            Joystick::hr = Joystick::joystick->Acquire();
        }

        // If we encounter a fatal error, return failure.
        if ((Joystick::hr == DIERR_INVALIDPARAM) || (Joystick::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 (Joystick::hr == DIERR_OTHERAPPHASPRIO)
        {
            return S_OK;
        }
    }

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

    return S_OK;
}


void Joystick::disConnectJoystick()
{
    if (Joystick::joystick)
    {
        Joystick::joystick->Unacquire();
    }
}
...