:: Program till the end ::

Publicado: 21:25 04/07/2007 · Etiquetas: , , , , , , , · Categorías: Informática
Dado que me lo pidieron hace tiempo en la entrada sobre mi particular versión del juego de Snake (no confundir con Metal Gear ), que hice tras mi primer año de carrera, pondré un sencillo tutorial para entenderse un poco con la gestión de las teclas en un programa C simple. No es nada complejo ni es la mejor forma de hacer las cosas, pero para quien está empezando o tenga dudas de cómo hacerlo, puede ser útil. Eso sí, debo aclarar que los ejemplos que vamos a ver, son para MS-DOS / Windows. En Linux alguna cosa puede ser diferente.

El punto de partida es: estamos haciendo un programa o juego sencillo con C/C++, y queremos capturar teclas que el usuario pulse. En principio uno pensaría en scanf o cin>>, que sirven para entrada de datos, pero no sirven, dado que éstos, esperan que se escriba algún dato para luego pulsar Enter. Aquí lo que nos interesa es que el programa sepa de inmediato que se ha pulsado una tecla (como puede ser una tecla de dirección), e identificar cuál.

Para casos como este, hay que tener el código ASCII a mano:


Pincha sobre la imagen para verla más grande

Recordad que el código ASCII tiene algunas variantes, por lo que no todos los códigos ASCII que encontréis serán iguales. Pero para usar unos pocos caracteres no suele dar problemas. Los 32 primeros caracteres son no imprimibles... en según qué casos. Se usan como caracteres de control (por ejemplo, salto de línea), aunque también tienen dibujitos asociados y dependiendo del lugar donde se usen, se pintará el dibujo o se realizará la acción asociada.

Otra particularidad es que hay teclas que comparten el código... como es el caso de las teclas de dirección. Éstas no están señaladas en ninguna tabla ASCII que haya visto. Hay que averiguar cómo referirse a estas teclas (para las teclas imprimibles, como la letra a, basta con usar la propia letra con comillas simples: 'a').

Trabajando con una buena librería o herramienta de gestión de eventos, no sería necesario preocuparse por el código ASCII, porque en esos casos normalmente toda tecla o carácter tiene su correspondiente etiqueta asociada (por ejemplo, KEY_LEFT para referirse a la tecla de dirección izquierda). Suponiendo que no es así, que estamos con C/C++ "a pelo" y sin ningún tipo de ayuda como la comentada, tendremos que definir nosotros mismos esas etiquetas. Pasamos a la acción.

1- Cómo averiguar empíricamente el código de una tecla

Para ello podemos hacer un programa sencillo que nos permita averiguarlo:

------------------------------------------------

#include <conio.h> //Para getch
#include <stdio.h> //Para printf

int main(){
char tecla;

printf("Pulsa la tecla de la que quieres conocer su codigo: ");
tecla = getch();

printf("\nEl codigo de la tecla pulsada es: %d\n",tecla);

return 0;
}

------------------------------------------------

Explicación: getch captura una tecla y la devuelve, pudiendo almacenar el código en una variable, como hacemos en este programa. Después, interpretamos como una variable entera a tecla usando el código %d para imprimirla, de modo que vemos su código numérico que es lo que nos interesa.

A continuación lo compilamos. Si el archivo es ascii.c, podemos hacer:

gcc -Wall ascii.c -o ascii.exe

si tenemos gcc, o del modo que sea si usamos otra herramienta.

Cuando lo ejecutemos, y pulsemos por ejemplo la tecla de dirección izquierda, es posible que obtengamos esta salida:

Pulsa la tecla de la que quieres conocer su codigo:
El codigo de la tecla pulsada es: 0


Eso NO quiere decir que el código de la tecla sea 0. El problema es que getch coge caracteres del buffer de teclado y a veces (particularmente cuando la tecla pulsada es una de dirección), se cuela alguno que no debe, por decirlo de forma más o menos sencilla . Pero si lo volvemos a ejecutar obtenemos la salida correcta. Tras algunas ejecuciones, vemos que los códigos son como sigue:

