Windows の「ゲーム デバイスの調整」は実際に何を行うのでしょうか?

Windows の「ゲーム デバイスの調整」は実際に何を行うのでしょうか?

このウィザードは実際には何を行いますか? デッドゾーンを作成してレジストリに保存しますか? 生のデータを上限と下限のどこかにマッピングしますか?

これはソフトウェアによるキャリブレーションのみですか、それともデータをデバイスに送り返しますか?

このウィザードの出力を識別して、アプリケーション内からキャリブレーションを利用できるようにできるかどうか知りたいです。

答え1

Windows に組み込まれているジョイスティック コントローラーのキャリブレーション ツールを最近調べたところ、PS4 ジョイスティックで次の動作を確認できました (他のコントローラーでも結果は同様になるはずです)。

  • キャリブレーション ウィザードを実行すると、次のレジストリにキャリブレーション済みデータが書き込まれます。 HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE_ID>\Calibration\0\Type\Axes\<NUM>ここで、 は<NUM>軸番号です。

  • PS4 ジョイスティックの場合、Windows は 6 つの軸を読み取るため、6 つのレジストリ キー値が作成されます。軸の番号は次のとおりです。

    • 0 (x) --> 左アナログスティックの水平移動。
    • 1 (y) --> 左アナログスティックの垂直移動。
    • 2 (z) --> 右アナログ水平移動。
    • 3 (Rx) --> L2トリガー。
    • 4 (Ry) --> R2トリガー。
    • 5 (Rz) --> 右アナログ垂直移動。
  • レジストリキーのフォーマットは、Calibration12バイトのバイナリ値(エンコード<MIN> <MID> <MAX>)にマッピングされます。たとえば、軸0(x)の値は、<00 00 00 00> <80 00 00 00> <ff 00 00 00> となり、次のように変換されます。

    • 軸 0 の最小値 = <00 00 00 00> = 0 (10 進数)
    • 中央軸 0 の値 = <80 00 00 00> = 128 (10 進数)
    • 軸 0 の最大値 <ff 00 00 00> = 255 (10 進数)
  • Windows が行うキャリブレーションは、物理値をキャリブレーションされた範囲 (上から最小値、中間値、最大値) に変換することです。たとえば、故障した左アナログ スティックの水平移動 (X 軸) が 0 ~ 255 の範囲であるべきところ、10 ~ 100 と表示されるとします。この場合、故障したアナログ スティックをキャリブレーションするために、最小値と最大値をそれぞれ 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

エントリの形式がどのようなものかはわかりませんが、人間が読める形式ではありません。

関連情報