1

i want to connect joystick to my c++ qt program in windows.I studied about programming with win32 api using the joystickapi library in microsoft guid for joystick program But I didn't understand exactly What should I do after checking the system compatibility?

Completion description:

my code for system compatibility:

JOYINFO joyinfo;
UINT wNumDevs, wDeviceID;
BOOL bDev1Attached, bDev2Attached;
void joyCapablitis(){
    if((wNumDevs = joyGetNumDevs()) == 0)
        qDebug()<<"no driver available";
    bDev1Attached = joyGetPos(JOYSTICKID1,&joyinfo) != JOYERR_UNPLUGGED;
    bDev2Attached = wNumDevs == 2 && joyGetPos(JOYSTICKID2,&joyinfo) !=
            JOYERR_UNPLUGGED;
    if(bDev1Attached || bDev2Attached)   // decide which joystick to use
    {

        wDeviceID = bDev1Attached ? JOYSTICKID1 : JOYSTICKID2;

    }
    else
        qDebug()<<"no device available";

}

I want to track the movement of buttons and simulate it in software.How can I get joystick information (such as number of button and button on or off) from win32 api?

masoume
  • 33
  • 1
  • 6
  • 1
    Please be more specific. What did you try and where are you stuck? – JHBonarius Oct 12 '20 at 08:26
  • We need a litttle more information to be able to help. Can you explain to us what you need to obtain from your joystick? Does your program need to know the position of your stick? What is the purpose of your program? – Patrick Oct 12 '20 at 08:32
  • FYI: [QJoysticks library](https://github.com/alex-spataru/QJoysticks) - If not for using, it might provide at least inspiration... – Scheff's Cat Oct 12 '20 at 08:58

2 Answers2

1

According to Joysticks,

The multimedia joystick API has been superseded by DirectInput, which has more capabilities for today's input and force-feedback devices. For more information, see the DirectX documentation.

What you need is DirectInput, please start from Buffered Joystick Data.

Each element in the DIDEVICEOBJECTDATA array represents a change in state for a single object on the joystick. For instance, if the user presses button 0 and moves the stick diagonally, the array passed to IDirectInputDevice8::GetDeviceData (if it has at least three elements, and pdwInOut is at least 3) will have three elements filled in-an element for button 0 being pressed, an element for the change in the x-axis, and an element for the change in the y-axis-and the value of pdwInOut will be set to 3.

And Immediate Joystick Data,

To retrieve the current state of the joystick, call the IDirectInputDevice8::GetDeviceState method with a pointer to a DIJOYSTATE or a DIJOYSTATE2 structure, depending on whether the data format was set with c_dfDIJoystick or c_dfDIJoystick2. (See Device Data Formats.) The joystick state returned in the structure includes the coordinates of the axes, the state of the buttons, and the state of the point-of-view controllers.

Strive Sun
  • 5,988
  • 1
  • 9
  • 26
1

I wrote a QJoystick lib in a form of a Qt module but it's not yet released.

Here is a bit of code for Windows.

First, you need to initialize DirectInput:

#include "comdef.h"

#define SAFE_DELETE(p)  { if(p) { delete (p);     (p) = nullptr; }}
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p) = nullptr; }}

#define AS(x, p) reinterpret_cast<x>(p)

BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE*       deviceInstance, void* controller);
BOOL CALLBACK EnumObjectsCallback  (const DIDEVICEOBJECTINSTANCE* objectInstance, void* controller);

static LPDIRECTINPUT8 DirectInputPtr = nullptr;

HRESULT hr;

if (DirectInputPtr == nullptr)
{
    if (FAILED(hr = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, AS(void**, &DirectInputPtr), nullptr)))
        qCritical("QJoystick failed to obtain direct input interface: %s", qPrintable(hrError(hr)));
}

Second, setup callbacks:

if (DirectInputPtr)
{
    if (FAILED(hr = DirectInputPtr->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, this, DIEDFL_ATTACHEDONLY)))
        qDebug("QJoystick EnumDevices failed");

    if (joystickPtr)
    {
        if (FAILED(hr = joystickPtr->SetDataFormat(&c_dfDIJoystick2)))
            qWarning("QJoystick: failed to set data format for id %d", deviceId);

        if (SUCCEEDED(hr = joystickPtr->EnumObjects(EnumObjectsCallback, this, DIDFT_ALL)))
        {
            DIDEVICEINSTANCE joystickinfo;
            joystickinfo.dwSize = sizeof(joystickinfo);

            if (FAILED(hr = joystickPtr->GetDeviceInfo(&joystickinfo)))
            {
                qCritical() << "QJoystick GetDeviceInfo failed:" << hrError(hr);
                SAFE_RELEASE(joystickPtr)
            }

            description = QString::fromWCharArray(joystickinfo.tszProductName);
            guid        = QString("%1").arg(joystickinfo.guidProduct.Data1, 8, 16, QLatin1Char('0'));
        }
        else
            qCritical("QJoystick: set callback on EnumObjects failed for %d", deviceId);
    }
}

EnumJoysticksCallback is where you create a virtual device for your joystick:

BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* deviceInstance, void* pController)
{
    QJoystickPrivate* controller = AS(QJoystickPrivate*, pController);
    BOOL result = DIENUM_CONTINUE;

    if (controller->enumCounter == controller->deviceId)
    {
        HRESULT hr = DirectInputPtr->CreateDevice(deviceInstance->guidInstance, &(controller->joystickPtr), nullptr);

        if (SUCCEEDED(hr))
            result = DIENUM_STOP;
        else
            qWarning("QJoystick: CreateDevice failed %d", controller->deviceId);
    }
    else
        ++controller->enumCounter;

    return result;
}

And EnumObjectsCallback will be executed for every button or axis during the enumeration process:

BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* objectInstance, void* pController)
{
    QJoystickPrivate* controller = AS(QJoystickPrivate*, pController);

    //Set the range for axis
    if (objectInstance->dwType & DIDFT_AXIS)
    {
        DIPROPRANGE diprg;

        diprg.diph.dwSize       = sizeof(DIPROPRANGE);
        diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
        diprg.diph.dwHow        = DIPH_BYID;
        diprg.diph.dwObj        = objectInstance->dwType; // Specify the enumerated axis

        diprg.lMin = -1000;
        diprg.lMax = +1000;

        if (FAILED(controller->joystickPtr->SetProperty(DIPROP_RANGE, &diprg.diph)))
            return DIENUM_STOP;
    }

    if (objectInstance->guidType == GUID_XAxis  || objectInstance->guidType == GUID_YAxis  || objectInstance->guidType == GUID_ZAxis  ||
        objectInstance->guidType == GUID_RxAxis || objectInstance->guidType == GUID_RyAxis || objectInstance->guidType == GUID_RzAxis ||
        objectInstance->guidType == GUID_Slider)
    {
        // axis
    }
    else if (objectInstance->guidType == GUID_POV)
        // pov...
    else if (objectInstance->guidType == GUID_Button)
        // button...
    else if (objectInstance->guidType == GUID_Unknown)
        // unknown...

    return DIENUM_CONTINUE;
}
samdavydov
  • 564
  • 3
  • 22