- Tecla de dirección arriba: 72
- Tecla de dirección izquierda: 75
- Tecla de dirección derecha: 77
- Tecla de dirección abajo: 80

Con lo que en el programa que estamos haciendo, podemos añadir al principio estas líneas:

#define KEY_UP 72
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_DOWN 80

Y ya podemos usar estas etiquetas en lugar de los códigos ASCII en el resto del programa.

2- Captura de teclas en programas dinámicos

Ya hemos visto cómo capturar una tecla en un caso en el que el programa espera a que se pulse alguna, pero ¿y si queremos que el programa esté procesando o haciendo cualquier actividad aunque no se pulsen teclas? Por ejemplo en el juego de la serpiente: las serpientes se mueven aunque ningún usuario pulse ninguna tecla. Necesitamos algo que nos diga cuándo se pulsa una tecla. No se puede ejecutar getch() salvo que sepamos que el usuario ha pulsado una tecla y por lo tanto el programa no va a quedarse bloqueado. La solución (en MS-DOS / Windows) es la función kbhit(), también incluida en conio.h. Esta función se usa del siguiente modo:

------------------------------------------------

...

#define KEY_ESC 27
...

tecla = KEY_RIGHT; //Inicializamos

do{

...
//Procesamos
...

if(kbhit())
tecla = getch();
} while(tecla != KEY_ESC);

------------------------------------------------

Explicación: se suponen definidas las etiquetas para las teclas. En este código, se inicializa la tecla a "derecha", como si el usuario hubiese pulsado ya "derecha". A continuación itera en función de esa variable y posiblemente otros datos hasta que el usuario pulse Esc (el código de la tecla Esc es 27, lo podéis comprobar con el programa que vimos antes). La función kbhit devuelve true si el usuario ha pulsado una tecla, o false en caso contrario. Lo que quiere decir, que el programa seguirá iterando sin ejecutar getch hasta que el usuario pulse alguna tecla, que será capturada de inmediato (cuando termine la iteración en curso).

Debo indicar que kbhit en según qué implementaciones (compilador usado) puede no funcionar del todo bien y, por ejemplo, provocar un ligero parón, haciendo que se ralentice el programa por un instante en el momento en que el usuario ha pulsado una tecla. Como digo, depende del compilador usado.

En cualquier caso, esta forma de implementar no es la más elegante ni la más recomendable. Por ejemplo, no funcionará bien si se pulsan varias teclas a la vez, o se mantiene pulsada alguna. Es más recomendable disponer de algún mecanismo de gestión de eventos, de forma que el programa trabaje "a su bola" y cuando se pulse alguna tecla, simplemente se le avise para que atienda la pulsación, sin tener que hacer continuas comprobaciones. Pero en casos sencillos (como el juego que puse aquí), puede valer.

Quien tenga alguna duda sobre lo expuesto o cualquier otra cosa, que me lo haga saber con un comentario .

28 comentarios :: Enlace permanente
Compartir
FacebookCompartir
TuentiCompartir en Tuenti
MenéameMenéame Enviar
Comentarios: (del primero al último)
Anónimo
19:37 10/07/2007
muchas gracias por ofrecer esta informacion tan valiosa.
23:36 10/07/2007
Muy buena guía para manejar teclas en "tiempo real", google te lo recompensa con hoygan y todo.
Anónimo
20:47 03/08/2007
no se entiende
12:14 04/08/2007
taty: especifica lo que no entiendes y tal vez te pueda ayudar ;).
Anónimo
19:46 04/08/2007
gracias, andaba buscando algo asi desde hace mucho , una duda solo , a  mi las teclas de direccion me salen con el mismo codigo: 27  xq?
01:15 05/08/2007
polly: así de pronto, no sé a qué puede deberse que te lea las teclas de dirección como ESC (27). Si puedes, ponme el código con el que lees las teclas (que me imagino que no será idéntico a lo que hay aquí) y le echamos un vistazo ;)
Anónimo
04:01 21/08/2007
gracias por esta informacion!!--yo estoy utilizando pascal aun, tengo que hacer un ultimo proyecto para terminar de verlo y en realidad me ayudo un moonnton!!-tambien tengo que hacer un juego pero vamos a ver como me va-muchisimas gracias---Que Dios te bendiga!!--
Anónimo
23:15 31/08/2007
hola!!! apenas estoy aprendiendo a programar en c:pero no le entiendo nada al profesor, y me deja una tarea espero me puedas ayudar para que sirve gets(), en un programa por fa necesito la ayuda de alguien espero me la puedas brindar!!!!
te lo agradeceria !!!
12:14 01/09/2007
gets() sirve para pedir al usuario una cadena de texto. Captura todo lo que el usuario escriba hasta que pulse Enter. Ejemplo:

