Leer una sola tecla de la consola puede parecer un hecho trivial. En DOS,
en Windows, se usa simplemente la función getch, o getche (funciones del
viejo "conio.h"). Sin embargo en Linux (en Unix en general) resulta no
serlo. El driver de la terminal acepta la entrada de a una línea entera por
vez, y si ejecutamos read(0, buf, 1)
, ese 1 no hace que
read termine al pulsarse una tecla. Esto viene de la época en que
las computadoras se usaban desde terminales unidas a la computadora por una
conexión no muy rápida, entonces era un desperdicio enviar cada tecla
pulsada.
Para lograr que la terminal envíe una tecla a la vez hay que cofigurar la terminal adecuadamente, esto se logra con funciones de termios(2). En concreto: es necesario desactivar el flag ICANON. Información sobre este tipo de flags puede encontrarse en la manpage de stty.
Ejemplo:
#include <stdio.h> #include <termios.h> #include <unistd.h> int main(int argc, char **argv) { struct termios t; int c; /* Obtenemos la configuración actual de la terminal */ tcgetattr(0, &t); /* Le apagamos el bit "ICANON" */ t.c_lflag &= ~ICANON; /* Establecemos la nueva configuración de la terminal */ tcsetattr(0, TCSANOW, &t); printf("Una tecla..: "); fflush(stdout); c = getchar(); printf("\n%d\n", c); /* ¡Ojo! ¡Si no dejamos todo como estaba le dejamos * al usuario la terminal rota! */ t.c_lflag |= ICANON; tcsetattr(0, TCSANOW, &t); return 0; }
Un detalle ya que estamos. Note que después del printf llamo a fflush. Esto es porque cuando la salida está conectada a una terminal (y no a un pipe) muchas funciones sacan la salida de a líneas. Entonces necesitamos fflush para que esto no sea así.
También puede ser necesario evitar que Linux muestre la tecla pulsada
automáticamente. Esto de mostrar la tecla pulsada se llama eco.
Para desconectar el eco en la terminal se procede de manera similar a lo ya
dicho. La diferencia es sólo que el flag a apagar no es ICANON
si no ECHO
. Así:
... tcgetattr(0, &t); t.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &t); ...
Si se quieren hacer cosas más complicadas es conveniente ver qué bibliotecas ya existen. Por ejemplo, para hacer interfaces de linea de comando conviene investigar la biblioteca readline. Esta biblioteca soporta historial de comandos, edición, completar la línea inteligentemente cuando se pulse tab, etc. Readline viene con todas las distribuciones.
Si lo que se quiere es hacer una aplicación completamente de consola, a pantalla completa, entonces lo que se necesita es curses. Este paquete viene con todas las distribuciones, ver las páginas de manual (man ncurses). Empecé una introducción a cómo pueden hacerse aplicaciones de consola. Para los que vienen del mundo Windows/DOS: Curses sería un reemplazo completo de todas las funciones que se encuentran en conio.h, pero para Unix.
Volver al índice.