(gelöst) [Raw Input] Kalibrierung finden

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

(gelöst) [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Hi,

Ich verarbeite Benutzereingaben durch Raw Input. Beim Verarbeiten von HIDs stehe ich nun aber vor einem Dilemma: Die Werte, die ich bekomme, sind nicht kalibriert.

Die Geräte melden zwar immer denselben Wertumfang, aber die Werte, die tatsächlich eintreffen, liegen in einem kleineren Bereich. Bei mir persönlich kann ich feststellen, dass sich die Werte verschoben haben sobald der PC aus dem Energiesparmodus kommt; bei einem anderen Benutzer reagiert der Joystick nur zur Hälfte weil das Gerät grundsätzlich viel zu kleine Werte schickt.

Wie genau ich die Werte verarbeite, reiche ich nachher nach.

Jedenfalls: Windows bietet in den Geräteeigenschaften an, das Gerät zu kalibrieren. In dem Dialog wird auch ziemlich klar, dass die Raw Input-Daten nicht ganz der Realität entsprechen. Nur: Wie greife ich dann auf diese Kalibrierungsdaten zu? Irgendeine API muss es ja dafür geben …
Zuletzt geändert von Krishty am 10.04.2013, 00:45, insgesamt 1-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Okay; ich habe den Ort der Kalibrierungsdaten:

http://msdn.microsoft.com/en-us/library ... e/ff538389

auf den ersten Blick scheinen die zu stimmen. Nun muss ich rausfinden, wie ich von meinem RawInput-HID zu dem Key komme …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Was wir wollen:
    #include <Windows.h>
   
    namespace DInput {
   
        struct CalibrationData { // http://msdn.microsoft.com/en-us/library ... e/ff538389
            struct {
                DWORD dwFlags;
                DWORD dwNumButtons;
            }     hws;
            DWORD dwUsageSettings;
            struct {
                struct {
                    struct {
                        DWORD dwX;
                        DWORD dwY;
                        DWORD dwZ;
                        DWORD dwR;
                        DWORD dwU;
                        DWORD dwV;
                    } jpMin, jpMax, jpCenter;
                }     jrvHardware;
                DWORD dwPOVValues[4];
                DWORD dwCalFlags;
            }     hwv;
            DWORD dwType;
            DWORD dwReserved;
        };
       
    }
Wie wir es kriegen:
    bool isJoystickCalibrated(
        WORD                      vendorID,
        WORD                      productID,
        DInput::CalibrationData & result
    ) {
        bool succeeded = false;
   
        wchar_t keyPath[] = L"System\\CurrentControlSet\\Control\\MediaResources\\Joystick\\DINPUT.DLL\\JoystickSettings\\VID_????&PID_????";
        keyPath[ 89] = asHexadecimalDigit(( vendorID & 0xF000) >> 12u);
        keyPath[ 90] = asHexadecimalDigit(( vendorID & 0x0F00) >>  8u);
        keyPath[ 91] = asHexadecimalDigit(( vendorID & 0x00F0) >>  4u);
        keyPath[ 92] = asHexadecimalDigit(( vendorID & 0x000F) >>  0u);
        keyPath[ 98] = asHexadecimalDigit((productID & 0xF000) >> 12u);
        keyPath[ 99] = asHexadecimalDigit((productID & 0x0F00) >>  8u);
        keyPath[100] = asHexadecimalDigit((productID & 0x00F0) >>  4u);
        keyPath[101] = asHexadecimalDigit((productID & 0x000F) >>  0u);
   
        HKEY joystickKey = nullptr;
        if(0 == RegOpenKeyExW(
            HKEY_CURRENT_USER, keyPath, 0u,
            KEY_READ, &joystickKey
        )) {
            DWORD valueType = REG_NONE;
            DWORD valueSize = 0;
            RegQueryValueExW(
                joystickKey, L"Joystick1Configuration", nullptr,
                &valueType, nullptr, &valueSize
            );
            if(REG_BINARY == valueType && sizeof result == valueSize) {
   
                if(0 == RegQueryValueExW(
                    joystickKey, L"Joystick1Configuration", nullptr,
                    &valueType, &result, &valueSize
                )) {
                    succeeded = true;
                }
   
            }
            RegCloseKey(joystickKey);
        }
   
        return succeeded;
    }


(Das DINPUT.DLL im Pfad stimmt mich misstrauisch: offenbar ist das der Treibername, und er könnte sich auf einigen System unterscheiden. Ich habe aber keinen Weg gefunden, da ranzukommen.)
Wie wir es kriegen wenn wir nur ein Geräte-Handle von Windows haben (dafür braucht man das Windows Driver Kit):
    #include <Hidsdi.h>

    bool isJoystickCalibrated(
        HANDLE                    itsDeviceHandle,
        DInput::CalibrationData & result
    ) {
        HIDD_ATTRIBUTES attributes;
        if(0 != HidD_GetAttributes(itsDeviceHandle, &attributes)) {
            return isJoystickCalibrated(attributes.VenderID, attributes.ProductID, result);
        } else {
            return false;
        }
    }


(Da jeder NT-HID-Pfad ebenfalls Hersteller-ID und Produkt-ID in Textform beinhaltet, könnte man auch damit arbeiten. Weil es bei einigen meiner XP-Anwender aber Probleme mit Pfaden gab, die nicht dem Standard-Layout zu folgen scheinen, verlasse ich mich lieber auf HidD_GetAttributes().)
Ich bin mir ziemlich sicher, dass das das Standardverfahren von DirectInput ist. Getestet habe ich es aber bisher nur auf meinem eigenen System.

Ich habe diese Lösung auch bisher noch nirgendwo anders gefunden. Wer Nerv hat, kann sie ja mal den Leuten von Unity mitteilen.

Wie die Funktionsnamen suggerieren, arbeitet das auch nur mit Joysticks. Für andere HIDs muss man weiterhin beten, dass die Hardware auch den angekündigten Wertumfang liefert.
Zuletzt geändert von Krishty am 10.04.2013, 01:34, insgesamt 2-mal geändert.
Grund: #includes ergänzt und erwähnt, dass man das WDK braucht
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4878
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: (gelöst) [Raw Input] Kalibrierung finden

Beitrag von Schrompf »

Krishty, Du bekommst den "Boldly Go Where Noone Has Gone Before"-Award in Silber (mit Goldrand). Danke für Deine Arbeit.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (gelöst) [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Dann warte erst, bis du den Rest der HID-Raw-Input-Frickelei siehst – ich schreibe einen Artikel drüber, sobald es zufriedenstellend funktioniert. Dann habe ich mein eigenes DirectInput ;)

Das Kalibrierungsproblem hat mich übrigens sieben Monate genervt; hoffentlich ist das nun endlich überstanden. Ich habe gemerkt, dass einige Spiele (z.B. Live for Speed) intern kalibrieren; und ich fürchte, dass das seine Gründe hat. Andererseits kann ich bis heute nicht glauben dass Microsoft nichts zur Verfügung stellt, womit man Raw Input für HIDs korrekt interpretieren kann.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (gelöst) [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Okay; ich revidiere das oben. Der DINPUT.DLL-Key existiert natürlich nirgendwo sonst als auf meinem eigenen System.

Was plattformunabhängig zu funktionieren scheint, ist der Schlüssel

    HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\VID_    &PID_    \Calibration\0\Type\Axes\

mit den optionalen Unterschlüsseln 0, 1, 2, …, . Dort ist jeweils ein uint32_t-Tripel gespeichert mit Minimum, Mittelstellung, und Maximum.

Gemäß http://msdn.microsoft.com/en-us/library ... e/ff543445 und http://msdn.microsoft.com/en-us/library ... 87464.aspx bedeuten die Indizes der Achsen dabei (Index / DirectInput-GUID / HID Usage Page & Usage):

    0  >  GUID_XAxis    >  0x01 / 0x30 (Generic / X)
    1  >  GUID_YAxis    >  0x01 / 0x31 (Generic / Y)
    2  >  GUID_ZAxis    >  0x01 / 0x32 (Generic / Z)
    3  >  GUID_RxAxis   >  0x01 / 0x33 (Generic / RX)
    4  >  GUID_RyAxis   >  0x01 / 0x34 (Generic / RY)
    5  >  GUID_RzAxis   >  0x01 / 0x35 (Generic / RZ)
    6  >  GUID_Slider   >  0x01 / 0x36 (Generic / Slider)
                        >  0x01 / 0x37 (Generic / Dial)
                        >  0x01 / 0x38 (Generic / Wheel)
                        >  0x02 / 0xBB (Simulation / Throttle)
    7  >  GUID_Slider      (selbe; fragt mich nicht nach dem Unterschied)


Damit weiß man dann, wann man welche Wertebereiche auf welche Eingaben anzuwenden hat.
Zuletzt geändert von Krishty am 12.04.2013, 05:51, insgesamt 1-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
NytroX
Establishment
Beiträge: 367
Registriert: 03.10.2003, 12:47

Re: (gelöst) [Raw Input] Kalibrierung finden

Beitrag von NytroX »

Coole Sache, vielen Dank für deine ausführlichen Erläuterungen.
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (gelöst) [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Wieder zu früh gedankt – immernoch falsch.

Die Zahlen oben stimmen vorne und hinten nicht. Es sieht eher so aus, als würden die Achsen durch OEM-Einstellungen in der Registry zugewiesen – so hat der Schieber z.B. nicht den Index 6, der GUID_Slider entsprechen würde, sondern … 3. Scheinbar ist der einzige Weg, das herauszufinden, in den OEM-Einstellungen Achse 3 zu öffnen und den Wert zu lesen – den String Throttle, der zusätzlich durch einen Wert Attributes an eine bestimmte HID Usage Page / Usage gebunden werden kann.

Ich bin mir auch nicht sicher, dass das wirklich durch Strings kodiert wird, zumal ich keine vollständige Tabelle von denen finden konnte. Ich habe jetzt hier ein Lenkrad, ein Gamepad, und zwei Joysticks mit ziemlich exotischen Einstellungen und melde mich zurück, sobald ich die Kalibrierung nachvollziehen kann.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (gelöst) [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Nagut; also mal wieder ohne Gewähr:

DirectInput arbeitet intern mit 8 Achsen der Indizes 0–7 gemäß der Tabelle oben: X, Y, Z, RX, RY, RZ, Slider, Slider 2.

Zuerst prüft DirectInput, welche Achsen davon das Gerät nativ anbietet und bindet sie an die Indizes.

Dann werden die Werte Attributes unter HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\VID_xxxx&PID_xxxx\Axes\x geladen. Die letzten 32 Bits sind eine Kombination aus HID Usage Page und Usage. Damit werden entweder Verbindungen überschrieben oder weitere hinzugefügt – so dass man etwa einen Gamepad-Stick, der normalerweise RY ist, als Gaspedal auf Z benutzen kann.

Jetzt wird es verzwickter: Gemäß dem ersten Abschnitt von http://msdn.microsoft.com/en-us/library ... e/ff543445 werden die Achsen möglicherweise umsortiert. Zwar sagt der Abschnitt, „the default mapping for devices reporting through HID has not changed except that GUID_Slider axes are no longer substituted for GUID_ZAxis“, aber ich habe gerade die starke Vermutung, dass das für das Registry-Mapping weiterhin zutrifft: Bieten meine Controller kein Z an, landen die Slider grundsätzlich bei Index 2. Dummerweise habe ich keinen Controller mit Z und Slider zugleich, mit dem ich sicherstellen könnte, dass der Slider dann noch auf 6 landet.

Naja. Dann ist jedenfalls allen besetzten DirectInput-Achsen eine HID-Achse zugeordnet und es geht weiter wie 2 Posts weiter oben.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (gelöst) [Raw Input] Kalibrierung finden

Beitrag von Krishty »

Hatte ich bisher vergessen, aber eines sollte man beachten: Windows erlaubt, einen bevorzugten Controller auszuwählen. Den sollte dann natürlich auch die eigene Anwendung bevorzugen.

Unter HKEY_CURRENT_USER\­System\­CurrentControlSet\­Control\­MediaResources\­Joystick\­DINPUT.DLL\­CurrentJoystickSettings\­Joystick1OEMName findet ihr einen Wert in der Form VID_xxxx&PID_xxxx, der die Vendor ID und die Product ID angibt. (Für alle weiteren Gamecontroller existieren Joystick2OEMName usw; aber die sind allgemein unwichtig.)

(Damit ihr nicht die weichen Trennzeichen aus dem Text oben rausfischen müsst:)

Code: Alles auswählen

L"System\\CurrentControlSet\\Control\\MediaResources\\Joystick\\DINPUT.DLL\\CurrentJoystickSettings"
Der Wert, der da eingetragen ist, muss nicht zwingend am System angeschlossen sein – so lange der Benutzer nach dem Abklemmen des Lieblingsgeräts nicht in die Gamecontrollereinstellungen von Windows geht, schwirrt es dort weiter als Geist herum.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten