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(십진수)
    • 중간 축 0 값 = <80 00 00 00> = 128(십진수)
    • 최대 축 0 값 <ff 00 00 00> = 255(십진수)
  • Windows에서 수행하는 보정은 물리적 값을 보정된 범위(위의 최소, 중간, 최대 값)로 변환하는 것입니다. 예를 들어 결함이 있는 왼쪽 아날로그 스틱의 범위가 0-255여야 하는데 수평 이동(x축)에 대해 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

항목의 형식이 무엇인지는 모르지만 사람이 읽을 수는 없습니다.

관련 정보