Saltar al contenido

Escribir un programa de terminal interactivo “real” como vim, htop, … en C / C ++ sin ncurses

Solución:

Para manipular el terminal tienes que usar secuencias de control. Desafortunadamente, esos códigos dependen del terminal particular que esté utilizando. Es por eso terminfo (previamente termcap) existe en primer lugar.

No dices si quieres usar terminfo o no. Entonces:

  • Si va a utilizar terminfo, le dará la secuencia de control correcta para cada acción que admita su terminal.
  • Si no usa terminfo … bueno, debe codificar manualmente cada acción en cada tipo de terminal que desee admitir.

Como desea esto con fines de aprendizaje, lo explicaré en el segundo.

Puede descubrir el tipo de terminal que está utilizando desde la variable de entorno $TERM. En linux los más habituales son xterm para emuladores de terminal (XTerm, gnome-terminal, konsole) y linux para terminales virtuales (aquellos en los que X no se está ejecutando).

Puede descubrir las secuencias de control fácilmente con el comando tput. Pero como tput los imprime en la consola, se aplicarán inmediatamente, así que si realmente quieres verlos, usa:

$ TERM=xterm tput clear | hd
00000000  1b 5b 48 1b 5b 32 4a                              |.[H.[2J|

$ TERM=linux tput clear | hd
00000000  1b 5b 48 1b 5b 4a                                 |.[H.[J|

Es decir, para limpiar la pantalla en un xterm tienes que salir ESC [ H ESC [ 2J en un xterm pero ESC [ H ESC [ J en una terminal de Linux.

Acerca de los comandos particulares sobre los que pregunta, debe leer con atención man 5 terminfo. Hay mucha información ahí.

Aunque esta es una pregunta un poco vieja, pensé que debería compartir un pequeño ejemplo de cómo hacer esto sin usar ncurses, no es difícil pero estoy seguro de que no será tan portátil.

Este código establece stdin en modo crudo, cambia a una pantalla de búfer alternativa (que guarda el estado del terminal antes de iniciarlo), habilita el seguimiento del mouse e imprime el botón y las coordenadas cuando el usuario hace clic en algún lugar. Después de dejar de fumar control+C el programa revierte la configuración del terminal.

#include <stdio.h>
#include <unistd.h>
#include <termios.h>

int main (void)
{
    unsigned char buff [6];
    unsigned int x, y, btn;
    struct termios original, raw;

    // Save original serial communication configuration for stdin
    tcgetattr( STDIN_FILENO, &original);

    // Put stdin in raw mode so keys get through directly without
    // requiring pressing enter.
    cfmakeraw (&raw);
    tcsetattr (STDIN_FILENO, TCSANOW, &raw);

    // Switch to the alternate buffer screen
    write (STDOUT_FILENO, "e[?47h", 6);

    // Enable mouse tracking
    write (STDOUT_FILENO, "e[?9h", 5);
    while (1) {
        read (STDIN_FILENO, &buff, 1);
        if (buff[0] == 3) {
            // User pressd Ctr+C
            break;
        } else if (buff[0] == 'x1B') {
            // We assume all escape sequences received 
            // are mouse coordinates
            read (STDIN_FILENO, &buff, 5);
            btn = buff[2] - 32;
            x = buff[3] - 32;
            y = buff[4] - 32;
            printf ("button:%unrx:%unry:%unnr", btn, x, y);
        }
    }

    // Revert the terminal back to its original state
    write (STDOUT_FILENO, "e[?9l", 5);
    write (STDOUT_FILENO, "e[?47l", 6);
    tcsetattr (STDIN_FILENO, TCSANOW, &original);
    return 0;
}

Nota: Esto no funcionará correctamente para terminales que tengan más de 255 columnas.

Las mejores referencias para secuencias de escape que he encontrado son esta y esta.

Estoy un poco confundido. Hablas de una “aplicación terminal”, como vim; las aplicaciones de terminal no obtienen eventos del mouse y no responden al mouse.

Si habla de aplicaciones de terminal reales, que se ejecutan en un
xterm, lo importante a tener en cuenta es que muchos de los problemas de portabilidad conciernen al terminal y no al sistema operativo. El terminal se controla enviando diferentes secuencias de escape. Cuáles hacen qué dependen del terminal; los códigos de escape ANSI están ahora bastante extendidos, sin embargo, consulte http://en.wikipedia.org/wiki/ANSI_escape_code. Estos se entienden generalmente por xterm, por ejemplo.

Puede que tenga que generar una secuencia adicional al principio y al final para entrar y salir del modo de “pantalla completa”; esto es necesario para xterm.

Finalmente, tendrá que hacer algo especial en el nivel de entrada / salida para asegurarse de que su controlador de salida no agregue ningún carácter (por ejemplo, convertir un LF simple en un CRLF) y asegurarse de que la entrada no haga eco, sea transparente y regresa inmediatamente. En Linux, esto se hace usando ioctl. (Nuevamente, no olvide restaurarlo cuando termine).

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *