ue4用rawinput获取的轴数据被分段了

在windows的游戏控制器里看,数据是连贯的,但是用rawinput看,数据平均分成了两部分,静止的时候是0.5,推到中间是1,再继续往前推立刻就变成0了,然后推到头又变成0.5

请问怎么样让它是一段连贯的数据

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
这可能是由于UE4对输入设备的输入数据处理方式不同于Windows游戏控制器的原因导致的。UE4在处理输入数据时会进行一些中间处理,使得输入的轴数据呈现出了分段的状态。

要解决这个问题,可以通过在UE4中注册轴事件并手动处理RawInput数据来获得连续的轴数据。具体步骤如下:

  1. 首先,使用RawInput API注册输入设备并获取其句柄。

    RAWINPUTDEVICE rid = {};
    rid.usUsagePage = 0x01;
    rid.usUsage = 0x04; // joystick
    rid.dwFlags = RIDEV_INPUTSINK;
    rid.hwndTarget = hWnd; //窗口句柄,可以从UE4获取
    if (RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE)) == FALSE)
    {
        // 处理注册失败的情况
    }
    
  2. 在UE4的输入类中创建一个轴事件,并将其绑定到RawInput轴的通知函数中。在通知函数中将RawInput数据传递给轴事件以手动处理数据。

    // 在输入类中定义一个轴事件
    UFUNCTION(BlueprintImplementableEvent, Category = "Input")
    void OnJoystickAxis(float X, float Y);
    
    // RawInput轴通知函数
    LRESULT WINAPI RawInputAxis(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        // 使用GetRawInputData()获取输入数据
        RAWINPUT rawInput;
        UINT size = sizeof(RAWINPUT);
        if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &rawInput, &size, sizeof(RAWINPUTHEADER)) != UINT(-1))
        {
            if (rawInput.header.dwType == RIM_TYPEHID && rawInput.hid.dwSizeHid >= sizeof(HIDP_VALUE_CAPS))
            {
                HIDP_VALUE_CAPS valueCaps;
                USHORT numValues = 0;
                PHIDP_PREPARSED_DATA pData = nullptr;
                if (HidP_GetPreparsedData(rawInput.hid.bRawData, &pData) == HIDP_STATUS_SUCCESS)
                {
                    HidP_GetValueCaps(HidP_Input, &valueCaps, &numValues, pData);
    
                    if (numValues > 0)
                    {
                        HIDP_VALUE_CAPS* pValueCaps = new HIDP_VALUE_CAPS[numValues];
                        if (HidP_GetValueCaps(HidP_Input, pValueCaps, &numValues, pData) == HIDP_STATUS_SUCCESS)
                        {
                            // 解析轴数据
                            for (USHORT i = 0; i < numValues; ++i)
                            {
                                if (HidP_IsAxis(pValueCaps[i].UsagePage, pValueCaps[i].LogicalMin, pValueCaps[i].LogicalMax))
                                {
                                    LONG value = 0;
                                    if (HidP_GetUsageValue(HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].NotRange.Usage, &value, pData, rawInput.hid.bRawData, rawInput.hid.dwSizeHid) == HIDP_STATUS_SUCCESS)
                                    {
                                        float axisValue = (value - pValueCaps[i].LogicalMin) / static_cast<float>(pValueCaps[i].LogicalMax - pValueCaps[i].LogicalMin) * 2.f - 1.f;
    
                                        // 触发轴事件
                                        UGameViewportClient* viewport = GEngine->GameViewport;
                                        if (viewport)
                                        {
                                            APlayerController* controller = viewport->GetWorld()->GetFirstPlayerController();
                                            if (controller)
                                            {
                                                controller->ProcessEvent(controller->FindFunctionChecked("OnJoystickAxis"), &axisValue, 1);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        delete[] pValueCaps;
                    }
                    HidD_FreePreparsedData(pData);
                }
            }
        }
    
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    
  3. 最后,在项目中找到输入类并重写OnJoystickAxis事件以获取连续的轴数据。

    void AMyPlayer::OnJoystickAxis(float X, float Y)
    {
        // 可以直接使用手柄的X和Y轴数据
        // 处理连续的轴数据
    }
    

使用这种方式可以手动处理RawInput数据并获得连续的轴数据,从而解决分段的问题。
如果我的回答解决了您的问题,请采纳!

该回答引用chatgpt:
这可能是因为你没有正确处理RawInput的InputData。在RawInput中,轴数据是通过指定的轴值(一般为-32768到32767的整数)来表示的。UE4会将这些轴值归一化为0.0到1.0之间的浮点数,以便于在游戏中使用。因此,当你使用RawInput时,需要正确地处理归一化后的轴数据,以便获得正确的连续轴数据。

以下是一些代码示例,可以帮助你正确处理轴数据:

// 处理 WM_INPUT 消息
LRESULT CALLBACK RawInputWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_INPUT:
        {
            // 获取输入数据
            RAWINPUT rawInput;
            UINT size = sizeof(rawInput);
            GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &rawInput, &size, sizeof(RAWINPUTHEADER));
            
            // 处理轴数据
            if (rawInput.header.dwType == RIM_TYPEHID && rawInput.hid.dwType == RIM_TYPEHID && rawInput.hid.dwCount > 0)
            {
                PHIDP_PREPARSED_DATA preparsedData;
                HIDP_CAPS caps;
                HIDP_VALUE_CAPS valueCaps;
                NTSTATUS status = HidP_GetPreparsedData(rawInput.hid.bRawData, &preparsedData);
                status = HidP_GetCaps(preparsedData, &caps);
                ULONG valueCapsLength = caps.NumberInputValueCaps;
                PHIDP_VALUE_CAPS pHidValueCaps = new HIDP_VALUE_CAPS[valueCapsLength];
                status = HidP_GetValueCaps(HidP_Input, pHidValueCaps, &valueCapsLength, preparsedData);

                for (int i = 0; i < valueCapsLength; i++)
                {
                    // 处理轴数据
                    if (pHidValueCaps[i].IsRange == FALSE && pHidValueCaps[i].UsagePage == HID_USAGE_PAGE_GENERIC &&
                        pHidValueCaps[i].LinkCollection == 0 && pHidValueCaps[i].Usage == HID_USAGE_GENERIC_X)
                    {
                        LONG value = rawInput.hid.dwRawData[pHidValueCaps[i].ByteOffset];
                        float axisValue = (value - -32768.0f) / (32767.0f - -32768.0f); // 归一化轴值为0.0到1.0之间的浮点数
                        // 处理轴数据的连续性,例如使用缓存存储前一个轴数据的值,并在当前值与前一个值之间进行插值。
                        // 这里只是简单地将轴数据的值输出到控制台,用于演示如何正确处理轴数据。
                        std::cout << "Axis X: " << axisValue << std::endl;
                    }
                }
                delete[] pHidValueCaps;
                HidD_FreePreparsedData(preparsedData);
            }
            break;
        }
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}


引用chatGPT作答,这种情况可能是因为您没有正确处理RawInput传递的输入数据。您需要对数据进行解析和处理,以便正确地将其转换为轴输入值。以下是一些可能有用的步骤:

1.确保您正在读取正确的数据,这可能需要查看输入报告的格式和结构。
2.计算轴的值应该是多少,这可能涉及到将原始数据映射到轴的范围。
3.确保您处理轴输入的所有状态,包括轴值为零和轴值达到最大/最小值的情况。
4.如果您的游戏控制器支持多个轴,请确保您正确地识别和处理每个轴