Sdílet prostřednictvím


Začínáme s XInput v aplikacích pro Windows

XInput umožňuje aplikacím systému Windows zpracovávat interakce kontroleru (včetně záporných efektů kontroleru a hlasového vstupu a výstupu).

Toto téma obsahuje stručný přehled možností XInputu a jeho nastavení v aplikaci. Zahrnuje následující:

Úvod do XInputu

Aplikace můžou pomocí rozhraní XInput API komunikovat s herními řadiči, když jsou připojené k počítači s Windows (až čtyři jedinečné řadiče je možné připojit najednou).

Pomocí tohoto rozhraní API je možné dotazovat jakýkoli kompatibilní připojený kontroler na jeho stav a efekty vibrací je možné nastavit. Kontrolery, které mají připojenou náhlavní soupravu, se také dají dotazovat na zvuková vstupní a výstupní zařízení, která se dají použít s náhlavní soupravou pro zpracování hlasu.

Rozložení kontroleru

Kompatibilní ovladače mají dvě analogové směrové páčky, každá s digitálním tlačítkem, dvě analogové spouště, digitální směrový kříž se čtyřmi směry a osm digitálních tlačítek. Stavy každého z těchto vstupů se vrátí ve struktuře XINPUT_GAMEPAD, když je volána funkce XInputGetState.

Kontroler má také dva vibrační motory, které uživateli poskytují zpětnou vazbu prostřednictvím silových účinků. Rychlosti těchto motorů jsou specifikovány ve struktuře XINPUT_VIBRATION, která je předána do funkce XInputSetState pro nastavení vibračních efektů.

Volitelně můžete náhlavní soupravu připojit k ovladači. Náhlavní souprava má mikrofon pro hlasový vstup a sluchátko pro zvukový výstup. Můžete volat funkci XInputGetAudioDeviceIds nebo starší funkci XInputGetDSoundAudioDeviceGuids pro získání identifikátorů zařízení, které odpovídají zařízením pro mikrofon a sluchátka. Potom můžete použít rozhraní API pro Core Audio k příjmu hlasového vstupu a odesílání zvukového výstupu.

Použití XInputu

Použití XInput je stejně jednoduché jako volání funkcí XInput podle potřeby. Pomocí funkcí XInput můžete načíst stav ovladače, získat ID zvuku náhlavní soupravy a nastavit vibrační efekty ovladače.

Více kontrolerů

Rozhraní XInput API podporuje kdykoliv až čtyři kontrolery připojené. Funkce XInput všechny vyžadují parametr dwUserIndex, který se předává k identifikaci kontroléru, který je nastavován nebo dotazován. Toto ID bude v rozsahu od 0 do 3 a nastaví se automaticky pomocí XInputu. Číslo odpovídá portu, ke kterému je řadič připojen, a není možné ho upravit.

Každý kontroler zobrazí ID, které používá, tím, že ve středu kontroleru rozsvítí kvadrant na "prstenci světla". Hodnota dwUserIndex 0 odpovídá levému hornímu kvadrantu; číslování pokračuje kolem kruhu v pořadí po směru hodinových ručiček.

Aplikace by měly podporovat více kontrolerů.

Získání stavu ovladače

Během doby trvání aplikace bude získání stavu z kontroleru pravděpodobně provedeno nejčastěji. U každého snímku v herní aplikaci by měl být načten stav a aktualizovány údaje o hře, aby odrážely změny ovladače.

K načtení stavu použijte funkci XInputGetState:

DWORD dwResult;    
for (DWORD i=0; i< XUSER_MAX_COUNT; i++ )
{
    XINPUT_STATE state;
    ZeroMemory( &state, sizeof(XINPUT_STATE) );

    // Simply get the state of the controller from XInput.
    dwResult = XInputGetState( i, &state );

    if( dwResult == ERROR_SUCCESS )
    {
        // Controller is connected
    }
    else
    {
        // Controller is not connected
    }
}

Všimněte si, že návratová hodnota XInputGetState lze použít k určení, zda je kontroler připojený. Aplikace by měly definovat strukturu pro uchovávání informací o interním ovladači, a tyto informace by měly být porovnány s výsledky XInputGetState, aby se určilo, jaké změny, například stisknutí tlačítka nebo změny analogového ovladače, byly provedeny v tomto snímku. V předchozím příkladu g_Controllers takovou strukturu představuje.

