Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
XInput permite a las aplicaciones de Windows procesar las interacciones del controlador (incluidos los efectos de rumberación del controlador y la entrada y salida de voz).
En este tema se proporciona una breve introducción a las funcionalidades de XInput y cómo configurarla en una aplicación. Incluye lo siguiente:
Introducción a XInput
Las aplicaciones pueden usar la API XInput para comunicarse con controladores de juegos cuando se conectan a un equipo Windows (se pueden conectar hasta cuatro controladores únicos a la vez).
Con esta API, se puede consultar cualquier controlador conectado compatible para su estado y se pueden establecer efectos de vibración. Los controladores que tienen los auriculares conectados también se pueden consultar para dispositivos de entrada y salida de sonido que se pueden usar con los auriculares para el procesamiento de voz.
Diseño del controlador
Los controladores compatibles tienen dos sticks direccionales analógicos, cada uno con un botón digital, dos desencadenadores analógicos, una almohadilla direccional digital con cuatro direcciones y ocho botones digitales. Los estados de cada una de estas entradas se devuelven en la estructura XINPUT_GAMEPAD cuando se llama a la función XInputGetState .
El controlador también tiene dos motores de vibración para proporcionar efectos de retroalimentación de fuerza al usuario. Las velocidades de estos motores se especifican en la estructura XINPUT_VIBRATION que se pasa a la función XInputSetState para establecer efectos de vibración.
Opcionalmente, un casco se puede conectar al controlador. Los auriculares tienen un micrófono para la entrada de voz y un auriculares para la salida de sonido. Puedes llamar a la función XInputGetAudioDeviceIds o XInputGetDSoundAudioDeviceGuids heredada para obtener los identificadores de dispositivo que corresponden a los dispositivos para el micrófono y los auriculares. A continuación, puede usar las API de audio principal para recibir la entrada de voz y enviar la salida de sonido.
Uso de XInput
El uso de XInput es tan sencillo como llamar a las funciones XInput según sea necesario. Con las funciones XInput, puede obtener el estado del controlador, obtener identificadores de audio de auriculares y establecer efectos de vibración del controlador.
Varios controladores
La API XInput admite hasta cuatro controladores conectados en cualquier momento. Todas las funciones XInput requieren un parámetro dwUserIndex que se pasa para identificar el controlador que se va a establecer o consultar. Este identificador estará en el intervalo de 0 a 3 y XInput lo establecerá automáticamente. El número corresponde al puerto en el que está conectado el controlador y no se puede modificar.
Cada controlador muestra qué identificador está usando al iluminar un cuadrante en el "anillo de luz" en el centro del controlador. Un valor dwUserIndex de 0 corresponde al cuadrante superior izquierdo; la numeración continúa alrededor del anillo en orden de las agujas del reloj.
Las aplicaciones deben admitir varios controladores.
Obtención del estado del controlador
A lo largo de la duración de una aplicación, la obtención del estado de un controlador probablemente se realizará con más frecuencia. De fotograma a fotograma en una aplicación de juego, el estado debe recuperarse y actualizar la información del juego para reflejar los cambios en el mando.
Para recuperar el estado, use la función 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
}
}
Tenga en cuenta que el valor devuelto de XInputGetState se puede usar para determinar si el controlador está conectado. Las aplicaciones deben definir una estructura para contener información interna del controlador; esta información debe compararse con los resultados de XInputGetState para determinar qué cambios, como pulsaciones de botón o deltas del controlador analógico, se realizaron ese fotograma. En el ejemplo anterior, g_Controllers representa dicha estructura.
Una vez recuperado el estado en una estructura de XINPUT_STATE , puede comprobar si hay cambios y obtener información específica sobre el estado del controlador.
El miembro dwPacketNumber de la estructura XINPUT_STATE se puede usar para comprobar si el estado del controlador ha cambiado desde la última llamada a XInputGetState. Si dwPacketNumber no cambia entre dos llamadas secuenciales a XInputGetState, no se ha producido ningún cambio en el estado. Si difiere, la aplicación debe comprobar el miembro Gamepad de la estructura XINPUT_STATE para obtener información de estado más detallada.
Por razones de rendimiento, no llame a XInputGetState para un espacio de usuario "vacío" en cada fotograma. Recomendamos espaciar las comprobaciones de nuevos controladores cada pocos segundos.
Zona muerta
Para que los usuarios tengan una experiencia de juego coherente, el juego debe implementar correctamente la zona muerta. La zona muerta son los valores de "movimiento" que el controlador informa incluso cuando los sticks analógicos no están siendo movidos y están centrados. También hay una zona muerta para los 2 desencadenadores analógicos.
Nota:
Los juegos que usan XInput que no filtran la zona muerta en absoluto experimentarán un juego deficiente. Tenga en cuenta que algunos controladores son más sensibles que otros, por lo que la zona muerta puede variar de unidad a unidad. Se recomienda probar los juegos con varios controladores diferentes en diferentes sistemas.
Las aplicaciones deben usar "zonas muertas" en entradas analógicas (desencadenadores, sticks) para indicar cuándo se ha realizado un movimiento lo suficientemente en el stick o desencadenador para que se considere válido.
La aplicación debe comprobar si hay zonas muertas y responder correctamente, como en este ejemplo:
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
En este ejemplo se calcula el vector de dirección del controlador y cuánto se ha empujado el controlador a lo largo del vector. Esto permite imponer una zona muerta circular simplemente comprobando si la magnitud del controlador es mayor que el valor de la zona muerta. Además, el código normaliza la magnitud del controlador que luego se puede multiplicar por un factor específico del juego para convertir la posición del controlador en unidades relevantes para el juego.
Tenga en cuenta que puede definir sus propias zonas muertas para los sticks y desencadenadores (desde 0 a 65534), o puede usar las zonas muertas proporcionadas definidas como XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE y XINPUT_GAMEPAD_TRIGGER_THRESHOLD en XInput.h:
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
Una vez aplicada la zona muerta, puede resultar útil escalar el intervalo resultante [0.0..1.0] punto flotante (como en el ejemplo anterior) y, opcionalmente, aplicar una transformación no lineal.
Por ejemplo, con los juegos de conducción, puede ser útil elevar el resultado al cubo para proporcionar una mejor sensación al conducir los coches con un gamepad, ya que al elevar el resultado al cubo se obtiene más precisión en los rangos inferiores, lo cual es deseable, ya que los jugadores suelen aplicar fuerza suave para lograr un movimiento sutil o aplicar fuerza dura por completo en una dirección para obtener una respuesta rápida.
Establecer efectos de vibración
Además de obtener el estado del controlador, también puede enviar datos de vibración al controlador para modificar los comentarios proporcionados al usuario del controlador. El controlador contiene dos motores rumberos que se pueden controlar de forma independiente pasando valores a la función XInputSetState .
La velocidad de cada motor se puede especificar mediante un valor WORD en la estructura XINPUT_VIBRATION que se pasa a la función XInputSetState de la siguiente manera:
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 );
Tenga en cuenta que el motor derecho es el motor de alta frecuencia, el motor izquierdo es el motor de baja frecuencia. No siempre necesitan establecerse en la misma cantidad, ya que proporcionan efectos diferentes.
Obtención de identificadores de dispositivo de audio
Los auriculares de un controlador tienen estas funciones:
- Grabar sonido mediante un micrófono
- Reproducir sonido con auriculares
Use este código para obtener los identificadores de dispositivo para los auriculares:
WCHAR renderId[ 256 ] = {0};
WCHAR captureId[ 256 ] = {0};
UINT rcount = 256;
UINT ccount = 256;
XInputGetAudioDeviceIds( i, renderId, &rcount, captureId, &ccount );
Después de obtener los identificadores de dispositivo, puede crear las interfaces adecuadas. Por ejemplo, si usa XAudio 2.8, use este código para crear una voz de maestro para este dispositivo:
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;
Para obtener información sobre cómo usar el identificador de dispositivo captureId, consulta Capturar una secuencia.
Obtención de GUIDs de DirectSound (SDK heredado de DirectX únicamente)
Los auriculares que se pueden conectar a un controlador tienen dos funciones: puede grabar sonido mediante un micrófono y reproducir el sonido mediante un auricular. En la API XInput, estas funciones se realizan a través de DirectSound, mediante las interfaces IDirectSound8 e IDirectSoundCapture8 .
Para asociar el micrófono y los auriculares con sus interfaces de DirectSound adecuadas, debe obtener los DirectSoundGUIDs de los dispositivos de captura y reproducción llamando a XInputGetDSoundAudioDeviceGuids.
Nota:
No se recomienda usar DirectSound heredado y no está disponible en las aplicaciones de la Tienda Windows. La información de esta sección solo se aplica a la versión del SDK de DirectX de XInput (XInput 1.3). La versión de Windows 8 de XInput (XInput 1.4) usa exclusivamente identificadores de dispositivo de la API de sesión de audio de Windows (WASAPI) que se obtienen a través de XInputGetAudioDeviceIds.
XInputGetDSoundAudioDeviceGuids( i, &dsRenderGuid, &dsCaptureGuid );
Una vez que haya recuperado los GUID, puede crear las interfaces adecuadas llamando a DirectSoundCreate8 y DirectSoundCaptureCreate8 de esta manera:
// 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;