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>)。例如,我的軸 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)。作為獎勵,這裡是我的一些 bug,它使用 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

我不知道條目的格式是什麼,但它不是人類可讀的。

相關內容