Jakmile se stav načte ve struktuře XINPUT_STATE, můžete zkontrolovat změny a získat konkrétní informace o stavu kontroleru.

dwPacketNumber člen struktury XINPUT_STATE lze použít ke zjištění, zda se stav ovladače změnil od posledního volání XInputGetState. Pokud se dwPacketNumber mezi dvěma sekvenčními voláními XInputGetStatenezmění, tak nedošlo ke změně stavu. Pokud se liší, měla by aplikace zkontrolovat Gamepad člen struktury XINPUT_STATE a získat podrobnější informace o stavu.

Z výkonnostních důvodů nevolejte XInputGetState pro prázdný slot uživatele každý rámec. Místo toho doporučujeme rozložit kontroly nových kontrolerů po několika sekundách.

Mrtvá zóna

Aby uživatelé měli konzistentní herní prostředí, musí vaše hra správně implementovat mrtvou zónu. Mrtvá zóna jsou pohybové hodnoty hlášené kontrolerem, i když jsou analogové joysticky nedotčené a ve středu. Existuje také mrtvá zóna pro 2 analogové spouště.

Poznámka

Hry, které používají XInput, které vůbec nefiltrují mrtvou zónu, budou mít špatný herní výkon. Upozorňujeme, že některé kontrolery jsou citlivější než jiné, takže se mrtvá zóna může lišit od jednotky po jednotku. Doporučuje se otestovat hry s několika různými řadiči v různých systémech.

Aplikace by měly u analogových vstupů (spouště, páčky) použít "mrtvé zóny", aby bylo možné určit, kdy byl pohyb na páčce nebo spoušti dostatečný k tomu, aby byl považován za platný.

Vaše aplikace by měla zkontrolovat neaktivní zóny a reagovat na ně, jak je znázorněno v tomto příkladu:

XINPUT_STATE state = g_Controllers[i].state;

float LX = state.Gamepad.sThumbLX;
float LY = state.Gamepad.sThumbLY;

//determine how far the controller is pushed
float magnitude = sqrt(LX*LX + LY*LY);

//determine the direction the controller is pushed
float normalizedLX = LX / magnitude;
float normalizedLY = LY / magnitude;

float normalizedMagnitude = 0;

//check if the controller is outside a circular dead zone
if (magnitude > INPUT_DEADZONE)
{
    //clip the magnitude at its expected maximum value
    if (magnitude > 32767) magnitude = 32767;

    //adjust magnitude relative to the end of the dead zone
    magnitude -= INPUT_DEADZONE;

    //optionally normalize the magnitude with respect to its expected range
    //giving a magnitude value of 0.0 to 1.0
    normalizedMagnitude = magnitude / (32767 - INPUT_DEADZONE);
}
else //if the controller is in the deadzone zero out the magnitude
{
    magnitude = 0.0;
    normalizedMagnitude = 0.0;
}

//repeat for right thumb stick

Tento příklad vypočítá směrový vektor kontroleru a to, jak daleko podél vektoru byl kontroler posunut. To umožňuje vynucování kruhového mrtvého pásma tím, že jednoduše zkontrolujete, jestli je velikost kontroleru větší než hodnota mrtvého pásma. Kromě kódu normalizuje velikost kontroleru, který pak může být vynásoben konkrétním faktorem hry za účelem převodu pozice kontroleru na jednotky relevantní pro hru.

Všimněte si, že můžete definovat vlastní neaktivní zóny pro hůly a triggery (kdekoli od 0 do 65534) nebo můžete použít zadaná neaktivní pásma definovaná jako XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE a XINPUT_GAMEPAD_TRIGGER_THRESHOLD v XInput.h:

#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD    30

Po vynucení nezóny může být užitečné škálovat výsledný rozsah [0.0..1.0] v plovoucí desetinné čárce (jako v příkladu výše) a volitelně použít nelineární transformaci.

U závodních her může být užitečné krychlit výsledek, aby poskytoval lepší pocit řízení aut pomocí gamepadu, protože krychlení výsledku dává větší přesnost v nižších rozsazích, což je žádoucí, protože hráči obvykle aplikují menší sílu k získání jemného pohybu nebo aplikují silnou sílu až na doraz v jednom směru, aby získali rychlou odezvu.

