Lectura de un joystick

De Wikipedia, la enciclopedia libre

En este artículo vamos a estudiar varias maneras de leer la información que nos suministra un dispositivo controlador de juegos, como un joystick, un gamepad, etc. Aunque nos centraremos en un joystick, con lo que reducimos el campo a leer la información de los ejes y de los botones.

Antes de empezar, cabe destacar que joystick puede ser analógico o digital, en función de si la posición de sus ejes es un valor numérico dentro de un rango o bien es una simple variable booleana. No obstante, podemos trabajar en modo análogico con un joystick digital (obtendremos siempre alguno de los dos valores de los extremos para cualquier punto del eje) o bien trabajar con un joystick analógico en modo digital (simplemente sabremos si el stick se ha inclinado en alguna dirección del eje, pero sin especificar cuánto).

Tabla de contenidos

[editar] Ensamblador

Comenzamos con el lenguaje ensamblador. Hoy en día ya no se realiza el proceso de esta forma, pero sirve para ver un caso más y en un lenguaje de programación muy básico (el de más bajo nivel).

Para leer la información del joystick tenemos dos opciones: realizar una llamada a una interrupción o bien leer directamente del puerto de juegos.


[editar] Interrupción 15h

Mediante la interrupción 15h y sus subfunciones podemos leer el estado de un joystick:

  • Lectura de ejes:
    • Entrada -> AH = 84h ; DX = 01h
    • Salida -> AX = valor eje Y ; BX = valor eje X
  • Lectura de pulsadores:
    • Entrada -> AH = 84h ; DX = 00h
    • Salida -> AL = si bit 4 igual a 0, botón 1 pulsado ; si bit 5 igual a 0, botón 2 pulsado


[editar] Puerto de juegos (201h)

La otra manera consiste en obtener la información directamente del puerto de juegos, que es el 201h. El proceso para leer los ejes así como los botones varía bastante de la forma a la que habitualmente estamos acostumbrados (uno para cada cosa), ya que sólo disponemos de un puerto del que leer. Cada bit de este puerto significa una cosa distinta:

  • Bit 0 (LSB): Eje Y del joystick A
  • Bit 1: Eje X del joystick A
  • Bit 2: Eje Y del joystick B
  • Bit 3: Eje X del joystick B
  • Bit 4: Botón 2 del joystick A
  • Bit 5: Botón 1 del joystick A
  • Bit 6: Botón 1 del joystick B
  • Bit 7 (MSB): Botón 1 del joystick B


Los bits que representan los pulsadores del dispositivo controlador siguen lógica negativa: '0' cuando están presionados y '1' cuando no lo están. La lectura de los botones del joystick es sencilla ya que sólo hace falta testear los bits que leemos del puerto de juegos. A continuación se presenta un ejemplo práctico que averigua si el segundo botón del joystick conectado al puerto de juegos está presionado:

mov dx, 201h
out dx, al                ; Iniciamos la transferencia enviando cualquier valor al puerto
in al, dx                 ; Leemos del puerto de juegos
test al,0001000b          ; Comprobamos si el botón 2 está presionado
jz boton_2_no_presionado

Sin embargo la lectura de los ejes es un poco más complicada si estamos trabajando con un joystick analógico. Si por el contrario es un joystick digital, el proceso es equivalente a la lectura de un botón del dispositivo. Por lo tanto, veamos un ejemplo para conocer el valor (ya que recordemos que estamos tratando con un joystick analógico) de los ejes:

 mov  dx, 201h
 mov  bx,0                     ; Contador para el eje X
 out  dx,al                    ; Enviamos cualquier valor al puerto
leer_ejes_X:
 in      al, dx                ; Leemos del puerto
 test    al, 0000001b          ; Comprobamos el bit 1
 jz      fin_lectura_X          ; No hay nada? Fin de lectura del eje X
 inc     bx                    ; Sino, se incrementa el contador de las X
 jmp leer_eje_X


[editar] Entornos de desarrollo para juegos

A continuación vamos a realizar las mismas operaciones que antes (leer el estado de los ejes y de los botones) pero empleando para ello alguna librería especializada en desarrollo de videojuegos. Hoy en día, todas implementan un módulo de trabajo con los periféricos de control de juegos.


[editar] DirectInput

Es el módulo para la lectura y tratamiento de las entradas de usuario (teclado, ratón, joystick y otros controladores) de DirectX.

A continuación, veamos un esqueleto de ejemplo desarrollado en DirectInput 7 en lenguaje C:

  • Declaramos una variable para almacenar el estado del joystick.
CDIJoystick myJoystick1;
  • Comprobamos si existe algún joystick conectado. Para ello se emplea la función GetFirstJoystickID( ) en el caso del primero y GetNextJoystickID( ) para el resto.
LPCDIDEVICEINSTANCE lpddi=NULL;

lpddi = myJoystick1.GetFirstJoystickID();

if (!lpddi)
{
     /* No se ha encontrado ningún joystick */
}
  • Si queremos leer los ejes de un joystick de forma analógica:
myJoystick1.PollDevice();
LPDIJOYSTATE2 joy;

joy = myJoystick1.GetJoystickStateInfo();

printf("Eje X = %d\r\n", joy->lX);
printf("Eje Y = %d\r\n", joy->lY);
  • O bien si los queremos leer de forma digital:
myJoystick1.PollDevice();

