¡Esta es una revisión vieja del documento!
Es la parte de DirectX que interactua directamente con los dispositivos de entrada (teclado, ratón, joystick…), utilizándolo obtienes mayor flexibilidad en la obtención de datos introducidos por el usuario. Sus ventajas son que al tratarse directamente con el dispositivo se desvinculan a tu aplicación las configuraciones realizadas por el usuario en el sistema operativo, además no funciona por eventos sino que a cada momento del tiempo el dispositivo tiene un estado distinto. Seguiremos los siguientes pasos para una correcta utilización:
Recuerda:
dxguid.lib y dinput8.lib.Código general que se ha utilizado para los ejemplos:
#include <dinput.h> #define MSGBOX(body) MessageBox(NULL,body,"",MB_OK);
Para crear un objeto utilizaremos la función: DirectInput8Create, a esta se le pasan los siguientes argumentos:
LPDIRECTINPUT8 objDI; if (FAILED(DirectInput8Create(inst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&objDI, NULL))) MSGBOX("Error al crear el objeto DInput");
Para crear un objeto dispositivo tendremos que declarar primero un objeto de este tipo (LPDIRECTINPUTDEVICE8) y luego llamar a la función CreateDevice del objeto LPDIRECTINPUT8 ya creado anteriormente. Esta función recoge los siguientes parámetros:
Tenemos que asignar al dispositivo un formato de datos, es decir, indicar cómo vamos a tratar con él; tenemos los siguientes: c_dfDIJoystick, c_dfDIJoystick2, c_dfDIKeyboard, c_dfDIMouse, y c_dfDIMouse2. Son variables globales que nos liberan del tedio de hacerlo por nuestra cuenta, sólo tenemos que pasar la elegida como referencia al método SetDataFormat del dispositivo que queramos.
Esto es cómo el dispositivo va a comunicarse con el Sistema Operativo, para indicarlo, en el objeto del dispositivo (LPDIRECTINPUTDEVICE8) llamamos al método SetCooperativeLevel pasándole:
Básicamente con esto indicas si se seguirá el dispositivo cuando deje de estar en primer plano (foreground) o no; y si será exclusivo (que bloqueará el dispositivo para si mismo) o no. Podemos utilizar la siguiente combinación:
Esto es, como ya lo tenemos configurado se llama al método Acquire de este y podremos comenzar a utilizarlo.
void createKeyboard () { objDI->CreateDevice(GUID_SysKeyboard, &keyb, NULL); keyb->SetDataFormat(&c_dfDIKeyboard); keyb->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY); keyb->Acquire (); } void createMouse () { objDI->CreateDevice(GUID_SysMouse, &mouse, NULL); mouse->SetDataFormat(&c_dfDIMouse); mouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); mouse->Acquire (); }
Una vez acabemos de utilizar DInput debemos liberar los dispositivos (llamando a Unadquire y luego a Release) y luego liberar el objeto DInput, llamando al Release de este:
keyb->Unacquire(); keyb->Release(); mouse->Unacquire(); mouse->Release(); objDI->Release(); keyb = NULL; mouse = NULL; objDI = NULL;
Una vez tengas funcionando tu aplicación, si esta pierde el foco (aunque sea por un messagebox propio) tendrás que volver a cargar el objeto dispositivo. Puedes detectar que la aplicación ha perdido el foco mediante el mensaje WM_ACTIVATEAPP al WindowProcedure. Sabrás si se ha activado\desactivado mediante el wParam.
Notarás, también, que has perdido algún dispositivo porque métodos de este ya no devolverán DI_OK.
Los datos del teclado vienen dados en un buffer donde se guarda el estado actual de cada tecla. Para recoger dicho buffer únicamente has de declarar un array de bytes de 256 (nº de teclas) y llamar a la función GetDeviceState del objeto dispositivo pasándole como primer parámetro el tamaño del buffer (256 o sizeof(buffer)).
Para saber si se ha presionado la tecla que queremos existen unas constantes de DInput con los nombres de las teclas (DIK_ESCAPE, DIK_LEFT…), son números que corresponden a una posición del buffer. Para saber si una tecla en concreto se ha pulsado el contenido en el buffer de la posición correspondiente añadiendole lógicamente (&) un valor 0x80 tiene que dar como valor booleano true.
#define KEYDOWN(name, key) (name[key] & 0x80) ... byte buffer[256]; HRESULT hr = keyb->GetDeviceState(sizeof(buffer), (LPVOID)&buffer); if (hr == DI_OK) { if (KEYDOWN(buffer, DIK_ESCAPE)) ... if (KEYDOWN(buffer, DIK_LEFT)) ... }
Para controlar la posición del mouse necesitarás de una nueva estructura: DIMOUSESTATE. Un objeto de esta es lo que has de pasar al GetDeviceState del objeto dispositivo del mouse junto con un sizeof:
DIMOUSESTATE msdata; mouse->GetDeviceState(sizeof(msdata), &msdata);
Las propiedades que contiene son: lX e lY. En ellas encontrarás cuanto se ha movido el mouse en esas coordenadas desde la última vez que se hizo un GetDeviceState. También contiene un array de bytes con 4 posiciones correspondientes a 4 botones del ratón, para saber si se ha pulsado algún botón sólo has de añadir lógicamente (&) el valor 0x80 a la posición de dicho array correspondiente al botón (izquierdo = 0, derecho = 1…) y te dará un valor booleano que indica si ha sido pulsado o no. Otro valor, el lZ, indica cuanto ha sido movida la rueda.
DIMOUSESTATE msdata; mouse->GetDeviceState(sizeof(msdata), &msdata); mouseX += msdata.lX; mouseY += msdata.lY; if (msdata.rgbButtons[0] & 0x80) ... if (msdata.lZ > 0) ...
if (FAILED(DirectInput8Create(inst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&objDI, NULL))) MSGBOX("Error al crear el objeto DInput");