<?xml version="1.0" encoding="utf-8"?><!DOCTYPE article  PUBLIC '-//OASIS//DTD DocBook XML V4.4//EN'  'http://www.docbook.org/xml/4.4/docbookx.dtd'><article><articleinfo><title>WebHome/TrabajosPracticos/EcoNoEco</title><revhistory><revision><revnumber>9</revnumber><date>2019-09-10 17:53:35</date><authorinitials>GuillermoSteiner</authorinitials><revremark>Se cambia nombre desde &quot;WebHome/TrabajosPracticos/Tutoriales/EcoNoEco&quot;</revremark></revision><revision><revnumber>8</revnumber><date>2019-09-10 17:47:05</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>7</revnumber><date>2019-09-10 17:45:56</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>6</revnumber><date>2019-09-10 17:40:11</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>5</revnumber><date>2019-09-10 17:39:10</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>4</revnumber><date>2019-09-10 17:13:09</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>3</revnumber><date>2019-09-09 21:13:53</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>2</revnumber><date>2019-09-09 21:12:01</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>1</revnumber><date>2019-09-09 21:10:04</date><authorinitials>GuillermoSteiner</authorinitials></revision></revhistory></articleinfo><section><title>Programación de la terminal de Linux</title><section><title>Modo canónico vs. no-canónico</title><para>Por defecto, la entrada por teclado desde la terminal no se envía al programa hasta que el usuario presiona la tecla Enter. En la mayoría de los casos, esto es un beneficio dado que permite al usuario corregir errores de escritura usando la tecla Backspace, y solo cuando se está satisfecho con lo escrito en pantalla, se presiona Enter para enviar dicha cadena de texto al programa. </para><para>Este comportamiento se llama modo canónico o estándar. Toda la entrada se procesa en términos de líneas. Hasta que se complete una línea de entrada (generalmente cuando el usuario presiona Enter), la interfaz del terminal gestiona todas las pulsaciones de teclas, incluido el Backspace, y la aplicación no puede leer ningún carácter. El comportamiento contrario es el modo no canónico, donde la aplicación tiene un control mucho mayor sobre el procesamiento de los caracteres de entrada.  </para><para>Entre otras cosas, el controlador de la terminal de Linux ayuda al traducir caracteres de interrupción a señales (por ejemplo, deteniendo el programa cuando presiona Ctrl-C) y procesa de forma automática las teclas Backspace y Delete, para no tener que volver a implementar su comportamiento en cada programa que se escribe. </para></section><section><title>Estructura termios</title><para>La configuración de la terminal se realiza mediante la estructura <emphasis role="strong">termios</emphasis> (archivo de cabecera <emphasis role="strong">termios.h</emphasis>): </para><programlisting format="linespecific" language="highlight" linenumbering="numbered" startinglinenumber="1"><token><![CDATA[struct]]></token><![CDATA[ ]]><methodname><![CDATA[termios]]></methodname>
<![CDATA[  {]]>
<![CDATA[    ]]><methodname><![CDATA[tcflag_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_iflag]]></methodname><![CDATA[;           ]]><lineannotation><![CDATA[/* input mode flags */]]></lineannotation>
<![CDATA[    ]]><methodname><![CDATA[tcflag_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_oflag]]></methodname><![CDATA[;           ]]><lineannotation><![CDATA[/* output mode flags */]]></lineannotation>
<![CDATA[    ]]><methodname><![CDATA[tcflag_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_cflag]]></methodname><![CDATA[;           ]]><lineannotation><![CDATA[/* control mode flags */]]></lineannotation>
<![CDATA[    ]]><methodname><![CDATA[tcflag_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_lflag]]></methodname><![CDATA[;           ]]><lineannotation><![CDATA[/* local mode flags */]]></lineannotation>
<![CDATA[    ]]><methodname><![CDATA[cc_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_line]]></methodname><![CDATA[;                ]]><lineannotation><![CDATA[/* line discipline */]]></lineannotation>
<![CDATA[    ]]><methodname><![CDATA[cc_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_cc]]></methodname><![CDATA[[]]><methodname><![CDATA[NCCS]]></methodname><![CDATA[];            ]]><lineannotation><![CDATA[/* control characters */]]></lineannotation>
<![CDATA[    ]]><methodname><![CDATA[speed_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_ispeed]]></methodname><![CDATA[;           ]]><lineannotation><![CDATA[/* input speed */]]></lineannotation>
<![CDATA[    ]]><methodname><![CDATA[speed_t]]></methodname><![CDATA[ ]]><methodname><![CDATA[c_ospeed]]></methodname><![CDATA[;           ]]><lineannotation><![CDATA[/* output speed */]]></lineannotation>
<![CDATA[  };]]>
</programlisting><para>Para anular el modo canónico y el eco, se debe modificar campo <emphasis role="strong">c_lflag</emphasis>. Para ello se útilizaran las siguientes banderas  </para><itemizedlist><listitem><para><emphasis role="strong">ECHO</emphasis> repite los carácter en la terminal (eco). </para></listitem><listitem><para><emphasis role="strong">ICANON</emphasis> entrada canónica o modo linea, los caracteres no son enviados a la aplicación hasta que se presiona enter  </para></listitem></itemizedlist><para>para mas información [Local Modes](<ulink url="https://www.gnu.org/software/libc/manual/html_node/Local-Modes.html#Local-Modes"/>) </para></section><section><title>Funciones</title><itemizedlist><listitem><para><emphasis role="strong">tcgetattr</emphasis>: para obtener los parámetros actuales de la terminal. Prototipo de función: <code> int tcgetattr(int fd, struct termios *termios_p); </code> </para></listitem><listitem><para><emphasis role="strong">tcsetattr</emphasis>: para configurar los parámetros a una terminal. Prototipo de función: <code>int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);</code> </para></listitem></itemizedlist><para>(para más ayuda <code>&gt; man 3 tcsetattr</code>). </para></section><section><title>Ejemplo: imprimir el carácter y su código</title><programlisting format="linespecific" language="highlight" linenumbering="numbered" startinglinenumber="1"><![CDATA[#include ]]><lineannotation><![CDATA[<stdio.h>]]></lineannotation>
<![CDATA[#include ]]><lineannotation><![CDATA[<termios.h>]]></lineannotation>

<![CDATA[#define FD_STDIN 0]]>

<token><![CDATA[int]]></token><![CDATA[ ]]><methodname><![CDATA[main]]></methodname><![CDATA[()]]>
<![CDATA[{]]>
<![CDATA[   ]]><token><![CDATA[char]]></token><![CDATA[ ]]><methodname><![CDATA[tec]]></methodname><![CDATA[;]]>
<![CDATA[   ]]><token><![CDATA[struct]]></token><![CDATA[ ]]><methodname><![CDATA[termios]]></methodname><![CDATA[ ]]><methodname><![CDATA[t_old]]></methodname><![CDATA[, ]]><methodname><![CDATA[t_new]]></methodname><![CDATA[;]]>
<![CDATA[   ]]><methodname><![CDATA[tcgetattr]]></methodname><![CDATA[(]]><methodname><![CDATA[FD_STDIN]]></methodname><![CDATA[, &]]><methodname><![CDATA[t_old]]></methodname><![CDATA[); ]]><lineannotation><![CDATA[// lee atributos del teclado]]></lineannotation>
<lineannotation></lineannotation><![CDATA[   ]]><methodname><![CDATA[t_new]]></methodname><![CDATA[ = ]]><methodname><![CDATA[t_old]]></methodname><![CDATA[;]]>
<![CDATA[   ]]><methodname><![CDATA[t_new]]></methodname><![CDATA[.]]><methodname><![CDATA[c_lflag]]></methodname><![CDATA[ &= ~(]]><methodname><![CDATA[ECHO]]></methodname><![CDATA[ | ]]><methodname><![CDATA[ICANON]]></methodname><![CDATA[); ]]><lineannotation><![CDATA[// anula entrada canónica y eco]]></lineannotation>
<lineannotation></lineannotation><![CDATA[   ]]><methodname><![CDATA[tcsetattr]]></methodname><![CDATA[(]]><methodname><![CDATA[FD_STDIN]]></methodname><![CDATA[,]]><methodname><![CDATA[TCSANOW]]></methodname><![CDATA[,&]]><methodname><![CDATA[t_new]]></methodname><![CDATA[); ]]><lineannotation><![CDATA[// actualiza con los valores nuevos de la config. TCSANOW = activar la modificación inmediatamente]]></lineannotation>
<lineannotation></lineannotation><![CDATA[   ]]><methodname><![CDATA[tec]]></methodname><![CDATA[ = 0;]]>
<![CDATA[   ]]><token><![CDATA[while]]></token><![CDATA[ (]]><methodname><![CDATA[tec]]></methodname><![CDATA[!=10){ ]]><lineannotation><![CDATA[// Ingresar hasta oprimir enter]]></lineannotation>
<lineannotation></lineannotation><![CDATA[      ]]><methodname><![CDATA[tec]]></methodname><![CDATA[=]]><methodname><![CDATA[getchar]]></methodname><![CDATA[();]]>
<![CDATA[      ]]><methodname><![CDATA[printf]]></methodname><![CDATA[(]]><phrase><![CDATA["]]></phrase><phrase><![CDATA[%c - %d]]></phrase><![CDATA[
]]><phrase><![CDATA["]]></phrase><![CDATA[,]]><methodname><![CDATA[tec]]></methodname><![CDATA[,]]><methodname><![CDATA[tec]]></methodname><![CDATA[);]]>
<![CDATA[   }]]>
<![CDATA[   ]]><methodname><![CDATA[tcsetattr]]></methodname><![CDATA[(]]><methodname><![CDATA[FD_STDIN]]></methodname><![CDATA[, ]]><methodname><![CDATA[TCSANOW]]></methodname><![CDATA[, &]]><methodname><![CDATA[t_old]]></methodname><![CDATA[); ]]><lineannotation><![CDATA[// actualiza con los valores previos ]]></lineannotation>
<lineannotation></lineannotation><![CDATA[}]]>
</programlisting></section></section></article>