¿Qué hace realmente la "Calibración del dispositivo de juego" de Windows?

¿Qué hace realmente la "Calibración del dispositivo de juego" de Windows?

¿Qué hace realmente este asistente? ¿Crea zonas muertas y las almacena en el registro? ¿Asigna datos sin procesar a límites superiores e inferiores en alguna parte?

¿Es esto exclusivamente una calibración de software o envía datos al dispositivo?

Me pregunto si se puede identificar el resultado de este asistente para que la calibración esté disponible desde mi aplicación.

Respuesta1

De mi reciente exploración de la herramienta de calibración del controlador de joystick incorporada de Windows, puedo confirmar el siguiente comportamiento en un joystick de PS4 (los resultados deberían ser similares para otros controladores):

  • Después de pasar por el asistente de calibración, se escriben los siguientes registros con los datos calibrados, HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE_ID>\Calibration\0\Type\Axes\<NUM>donde <NUM>está el número de eje.

  • Para un joystick de PS4, Windows lee seis ejes y, por lo tanto, se crean seis valores de clave de registro. La numeración de los ejes es la siguiente:

    • 0 (x) --> Movimiento horizontal del joystick analógico izquierdo.
    • 1 (y) --> Movimiento vertical del joystick analógico izquierdo.
    • 2 (z) --> Movimiento horizontal analógico derecho.
    • 3 (Rx) --> disparador L2.
    • 4 (Ry) --> disparador R2.
    • 5 (Rz) --> Movimiento vertical analógico derecho.
  • El formato de las claves de registro se Calibrationasigna a un valor binario de 12 bytes (codificado como <MIN> <MID> <MAX>). Por ejemplo, mi Eje 0 (x) tiene valor: <00 00 00 00> <80 00 00 00> <ff 00 00 00> que se traduce en

    • Valor mínimo del eje 0 = <00 00 00 00> = 0 (decimal)
    • Valor del eje medio 0 = <80 00 00 00> = 128 (decimal)
    • Valor máximo del eje 0 <ff 00 00 00> = 255 (decimal)
  • La calibración que hace Windows es convertir los valores físicos en un rango calibrado (valores mínimo, medio y máximo desde arriba). Por ejemplo, supongamos que mi palanca analógica izquierda defectuosa lee de 10 a 100 para movimiento horizontal (eje x) cuando debería estar en un rango de 0 a 255. Luego puedo configurar los valores mínimo/máximo en 10 y 100 respectivamente para calibrar el joystick analógico defectuoso.

  • No parece haber una configuración específica para las zonas muertas, por lo que supongo que se trata de un detalle de implementación dejado para la aplicación anterior (por ejemplo, para un juego, definido como parte del código lógico del juego).

  • Dado que la configuración de calibración se almacena en el registro, la calibración no es persistente en diferentes máquinas.

En cuanto a su caso particular, es posible que desee considerar el uso de alguna API de Windows para leer los valores (por ejemplo, XInput, API de UWP). Como beneficio adicional, aquí hay algunos de mis errores que leen la entrada del controlador usando la API XInput de Windows.

#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));
    }
}

Respuesta2

Creo que la información de calibración está almacenada en el registro en:

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

No sé cuál es el formato de las entradas, pero no es legible por humanos.

información relacionada