【问题标题】:c++ programming for joystick in windowsc++ windows中操纵杆编程
【发布时间】:2021-01-26 13:11:40
【问题描述】:

我想在windows中将joystick连接到我的c++ qt程序。我在 microsoft guid for joystick program使用joystickapi库学习了win32 api编程但是我不明白检查系统兼容性后我应该做什么?

完成说明:

我的系统兼容性代码:

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";

}

我想跟踪按钮的移动并在软件中进行模拟。如何从win32 api获取操纵杆信息(例如按钮数量和按钮打开或关闭)?

【问题讨论】:

  • 请更具体。你尝试了什么,你在哪里卡住了?
  • 我们需要更多信息才能提供帮助。您能向我们解释一下您需要从操纵杆中获得什么吗?你的程序需要知道你的棍子的位置吗?您的计划的目的是什么?
  • 仅供参考:QJoysticks library - 如果不使用,它至少可以提供灵感......

标签: c++ qt winapi joystick


【解决方案1】:

我以 Qt 模块的形式编写了一个 QJoystick 库,但它尚未发布。

这里有一些适用于 Windows 的代码。

首先,你需要初始化 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)));
}

二、设置回调:

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 是您为操纵杆创建虚拟设备的地方:

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;
}

EnumObjectsCallback会在枚举过程中对每个按钮或轴执行:

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;
}

【讨论】:

    【解决方案2】:

    根据Joysticks

    多媒体操纵杆 API 已被 DirectInput 取代,后者 为当今的输入和力反馈设备提供更多功能。 有关详细信息,请参阅 DirectX 文档。

    您需要的是DirectInput,请从Buffered Joystick Data开始。

    DIDEVICEOBJECTDATA 数组中的每个元素都代表一个变化 操纵杆上单个对象的状态。例如,如果用户 按下按钮 0 并沿对角线移动摇杆,数组传递给 IDirectInputDevice8::GetDeviceData(如果它至少有三个元素, 并且 pdwInOut 至少为 3) 将填充三个元素 按下按钮 0 的元素,用于更改 x 轴,以及 y 轴变化的元素,以及 pdwInOut 将设置为 3。

    还有Immediate Joystick Data

    要检索操纵杆的当前状态,请调用 IDirectInputDevice8::GetDeviceState 方法带有一个指向 DIJOYSTATE 或 DIJOYSTATE2 结构,取决于数据是否 使用 c_dfDIJoystick 或 c_dfDIJoystick2 设置格式。 (见设备 数据格式。)结构中返回的操纵杆状态包括 轴的坐标、按钮的状态和状态 的观点控制器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多