if (myJoystick1.IsJoystickLeft()) direccion_Izda = true;
else direccion_Izda = false;

if (myJoystick1.IsJoystickRight()) direccion_Dcha = true;
else direccion_Dcha = false;

if (myJoystick1.IsJoystickUp()) direccion_Arriba = true;
else direccion_Arriba = false;

if (myJoystick1.IsJoystickDown()) direccion_Abajo = true;
else direccion_Abajo = false;
  • Y por último, para leer el estado de los botones del controlador de juegos:
n_Botones = myJoystick1.HowManyButtons();

for (int i = 0; i < n_Botones; i++)
{
     if (myJoystick1.IsJoystickFire(i))
     {
          printf("Pretado el boton: %d\r\n", i);
     }
}


[editar] Allegro

A continuación veremos un pequeño ejemplo de uso de las funciones para joystick de Allegro (nuevamente en lenguaje C):

  • Incluimos el paquete allegro.h.
#include <allegro.h>
  • Inicializamos allegro con allegro_init( ).
if (allegro_init() != 0)
      return 1;
  • Para inicializar el joystick de forma automática invocamos la función install_joystick( ) (con el parámetro JOY_TYPE_AUTODETECT). Debemos llamar a esta rutina antes de invocar cualquier otra función relacionada con el joystick. Tan pronto como hayamos instalado el módulo de joystick, ya seremos capaces de leer el estado de los botones y la información de la dirección.
if (install_joystick(JOY_TYPE_AUTODETECT) != 0)
{
     /* Error inicializando el joystick */
}
  • A continuación, comprobamos el número de joysticks activos mediante la variable global num_joysticks.
if (!num_joysticks)
{
     /* Error: no se encuentra ningun joystick */
}
  • En el caso de emplear de forma analógica el joystick, deberíamos calibrarlo mediante la función calibrate_joystick( ).
/* Emplearemos la variable global joy para acceder a la informacion de todos los joysticks */
while (joy[0].flags & JOYFLAG_CALIBRATE)
{
     msg = calibrate_joystick_name(0);
     printf("%s\n", msg);

     if (calibrate_joystick(0) != 0)
     {
          /* Error calibrando joystick */
     }
}
  • A continuación testeamos si algún botón del joystick está siendo pulsado con la función poll_joystick( ). Ésta actualizará los valores globales del estado del joystick. Este estado es una estructura de tipo JOYSTICK_INFO donde se almacena el número de ejes y de botones y el estado de los mismos.
poll_joystick();

/* Algun boton presionado? */
for (c=0; c<joy[0].num_buttons; c++)
{
     if (joy[0].button[c].b) { /* Boton 'c' presionado*/ }
}

/* Comprobamos uno a uno cada posible movimiento */
if (joy[0].stick[0].axis[0].d1) { /* Izda */ }
if (joy[0].stick[0].axis[0].d2) { /* Dcha */ }
if (joy[0].stick[0].axis[1].d1) { /* Arriba */ }
if (joy[0].stick[0].axis[1].d2) { /* Abajo */ }

[editar] SDL

Y por último, veremos un ejemplo del uso de un joystick con SDL (planteado en C):

  • Incluimos el fichero de cabeceras SLD.h.
#include <SDL.h>
  • Para poder utilizar el joystick desde SDL tenemos que inicializarlo con el flag SDL_INIT_JOYSTICK.
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0)
{
     /* Error */
}
  • Lo primero que necesitamos saber es si hay algún joystick conectado al ordenador, y en su caso, cuántos hay. La siguiente función nos provee esta información: SDL_NumJoysticks( ).
  • Una vez que conocemos el número de joysticks conectados al ordenador, es el momento de utilizarlos. Lo primero que hay que hacer es abrirlos con la función SDL_JoystickOpen( ). La función devuelve un puntero del tipo SDL_Joystick.
SDL_Joystick *joystick;

if (SDL_NumJoysticks() >= 1)
{
     joystick = SDL_JoystickOpen(0);
}
  • El estado de los ejes del joystick lo consultamos con la siguiente función: SDL_JoystickGetAxis( ). Como parámetros le indicamos el joystick y el eje que queremos consultar. Nos devolverá el valor del estado del eje.
joyx = SDL_JoystickGetAxis(joystick, 0);
joyy = SDL_JoystickGetAxis(joystick, 1);
  • Para la consulta de los botones utilizaremos la función SDL_JoystickGetButton( ). Esta función es similar a la anterior, sólo que en vez del eje a consultar, le pasamos el botón a consultar. El valor devuelto puede ser 1, el botón está pulsado y 0 en caso contrario.
if (SDL_JoystickGetButton(joystick, 0))
{
     /* El boton 0 esta pulsado */
}
  • Y para finalizar, SDL dispone de otra función para cerrar el joystick: SDL_JoystickClose( ). Es importante que cerremos el joystick antes de finalizar el programa.
if (SDL_JoystickOpened(0))
{
     SDL_JoystickClose(joystick);
}

[editar] Referencias

  • Libro "Gran libro hardware: Información sobre la totalidad del hardware".
Capítulo: "Referencia de Hardware: Joysticks y Gamepads" páginas de la 279 a la 290 de Klaus Dembowski, Virginia Pérez Moreno, José Luis Cortés, Nuria González. Publicado en 2003 por Marcombo. ISBN:8426713424
  • -
Herramientas personales