Nastavení efektů kmitání

Kromě získání stavu kontroleru můžete také odeslat data o vibracích kontroleru, abyste změnili zpětnou vazbu poskytnutou uživateli kontroleru. Kontroler obsahuje dva vibrační motory, které lze ovládat nezávisle předáváním hodnot do funkce XInputSetState.

Rychlost každého motoru lze zadat pomocí hodnoty WORD ve struktuře XINPUT_VIBRATION, která je předána XInputSetState následujícím způsobem:

XINPUT_VIBRATION vibration;
ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) );
vibration.wLeftMotorSpeed = 32000; // use any value between 0-65535 here
vibration.wRightMotorSpeed = 16000; // use any value between 0-65535 here
XInputSetState( i, &vibration );

Všimněte si, že pravý motor je vysokofrekvenční motor, levý motor je nízkofrekvenční motor. Nemusí být vždy nastaveny na stejnou částku, protože poskytují různé účinky.

Získání identifikátorů zvukových zařízení

Náhlavní souprava pro kontroler má tyto funkce:

  • Nahrávání zvuku pomocí mikrofonu
  • Přehrávání zvuku pomocí sluchátek

Pomocí tohoto kódu získejte identifikátory zařízení pro náhlavní soupravu:

WCHAR renderId[ 256 ] = {0};
WCHAR captureId[ 256 ] = {0};
UINT rcount = 256;
UINT ccount = 256;

XInputGetAudioDeviceIds( i, renderId, &rcount, captureId, &ccount );

Po získání identifikátorů zařízení můžete vytvořit příslušná rozhraní. Pokud například používáte XAudio 2.8, použijte tento kód k vytvoření hlavního hlasu pro toto zařízení.

IXAudio2* pXAudio2 = NULL;
HRESULT hr;
if ( FAILED(hr = XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR ) ) )
    return hr;

IXAudio2MasteringVoice* pMasterVoice = NULL;
if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, renderId, NULL, AudioCategory_Communications ) ) )
    return hr;

Informace o tom, jak používat identifikátor zařízení captureId, najdete v tématu Zachycení streamu.

Jak získat identifikátory GUID DirectSound (pouze pro starší verze sady DirectX SDK)

Náhlavní souprava, která může být připojená k ovladači, má dvě funkce: může nahrát zvuk pomocí mikrofonu a přehrávat zvuk pomocí sluchátek. V rozhraní API XInput se tyto funkce provádějí prostřednictvím rozhraní DirectSound, pomocí rozhraní IDirectSound8 a IDirectSoundCapture 8.

Chcete-li přidružit mikrofon a sluchátka náhlavní soupravy s jejich příslušnými rozhraními DirectSound, je potřeba získat DirectSoundGUIDs pro zařízení pro záznam a přehrávání voláním XInputGetDSoundAudioDeviceGuids.

Poznámka

Použití starší verze DirectSound se nedoporučuje a není k dispozici v aplikacích pro Windows Store. Informace v této části platí jenom pro verzi sady DirectX SDK XInput (XInput 1.3). Verze XInput (XInput 1.4) ve Windows 8 používá výhradně identifikátory zařízení rozhraní WASAPI (Windows Audio Session API), které jsou získány prostřednictvím XInputGetAudioDeviceIds.

XInputGetDSoundAudioDeviceGuids( i, &dsRenderGuid, &dsCaptureGuid );

Po načtení identifikátorů GUID můžete vytvořit příslušná rozhraní voláním DirectSoundCreate8 a DirectSoundCaptureCreate8 takto:

// Create IDirectSound8 using the controller's render device
if( FAILED( hr = DirectSoundCreate8( &dsRenderGuid, &pDS, NULL ) ) )
   return hr;

// Set coop level to DSSCL_PRIORITY
if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_NORMAL ) ) )
   return hr;

// Create IDirectSoundCapture using the controller's capture device
if( FAILED( hr = DirectSoundCaptureCreate8( &dsCaptureGuid, &pDSCapture, NULL ) ) )
   return hr;

Referenční programování