Windows 的“游戏设备校准”到底起什么作用?

Windows 的“游戏设备校准”到底起什么作用?

这个向导实际上做了什么?它会创建死区并将其存储在注册表中吗?它会将原始数据映射到某个地方的上限和下限吗?

这仅仅是软件校准吗?还是它会将数据发送回设备?

我想知道是否可以识别该向导的输出,以便可以从我的应用程序中进行校准。

答案1

通过我最近对 ​​Windows 内置操纵杆控制器校准工具的探索,我可以确认 PS4 操纵杆上的以下行为(其他控制器的结果应该类似):

  • 经过校准向导后,以下注册表将写入校准数据, HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE_ID>\Calibration\0\Type\Axes\<NUM>其中<NUM>是轴编号。

  • 对于 PS4 操纵杆,Windows 读取六个轴,因此创建六个注册表项值。轴的编号如下:

    • 0 (x) --> 左模拟摇杆水平运动。
    • 1 (y)-->左模拟摇杆垂直运动。
    • 2 (z)-->右模拟水平运动。
    • 3(Rx)--> L2 触发器。
    • 4(Ry)-->R2 触发器。
    • 5(Rz)-->右模拟垂直运动。
  • 注册表项的格式Calibration映射到 12 字节二进制值(编码为<MIN> <MID> <MAX>)。例如,我的 Axis 0 (x) 的值为:<00 00 00 00> <80 00 00 00> <ff 00 00 00>,转换为

    • 最小轴 0 值 = <00 00 00 00> = 0(十进制)
    • 中轴 0 值 = <80 00 00 00> = 128(十进制)
    • 最大轴 0 值 <ff 00 00 00> = 255(十进制)
  • Windows 所做的校准是将物理值转换为校准范围(上面的最小值、中间值、最大值)。例如,假设我有缺陷的左模拟摇杆的水平移动(x 轴)读数为 10-100,而其范围应为 0-255。然后,我可以分别将最小值/最大值设置为 10 和 100,以校准有缺陷的模拟摇杆。

  • 似乎没有针对死区的特定设置,因此我认为这是为上述应用程序留下的实现细节(例如,对于游戏,定义为游戏逻辑代码的一部分)。

  • 由于校准设置存储在注册表中,因此校准在不同的机器之间不会持久。

对于您的特定情况,您可能需要考虑使用某些 Windows API 来读取值(例如 XInput、UWP API)。作为奖励,以下是使用 Windows XInput API 读取控制器输入的一些错误。

#pragma comment(lib,"XInput.lib")
#pragma comment(lib,"Xinput9_1_0.lib")

#include <iostream>
#include <roapi.h>
#include <Xinput.h>


XINPUT_STATE fetchAConnectedJoystick() 
{
    DWORD dwResult;    
    XINPUT_STATE state;

    for (DWORD i=0; i < XUSER_MAX_COUNT; i++)
    {
        ZeroMemory(&state, sizeof(XINPUT_STATE));

        // Simply get the state of the controller from XInput.
        dwResult = XInputGetState(i, &state);

        // Controller is connected
        if(dwResult == ERROR_SUCCESS)
        {
            return state;
        }
    }

    std::exit;
}


void printLeftAnalogStickReadings(XINPUT_STATE state) 
{
    float LX = state.Gamepad.sThumbLX;
    float LY = state.Gamepad.sThumbLY;
    std::cout << "(X=" << LX << ", Y=" << LY << ")\n";
}


int computeAdjustedMagnitude(XINPUT_STATE state) 
{
    int INPUT_DEADZONE = 42;

    float LX = state.Gamepad.sThumbLX;
    float LY = state.Gamepad.sThumbLY;

    float magnitude = sqrt(LX*LX + LY*LY);              // Determine how far the controller is pushed

    // Determine the direction the controller is pushed
    float normalizedLX = LX / magnitude;
    float normalizedLY = LY / magnitude;

    if (magnitude > INPUT_DEADZONE)                     // Check if the controller is outside a circular dead zone
    {
        if (magnitude > 32767) magnitude = 32767;       // Clip the magnitude at its expected maximum value
        magnitude -= INPUT_DEADZONE;                    // Adjust magnitude relative to the end of the dead zone

    }
    else                                                // If the controller is in the deadzone zero out the magnitude
    {
        magnitude = 0.0;
    }
    return magnitude;
}


int main()
{
    XINPUT_STATE state;
    int sleepDuration = 100;                            // Milliseconds
    int adjustedMag = 0;

    while (true) {
        state = fetchAConnectedJoystick();
        printLeftAnalogStickReadings(state);
//      adjustedMag = computeAdjustedMagnitude(state);
//      std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
    }
}

答案2

我相信校准信息存储在注册表中:

HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE>\Calibration

我不知道这些条目的格式是什么,但它不是人类可读的。

相关内容