char cadena[50];

printf("Escriba lo que le dé la gana: ");
gets(cadena);

Un problema de gets, bastante importante, es que no tienen ningún cuidado con el tamaño de la cadena. Es decir, aquí, que he creado una cadena de caracteres de tamaño 50, si el usuario escribe más de 50 caracteres, sobrepasará su tamaño y se "pisará" memoria no reservada, lo cual puede dar lugar a un error como una violación de segmento. De modo, que si usas gets, le tienes que pasar vectores de caracteres con un tamaño tal que estés seguro/a de que el usuario no va a escribir tanto (pero sin pasarse, hay que ahorrar memoria ^^).

Espero haberte ayudado. Te lo escribo también al correo.

Saludos.
Anónimo
19:34 21/09/2007
gracias por tu informacion es esebcial
Anónimo
14:09 07/10/2007
oye

pero como definimos la variable tecla?
15:36 07/10/2007
jokep: supongo que te refieres a la declaración de la variable. En el ejemplo lo he puesto:

char tecla; //Declaración de la variable tecla

...

tecla = getch();

En realidad, como un char es un byte (un número como otro cualquiera, pero de ese tamaño), se podría declarar como un short o int/long, que siguen siendo números pero con mayor capacidad, por lo que pueden albergar al carácter devuelto por getch(). Pero sería un tanto absurdo utilizar más espacio ;).
Anónimo
22:58 07/11/2007
BUENA INFORMACION HE ME INTERESARIA SABER MAS SOBRE PROGRAMACION
01:38 08/11/2007
CIOM: lo ideal sería distinguir entre "aprender un lenguaje" y "aprender programación", ya que con lo segundo aprendes a desenvolverte en el aprendizaje de nuevos lenguajes fácilmente. La distinción está en que con "aprender programación" me refiero a aprender metodología, paradigmas, etc., y acostumbrarse a aprender nuevos lenguajes con facilidad. Lo que ocurre es que este proceso suele ir ligado al aprendizaje de un lenguaje en particular, con el que uno va cogiendo soltura.

Si quieres aprender C/C++, esta página:

http://c.conclase.net/

tiene un curso muy completo. Pero, se centra en el lenguaje. Para aprender metodología y paradigmas, hay que trabajar más porque es algo más difuso... te podría recomendar algún libro, aunque ya dependerá de tus preferencias y conocimientos, y lo que estés haciendo. Si quieres aprender programación en serio, lo ideal es una ingeniería informática y la vocación correspondiente. Si no, ingeniería técnica en informática, y si no, existen ciclos formativos... al menos en España, no sé si eres de España. En cualquier caso, aprender a programar bien, requiere ganas y tiempo, leer libros y practicar mucho. Si tienes interés en que te aclare algo más o te recomiende algo, coméntamelo.

Algún día tal vez ponga otro tutorial, pero los tutoriales que haga serán de cosas muy concretas, más que sobre programación en C por ejemplo.

