Was macht die „Game Device Calibration“ von Windows eigentlich?

Was macht die „Game Device Calibration“ von Windows eigentlich?

Was macht dieser Assistent eigentlich? Erstellt er tote Zonen und speichert sie in der Registrierung? Ordnet er Rohdaten irgendwo Ober- und Untergrenzen zu?

Handelt es sich hierbei ausschließlich um eine Softwarekalibrierung oder werden auch Daten an das Gerät zurückgesendet?

Ich frage mich, ob die Ausgabe dieses Assistenten identifiziert werden kann, sodass die Kalibrierung innerhalb meiner Anwendung verfügbar gemacht werden kann.

Antwort1

Bei meiner jüngsten Untersuchung des in Windows integrierten Kalibrierungstools für Joystick-Controller kann ich das folgende Verhalten bei einem PS4-Joystick bestätigen (die Ergebnisse sollten bei anderen Controllern ähnlich sein):

  • Nach Durchlaufen des Kalibrierungsassistenten werden die folgenden Register mit den kalibrierten Daten geschrieben, HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE_ID>\Calibration\0\Type\Axes\<NUM>wobei <NUM>die Achsennummer ist.

  • Bei einem PS4-Joystick liest Windows sechs Achsen und daher werden sechs Registrierungsschlüsselwerte erstellt. Die Nummerierung der Achsen ist wie folgt:

    • 0 (x) --> Horizontale Bewegung des linken Analogsticks.
    • 1 (y) --> Vertikale Bewegung des linken Analogsticks.
    • 2 (z) --> Analoge Horizontalbewegung nach rechts.
    • 3 (Rx) --> L2-Trigger.
    • 4 (Ry) --> R2-Auslöser.
    • 5 (Rz) --> Rechte analoge vertikale Bewegung.
  • Das Format der Registrierungsschlüssel wird Calibrationeinem 12-Byte-Binärwert (codiert als <MIN> <MID> <MAX>) zugeordnet. Beispielsweise hat meine Achse 0 (x) den Wert: <00 00 00 00> <80 00 00 00> <ff 00 00 00>, was übersetzt bedeutet

    • Minimaler Achsenwert 0 = <00 00 00 00> = 0 (dezimal)
    • Mittlere Achse 0-Wert = <80 00 00 00> = 128 (dezimal)
    • Maximaler Achse 0-Wert <ff 00 00 00> = 255 (dezimal)
  • Die Kalibrierung, die Windows durchführt, besteht darin, die physikalischen Werte in einen kalibrierten Bereich umzuwandeln (Min.-, Mittel- und Maximalwerte von oben). Angenommen, mein defekter linker Analogstick zeigt für die horizontale Bewegung (x-Achse) einen Wert von 10-100 an, obwohl er im Bereich von 0-255 liegen sollte. Dann kann ich die Min.-/Max.-Werte auf 10 bzw. 100 setzen, um den defekten Analogstick zu kalibrieren.

  • Es scheint keine spezielle Einstellung für Totzonen zu geben, daher gehe ich davon aus, dass es sich hierbei um ein Implementierungsdetail handelt, das der obigen Anwendung überlassen bleibt (z. B. für ein Spiel, das als Teil des Spiellogikcodes definiert ist).

  • Da die Kalibrierungseinstellungen in der Registrierung gespeichert werden, bleibt die Kalibrierung auf verschiedenen Computern nicht bestehen.

In Ihrem speziellen Fall sollten Sie die Verwendung einer Windows-API zum Lesen der Werte in Betracht ziehen (z. B. XInput, UWP-API). Als Bonus finden Sie hier einige meiner Buggys, die Controller-Eingaben mithilfe der Windows XInput-API lesen.

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

Antwort2

Ich glaube, die Kalibrierungsinformationen sind in der Registrierung unter folgendem Namen gespeichert:

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

Ich kenne das Format der Einträge nicht, aber es ist nicht für Menschen lesbar.

verwandte Informationen