La introducción de datos por teclado es probablemente la necesidad más básica de cualquier programa, especialmente en programas para calculadoras.
Existen varias formas de leer entradas de teclado utilizando TIGCC, pero empezaremos aquí con las básicas, y cubriremos otras en futuras lecciones. Las que veremos hoy son la función ngetchx() (para leer pulsaciones de teclado), la función kbhit() (para determinar si se han presionado teclas o no), y una más rápida, pero más avanzada: la función OSdequeue() para leer pulsaciones de teclas directamente desde el búfer de teclado (lo cual resulta mucho más rápido que ngetchx()).
Inicie TIGCC y cree un nuevo proyecto. El proyecto debe ser creado de la forma en que se mostró en la lección uno. Guarde el proyecto en un subdirectorio llamado leccion2 con el nombre "esptecla". El archivo fuente C también debe llamarse "esptecla".
Edite el archivo fuente esptecla.c de forma que se vea como lo que sigue:
Los cambios importantes están en rojo oscuro. Tal como en la lección 1, necesitamos crear un método _main() para que el programa haga algo.
Este programa es bastante simple, excepto por el bucle while en el medio. Si usted ha programado antes en C, esto no debería ser un problema. Si no, intentaré explicarlo. Comenzaremos igual que antes, con un análisis línea a línea del programa.
// variable para pulsación de tecla
int tecla = 0;
Aquí tenemos un nuevo tipo de declaración de variable, una variable entera. Las variables enteras (int = integer o entero en inglés) son utilizadas para almacenar valores numéricos, como los valores de las pulsaciones de teclas, y otros valores similares. Los enteros, sin embargo, no pueden almacenar números en punto flotante. Esta declaración dice "deme un lugar en memoria lo suficientemente grande para un entero y almacene el valor 0 allí". Al igual que en el caso de los punteros a caracter, esta declaración tiene varias partes: 'int', 'tecla', '=' y '0'. El significado de cada una de ellas es casi obvio. 'int' es el tipo de variable, en este caso un entero. 'tecla' es el nombre de la variable entera, con el cual podremos localizarla. '=' es el operador de asignación que nos permite darle valores a nuestras variables. '0' es el valor que le queremos dar a la variable.
Siempre debería darle valores iniciales a sus variables cuando las declare, si es posible (hablaremos de casos donde usted no querrá o no necesitará hacer esto en una lección futura). No solo es una buena práctica de programación (como los comentarios que usted debería usar libremente), sino que C es muy poco específico en cuanto a lo que hace con variables que no tienen un valor inicial. Si usted intenta usar la variable antes de que haya sido inicializada, todo puede pasar. Esto se debe a que C simplemente almacena la variable en un espacio que podría haber sido utilizado previamente. Así que usted podría estar pisando sobre datos inseguros, que pueden llevarlo a bloqueos de la calculadora. El compilador normalmente advierte acerca del posible uso de variables no inicializadas, pero siempre es bueno asegurarse de incializarlas.
// cadenas de caracteres
const char *cad = "Por favor presione ESC\n";
const char *esccad = "¡Usted presionó ESC!\n";
const char *esccad2 = "Le dije que presionara ESC\n";
Las siguientes declaraciones de variables deberían ser obvias, considerando que tuvimos un puntero a caracter en la primera lección. No gastaré mucho tiempo en ellas ahora. Si necesita ayuda con estas declaraciones, estudie con atención la
lección 1.
// borra la pantalla
clrscr();
La función clrscr es muy similar a la función ClrScr que utilizamos en la primera lección (note el cambio en las mayúsculas; NO son la misma función). clrscr es empleada junto con otra función llamada printf que estaremos utilizando muy pronto. clrscr ayuda a printf a seguirle la pista a la posición del cursor, de forma que printf sepa donde desplegar las cadenas de caracteres. Usted observará que no tuvimos necesidad de decirle a printf dónde imprimir la cadena, contrario a la función DrawStr. Volveremos a estas cosas luego, pero tenga en mente que si usted utiliza printf, debería utilizar clrscr para borrar la pantalla; de otro modo, use ClrScr.
// despliega la cadena
printf(cad);
La función printf es otra función del sistema operativo de la calculadora almacenada en la FlashROM de la cual podemos aprovecharnos. Es otra función, similar a DrawStr(), que podemos utilizar para imprimir cadenas en pantalla. Sin embargo, printf tiene algunas propiedades muy especiales que podemos aprovechar. No necesitamos especificar coordenadas en pantalla. Esta función comenzará a imprimir en la esquina superior izquierda y bajará hasta la parte inferior de la pantalla. Cuando no haya más espacio disponible en pantalla, printf desplazará el texto por nosotros de modo que podamos ver las nuevas cosas desplegadas abajo, y lo que estaba en la parte superior desaparecerá. Hay más cosas que podemos hacer con printf que veremos en una lección posterior. Por ahora, usted puede pensar en la función printf como una una función más útil que DrawStr.
Hay otro componente de las cadenas de caracteres que puede ser poco familiar. La pareja de caracteres '\n' es llamada una secuencia de escape. Las secuencias de escape son utilizadas en cadenas con formato para agregar cieros caracteres especiales a una cadena. La secuencia \n significa 'nueva línea'. Así, cuando la función printf() calcula la longitud de la cadena, encuentra un caracter de nueva línea, y cualquier texto que printf comience a imprimir después aparecerá en la siguiente línea. Hay muchas secuencias de escape como esta que discutiremos en el futuro.
// espera que sea presionada la tecla ESC
while ((tecla = ngetchx()) != KEY_ESC) {
printf(esccad2);
}
Este es el corazón del programa, y obviamente la parte más compleja. La primera sentencia es el comienzo de un bucle while, una de las instrucciones de control en C. Mediante el bucle while, podemos ejecutar ciertos comandos muchas veces hasta que obtengamos el resultado que queremos. El formato de un bucle while es while (condición) {haga halgo}, lo que significa: mientras la condición sea verdadera, ejecute estas instrucciones.
En este caso, nuestra condición es ligeramente complicada. Primero, tenemos una sentencia de asignación incluida dentro de la condición para hacerla más eficiente. Podemos dividir el bucle while en estos sub-componentes: 'while', '(tecla = ngetchx())', '!=', y 'KEY_ESC'. while es el identificador que le dice a C que queremos un bucle while.
El lenguaje C, aún siendo muy poderoso para procesar sentencias, no puede procesar múltiples operadores de asignación sin agruparlos. Así, la sentencia (tecla = ngetchx()) es en realidad el lado izquierdo de una sentencia (lvalue en inglés). Este 'lvalue' contiene una sentencia en sí mismo, la cual es ejecutada primero gracias al agrupamiento. Siempre tomamos las sentencias agrupadas más internamente primero. De esta forma, la sentencia contenida en el 'lvalue' de nuestra condición es 'tecla = ngetchx()'. Esto significa: asígnele el valor retornado por la función ngetchx() a la variable llamada 'tecla' (recuerde que definimos tecla en la sección de declaración de variables del método _main()). Así pues, como nuestra sentencia más interna se ejecuta primero, sabemos que la sentencia (tecla = ngetchx()) será evaluada primero cuando el bucle while evalúe si la condición es verdadera. Entonces, la primera cosa que el bucle while debe hacer es ejecutar esa sentencia. Luego podemos proceder con la verificación de la condición.
En C, '!=' significa 'no es igual a', y es uno de los operadores condicionales en C. Existen otros, pero los cubriremos en lecciones futuras. Entonces, al procesar la condición del bucle while, queremos saber si el lado izquierdo (lvalue) no es igual al lado derecho (rvalue). Si esta sentencia es verdadera, entonces se ejecuta el cuerpo del bucle while (las sentencias en el interior de las llaves { } del bucle while). Si no, hemos terminado con este bucle.
La última parte de la condición es el lado derecho. 'KEY_ESC' es una definición de TIGCC que contiene el código de tecla de la tecla ESC. Está definida en el archivo de cabecera kbd.h, el cual es incluido automáticamente cuando incluímos tigcclib.h.
Entonces, ¿qué dice nuestra sentencia condicional? Simplemente esto: ejecute la función ngetchx() y asigne su valor a la variable tecla. Si el valor que hemos almacenado en tecla no es igual al valor de la tecla ESC, entonces ejecute este bucle while. Así, el programa se mantendrá ejecutando el cuerpo del bucle hasta que el usuario presione la tecla ESC.
printf(esccad2);
Esta sentencia es similar a la otra función de despliegue mostrada más arriba, con la diferencia que esta imprime la cadena apuntada por el puntero a caracter esccad2.
// muestra la cadena final
printf(esccad);
Esta sentencia es igual a las otras funciones de despliegue vistas arriba, con la diferencia que esta imprima la cadena apuntada por el puntero a caracter esccad.
// espera una entrada del usuario antes de salir del programa
ngetchx();
Ahora sólo necesitamos esperar a que el usuario presione una tecla antes de salir de forma que pueda ver lo que hicimos. Usted ya debería estar familiarizado con la función ngetchx(), así que no lo subestimaré explicándosela. Si necesita ayuda, consulte la
lección 1.
La función ngetchx() es muy poderosa, pero tiene serios inconvenientes. El primero, y quizá el principal para la mayoría de programadores, es que esta función espera a que el usuario presione una tecla antes de continuar (a menos que una tecla ya haya sido presionada, en cuyo caso simplemente la captura). Este es un gran problema para la programación de juegos, donde usted necesita hacer otras cosas además de chequear pulsaciones de teclas. Para manejar estas situaciones, ngetchx() por sí misma no hará lo que necesitamos. Así que exploremos algunos métodos alternos para trabajar con entrada de datos desde el teclado.