Saludos.
Anónimo
03:49 10/11/2007
Hola colegas muy buen curso yo necesito otra forma de detectar teclas algo parecido al KBHIT para poder designarle una tecla en ves de que salga contodas solo con una porfabor se los agradeceria
17:55 10/11/2007
Charly: si lo que quieres es que tu programa únicamente reaccione a una tecla en concreto, y estás haciendo un programa con kbhit() y getch(), se puede solucionar fácilmente:

char tecla;

...

while((tecla = getch()) != TECLA_ESPERADA);

En este caso, el programa se queda completamente quieto, bloqueado, y no reacciona mientras no se pulse una tecla en particular. Si lo que quieres es que el programa continúe trabajando pero reaccione a la pulsación de una tecla determinada, no es más que un caso particular de lo que puse en la entrada:

char tecla = '\0';

...

while(condicion){

if(kbhit())
  tecla = getch();

...

if(tecla == TECLA_ESPERADA)
 hacerAlgo;

...

}

En este caso, el programa itera mientras se cumpla "condicion", y en cada iteración comprueba si se ha pulsado alguna tecla. Si la tecla pulsada es la esperada, entonces realiza la acción que sea. Aquí ha sido necesario inicializar la variable tecla, para evitar que tenga cualquier valor mientras el usuario no pulse ninguna tecla. La inicializo al carácter nulo '\0', que es igual que poner 0, el primer carácter ASCII.

Espero que esto te sirva.
Anónimo
04:06 12/11/2007
Muchisimas gracias... me has salvado..stoy iniciando la carrera y me pusieron a hacer un juego parecido a snake, de verdad ke me ayudo mucho!!!!!!!!!!!!!!!!!!!
Anónimo
09:34 05/01/2008
muy buen aporte, gracias!!!
Anónimo
20:17 10/01/2008
me ha servido mucho este tutorial me gustaria que me pudieran enseñár un poco mas de como crear juegos en c++ muchas grasias  ahi les dejo mi correo
Anónimo
01:49 06/02/2008
hola esta muy buena tu explicacion, me podrias explicar o dar un link para aprender a detectar 2 o tres teclas pulsadas al mismo tiempo, es para un proyecto de control de un auto via radio control manejado por lpt1,necesito oprimir KEY_UP y KEY_LEFT al mismo tiempo y que si oprimo esas teclas sacar por lpt1 un codigo de 8 bits desde ya muchas gracias
13:24 06/02/2008
fabian Juarez: para eso lo ideal sería que usases un "framework" o librería de gestión de ventanas y eventos que te facilite la labor, como puede ser Qt (multiplataforma), MFC (para Windows), FOX (multiplataforma), etc. También se puede hacer con lenguaje ensamblador, pero ahí no te puedo ayudar.
Anónimo
15:14 27/03/2008
HOLA, QUE FUNCION TIENE EL GETS EN "C"?
21:33 27/03/2008
Permitir al usuario introducir una cadena de texto desde teclado, en un terminal en pantalla. Es una función que no se aconseja usar pues no comprueba el límite de la cadena pasada como argumento, por lo que si el usuario escribe demasiado, pisaría memoria no reservada y se puede liar la gorda.
Anónimo
06:50 03/04/2008
Hola. Quiero saber que puedo hacer para realizar un determinado proceso hasta que una tecla en especifico sea pulsada. Esto no se puede con while(!kbhit()) debido a que dicha función no regresa el valor de la tecla presionada. Lo ocupo para hacer un juego de la viborita =). Esto sería para que la viborita camine hasta que una tecla sea pulsada, entonces la viborita cambiara de dirección. También quiero saber si es posible conocer el tiempo que es presionada una tecla y que función puedo usar. Saludos!
12:58 03/04/2008
MasterCode: precisamente eso hice en mi versión del juego de la serpiente. kbhit() no te dice el valor de la tecla presionada, pero te avisa de cuando se ha presionado una tecla, que es lo importante, y entonces capturas la tecla con getch(). Es decir, en el juego de la serpiente, esta tiene que estar andando continuamente y reaccionar a las pulsaciones de teclas. Para ello tendrías algo así como:
char tecla;
while(!<condicion_de_fin>){
 <hacer_algo>

if(kbhit()){
 tecla = getch();
 <comprobar_valor_tecla_y_procesar>
}

<hacer_algo_mas>

}

