Paso 3: Conseguir entrada de GAMEPAD
Ahora, que sabemos cómo enviar la información a Arduino, sólo tenemos que aprender a adquirir la entrada desde el gamepad XBOX.
En esta sección vamos a aprender los conceptos básicos de XInput y escribir un programa muy sencillo, que muestra el estado actual del gamepad en la salida de la consola. También vamos a aprender algunos aspectos importantes del procesamiento previo de los valores de entrada para evitar rangos de entrada problemática Stick ("zonas muertas").
LOS CONCEPTOS BÁSICOS
XInput API proporciona los medios de conseguir la entrada de los controladores de XBOX 360 e incluye una variedad de herramientas para establecer los efectos de control (retroalimentación de la farsa), proceso de entrada/salida de audio para auriculares de juegos de azar y hacer otras cosas interesantes.
XInput soporta hasta 4 reguladores, pero en nuestra situación sólo controlador #0 se utilizará como predeterminada.
Para actualizar el estado actual del pad usaremos la función XInputGetState() . Lleva 2 parámetros: el ID del gamepad (que es 0 en la mayoría de los casos) y el puntero a la variable de estado XInput. El valor devuelto de XInputGetState puede utilizarse para comprobar la disponibilidad del pad. El valor de ERR_SUCCESS significa que el gamepad está en, y XInput estado ahora tiene su actual estado.
XINPUT_STATE consta de los siguientes elementos:
typedef struct _XINPUT_STATE { DWORD dwPacketNumber; XINPUT_GAMEPAD Gamepad; } XINPUT_STATE;
dwPacketNumber indica si se ha cambiado el estado de gamepad.
Mando de control es un tipo de datos, que representa el estado actual del gamepad, incluyendo Stick posiciones, valores de gatillo, D-pad y botón de las banderas.
typedef struct _XINPUT_GAMEPAD { WORD wButtons; BYTE bLeftTrigger; BYTE bRightTrigger; SHORT sThumbLX; SHORT sThumbLY; SHORT sThumbRX; SHORT sThumbRY; } XINPUT_GAMEPAD;
sThumbLX, sThumbLY, sThumbRX y sThumbRY son números enteros firmados 16-bit, que toman valores de −32, 768 a 32.767. Corresponden a las posiciones actuales de Stick.
bLeftTrigger y bRightTrigger toman valores en el rango de 0..255.
wButtons representa el estado de todos los botones en un mando de XBox, donde cada bit corresponde al estado actual de cada botón individual. Si queremos comprobar que si se presionó el botón de X tenemos que realizar las siguientes operaciones:
XINPUT_STATE gpState; // Create state variable memset(&gpState,0,sizeof(XINPUT_STATE)); // Reset state DWORD res = XInputGetState(0,&gpState); // Get new state if(gpState.wButtons & 0x4000 ) { printf("Xplosive kick!\n"); }
La siguiente lista muestra todos los botones y sus correspondientes máscaras de bits:
XINPUT_GAMEPAD_DPAD_UP 0x0001 XINPUT_GAMEPAD_DPAD_DOWN 0x0002 XINPUT_GAMEPAD_DPAD_LEFT 0x0004 XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 XINPUT_GAMEPAD_START 0x0010 XINPUT_GAMEPAD_BACK 0x0020 XINPUT_GAMEPAD_LEFT_THUMB 0x0040 // These are thumbstick buttons XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 // Left bumper XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 // Right bumper XINPUT_GAMEPAD_A 0x1000 XINPUT_GAMEPAD_B 0x2000 XINPUT_GAMEPAD_X 0x4000 XINPUT_GAMEPAD_Y 0x8000
VAMOS A PRACTICAR
En este momento tenemos todas las herramientas que necesitamos para escribir nuestro primer programa con XInput. Sería risiblemente simple, pero ayudarán a comprender cómo funciona este proceso y los elementos de XInput que necesitamos.
#include "stdafx.h" #include <Windows.h> #include <XInput.h> #pragma comment(lib, "XInput.lib") // required for linker int _tmain(int argc, _TCHAR* argv[]) { XINPUT_STATE gpState; // Gamepad state int player = -1; // Gamepad ID // Polling all 4 gamepads to see who's alive for(int i=0;i<4;i++) { DWORD res = XInputGetState(i,&gpState); // Getting state if(res==ERROR_SUCCESS) // If alive - print message { printf("Controller #%d is ON!\n",i+1); player = i; // Assign last alive gamepad as active } } if(player<0) // If player==-1 in other words... { printf("Haven't found any gamepads...\n"); } else { while(true) { system("CLS"); // Clear screen memset(&gpState,0,sizeof(XINPUT_STATE)); // Reset state DWORD res = XInputGetState(0,&gpState); // Get new state printf("LX\tLY\tRX\tRY\tLTrig\tRTrig\tButtons\n"); // Print header // Thumbstick values are divided by 256 for better consistency printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\n", gpState.Gamepad.sThumbLX/256, gpState.Gamepad.sThumbLY/256, gpState.Gamepad.sThumbRX/256, gpState.Gamepad.sThumbRY/256, gpState.Gamepad.bLeftTrigger, gpState.Gamepad.bRightTrigger, gpState.Gamepad.wButtons); } } system("PAUSE"); return 0; }
Una vez se genere la solución y ejecutar su programa, usted verá la salida cambia cuando se mueve thumbsticks, o los botones en el gamepad. Enviaremos esta información a la placa Arduino en la siguiente sección de este tutorial.
Ahora quiero que preste atención a la salida, cuando no haces nada. Los valores de LX, LY, RX y RY no son iguales a 0, les esperamos. Esto sucede por varias razones, pero lo más importante es que somos conscientes de este fenómeno.
Estas fluctuaciones y las inconsistencias en los valores se llaman "zonas muertas". Para deshacerse de este desagradable anomalía debemos encontrar el valor marginal más bajo al que podemos considerar que el stick se realmente empuja en cierta dirección.
Para ello tenemos que definir un umbral de zona de descanso y se compara con valores actuales. Revisa la referencia MSDN para obtener más información.
Mientras tanto, utilice este código de ejemplo para corregir estos valores:
float LX = gpState.Gamepad.sThumbLX; // Get LX float LY = gpState.Gamepad.sThumbLY; // Get LY magnitude = sqrt(LX*LX+LY*LY); // Calculate the radius of current position if(magnitude < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) // Inside dead zone? { // Set all to 0 LX=0.0; LY=0.0; } // Do the same for RX and RY
También hay valores predefinidas zona muerta para izquierda y derecha thumbsticks y desencadenadores. Puede utilizar estos, o definir sus propios límites (en mi caso ~ 6500 trabajado para stick izquierdo y derecho), pero recuerde que estos valores dependen en gran medida cómo Beat-up gamepad es!
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 #define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 #define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
LECTURA ADICIONAL
Es este el recurso adicional sólo voy a mencionar: XInput juego controlador API
Todo lo que necesitas saber sobre el XInput, incluyendo la referencia completa y útil guía de programación tiene.
Eso es todo por esta parte. Ahora, vamos a tratar de combinar nuestras habilidades en la programación de mandos y conexiones serie a control Arduino remotamente!!! ... en caso de que usted se olvidó de donde empezamos...