Aula Macedonia


Curso de Programación Multimedia Bajo DOS


Artículo realizado por
José Antonio Suárez.





Capítulo 2.
Programación del ratón (I).

1.- El Manejador del Ratón


Para comunicarse con el ratón, tenemos que emplear la interrupción 33h. El número de la función deseada se pasa con el registro AX y el resto de los registros se usan para pasar o recibir datos.

mov ax,0
int 0x33

Esta sería la forma de llamar a la función 0 del ratón.

Algunas funciones del interfaz del ratón son las que se encuentran en el siguiente cuadro:
 
 

Función Uso
00h Resetea el driver del ratón.
01h Dibuja el cursor del ratón en la pantalla.
02h Oculta el cursor del ratón.
03h Devuelve la posición del cursor y el estado de sus botones.
07h Define la zona horizontal de movimiento para el cursor.
08h Define la zona vertical de movimiento para el cursor.
09h Define el cursor del ratón para los modos gráficos.
0Ah Define el cursor del ratón para los modos de texto.
0Fh Fija la velocidad de desplazamiento del cursor.
 

Tras esta breve exposición del ratón a nivel hardware, comenzamos con el análisis de las rutinas que lo manejan.

La librería que se encarga del ratón se llama "RATON.C", y sus cabeceras están en "RATON.H", ambos ficheros incluidos íntegramente al final de esta sección.

Empecemos por cambiar el cursor del ratón, tarea sencilla para empezar. Sólo hay que dibujar un mapa de bits con la forma que queramos, dibujar también su negativo (máscara) y luego traducir esas líneas de binario a hexadecimal. En el fichero de cabeceras (RATON.H) podemos encontrar la siguiente declaración:

int cursor1 [32+32] = { // Flecha

0x3FFF, 0x1FFF, 0x0FFF, 0x07FF, 0x03FF, 0x01FF, 0x00FF, 0x007F, 0x003F, 0x001F, 0x000F, 0x0007,

0x0007, 0xF81F, 0xFC0F, 0xFE0F,

// Máscara

0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7F00, 0x7F80, 0x7FC0, 0x7FE0, 0x7FF0,

0x0780, 0x03C0, 0x01E0, 0x0000 };

Y usando el siguiente procedimiento hacemos efectivo el cambio:

void CambiaPunteroRaton(void)
{
    long dir;
    int dir2,dir3;
 
    dir=(long)cursor1; dir2=(int)dir; dir3=(int)(dir>>16);
    asm{
            mov ax,0x9
            mov bx,0
            mov cx,0
            mov dx,dir2
            mov es,dir3
            int 0x33
    }
}

Nótese el uso del Ensamblador dentro del código C, es decir, "Ensamblador Inmerso".

Como se ve, se ha llamado a la interrupción 33h, al servicio 9h.

Otra función y la primera que debemos ejecutar cuando queremos utilizar el ratón es la detección del propio ratón, ya que si éste no está, no podremos usarlo por mucho que programemos los eventos.

El procedimiento que lo hace es el siguiente:

 

int DetectarRaton(void)
{
    int w;
 
    asm{
            mov ax,0
            mov bx,0x2
            int 0x33
            mov w,ax
    }
    return(w);
}

Si DetectarRaton devuelve -1, es que el ratón está presente.

Una vez detectado la presencia del driver del ratón, hay que definir los límites (en píxels) por los que se podrá mover.

void EstablecerLimRaton(int xi,int yi,int xf,int yf)
{
    asm{
            mov ax,7
            mov cx,xi
            mov dx,xf
            int 0x33
            mov ax,8
            mov cx,yi
            mov dx,yf
            int 0x33
    }
}

De esta forma, independientemente de la resolución de la pantalla, podemos hacer que el ratón sólo se pueda mover por una zona determinada, por un rectángulo que especifican las coordenadas del procedimiento. Esto es útil cuando queremos centrar la atención del usuario sobre una zona determinada, no permitiéndole hacer otra cosa hasta que haya seleccionado algo indispensable para continuar.

Una vez detectado el ratón y establecido su ámbito de movimiento, hay que mostrar la flecha.

void MostrarRaton(void);

Algo que hay que tener en cuenta es que cuando se vaya a hacer un cambio en la pantalla tales como escribir un texto o una línea, hay que ocultar el ratón y volverlo a mostrar cuando acabemos, ya que si nó, aparecerán incongruencias entre la máscara del ratón y la memoria de vídeo, provocando la aparición de rectángulos extraños que estropearán lo que veamos. Esto es debido a que el driver del ratón continuamente usa una pequeña zona de memoria para almacenar lo que había "debajo" del cursor antes de que alcanzase la posición en que ahora se encuentra, de forma que al volverse a desplazar a otra posición se "restaura" lo que el cursor estaba "pisando". Por esto, si hacemos un cambio en una zona en la que se encuentra el cursor, al moverlo restaurará la "antigua" zona que antes estaba, y no la que ahora debería estar debido al cambio.

Para ocultar el ratón usaremos:

void OcultarRaton(void);

Y jugando con estos dos últimos procedimientos, escondemos y mostramos el ratón cuando se vayan a producir los cambios en la pantalla.

Aparte de esto, dos de los últimos procedimientos que vamos a presentar aquí (aunque hay más pero son secundarios), son los que se encargan de hacer esperar a la CPU hasta que se haya pulsado un botón (en este caso sólo se reconocen las pulsaciones de los botones izquierdo y derecho. Si se quisiera observar también el del botón central cuando el ratón disponga de tres, tendría que añadirse una tercera condición al "while": (*bot!=4)):

void EsperarPulsadoBoton(int *bot)
{
    do { PulsadoBoton(bot); }
    while ((*bot!=1)&&(*bot!=2));
}

y de hacerla esperar también hasta que se haya soltado ese botón. Los procedimientos son:

void EsperarSoltadoBoton(int bot)
{
    int *boton;
 
    do { PulsadoBoton(boton); }
    while (*boton==bot);
}

Ambos procedimientos llaman al procedimiento que interactúa directamente con el ratón:

void PulsadoBoton(int *bot)
{
    int boton;
 
    asm{
            mov ax,3
            int 0x33
            mov boton,bx
    }
    // Si vale 1 es el izquierdo, si vale 2 es el derecho,si vale 4 el central
    *bot=(int)boton;
}

Y por último, el procedimiento que se encarga de leer las coordenadas:

void LeerPosRaton(int *x,int *y)
{
    int xx,yy;

    asm{
            mov ax,3
            int 0x33
            mov xx,cx
            mov yy,dx
    }
    *x=xx;
    *y=yy;
}

Con esto, la exposición de los procedimientos que se encargan del ratón termina. Por último, usando estos procedimientos podremos saber cuándo el cursor se pulsa sobre una zona que nosotros hemos decidido que sea "sensible", esto es, un botón, un menú, un submenú, etc.




AULA MACEDONIA
a
MACEDONIA Magazine