Para lo del tiempo que una tecla es presionada, lo que necesitas es saber, además de cuándo es presionada, cuándo es soltada. Desconozco si hay alguna función para ello en las librerías básicas de C, ya sean estándar o para alguna plataforma específica como es el caso de kbhit(). Tal vez conio.h tenga alguna, investiga por ahí.

En realidad, para tener verdadero control de este tipo de cosas, lo ideal es una aplicación dirigida por eventos. Pero para ello necesitas usar una librería o entorno de gestión de ventanas y eventos (como MFC, Qt, wxWidgets...), y la cosa se complica bastante si no sabes usar ninguna y quieres hacer el juego rápidamente, aunque los resultados siempre podrán ser mejores.
Anónimo
00:47 28/05/2008
HOYGAN, VUEM HAPORTE
Anónimo
19:40 02/06/2008
Hola, quiero hacerlo pero linux no reconoce la funcion getch(). ¿Saben alguna solución?
15:32 03/06/2008
En Linux debe haber una función equivalente, pero la desconozco. En realidad, como ya dije en el tutorial, esto es solamente para entretenerse o aprender cosas básicas, porque para programas más o menos en serio, hay que usar otro tipo de herramientas, como Qt.
Participa con tu Comentario:

Este blog no permite comentarios.

Blog de maxter2001
I program till the end, for my purposes. What about you? [Blog de OK-River (maxter2001 en Vandal)]

Posts destacados por el autor:
· "Hola, mundo!" con Qt
· Odisea en busca de una PS3 de 60 GB, finalizada
· [Proyecto Fin de Carrera] Vídeo demostración + Capturas + Info
· Ingeniería Informática acabada
· [Proyecto Fin de Carrera] Capturas e info
· Programación: Tutorial para manejo de teclas
· The Legend Of Zelda: Twilight Princess terminado: impresiones/análisis
· Final Fantasy X - To Zanarkand (directo)
· Dichosas comparaciones atenuantes
· Juego para descargar: La Bicha 2.0
· Metal Gear Online "impresionado"
· Estreno



Vídeos:
· Música orquestada
· Variados
· Música variada
· El Informal
· Juegos
· Humoristas españoles


Últimas actualizaciones de blogs amigos:
hace una semana en
hace semanas en

Blogs amigos:
alw
ArKiTo
Arxel
Boddhai
Clone
ComIkari
Cornell
De-mon
delojo
EASMO
erizoazul
Ferr
GeRoxx
Granlutz
HWY2HELL
Isnard
Jimmytrius
Kanevsky
Kiriyama
Modo_7
nach
Naruto
NeoYoshimitsu
NoPLo
Resident Hill
RojoRedRouge
Shino-Kun
Sonny Chiba
Sr.A
suzumiya haruhi
vacajinjo
xispax_
Zeroshcr
ZZGRST
_-Sheik-_


Categorías:
Chorradillas
Hablar con propiedad no cuesta un puto duro
Informática
Manga/Anime/Dorama
Música
Personal
Regalos pal hocico
Tutoriales
Varios
Videojuegos


Archivo:
Octubre 2009
Septiembre 2009
Enero 2009
Septiembre 2008
Agosto 2008
Junio 2008
Mayo 2008
Abril 2008
Marzo 2008
Febrero 2008
Enero 2008
Diciembre 2007
Noviembre 2007
Octubre 2007
Septiembre 2007
Agosto 2007
Julio 2007
Junio 2007
Mayo 2007
Abril 2007
Marzo 2007
Febrero 2007
Enero 2007
Diciembre 2006
Noviembre 2006
Octubre 2006


Vandal Online:
Portada
Blogs
Foro

Blogs en Vandal · Contacto · Denunciar Contenido