turbo programar online español dev compiler compilador c++ c terminal interactive

español - programar c++ online



Escribir un programa terminal interactivo "real" como vim, htop,... en C/C++ sin ncurses (3)

No, no quiero usar ncurses , porque quiero aprender cómo funciona la terminal y divertirme programando por mi cuenta. :) No tiene que ser portátil, solo tiene que funcionar en emuladores de terminal basados ​​en linux xterm.

Lo que quiero hacer es programar una aplicación de terminal interactiva como htop y vim. Lo que quiero decir no es la salida de caracteres que parecen cajas o colores de configuración, esto es trivial; también para hacer que el contenido se ajuste al tamaño de la ventana. Lo que necesito es

  1. cómo obtener interacciones con el mouse, como hacer clic en un carácter y desplazar la rueda del mouse (cuando el mouse está en un carácter específico) para implementar el desplazamiento [ EDITAR: en un emulador de terminal, por supuesto ], y

  2. cómo guardar completamente y restaurar la salida del proceso principal y separar mi impresión de su salida, así que después de abandonar mi aplicación, nada más que el comando que ingresé en el shell debería estar allí, como al ejecutar htop y salir de nuevo: nada es visible de esta aplicación más.

Realmente no quiero usar ncurses. Pero, por supuesto, si sabes qué parte de ncurses es responsable de estas tareas, puedes decirme en qué parte del código fuente puedo encontrarlo, así que lo estudiaré.


Estoy un poco confundido. Usted habla de una "aplicación de terminal", como vim; las aplicaciones de terminal no reciben eventos de mouse y no responden al mouse.

Si habla de aplicaciones de terminal reales, que se ejecutan en un xterm , lo importante es que muchos de los problemas de portabilidad se refieren a la terminal y no al sistema operativo. El terminal se controla enviando diferentes secuencias de escape. ¿Cuáles hacen qué depende de la terminal? los códigos de escape de ANSI ahora están bastante extendidos, sin embargo, vea http://en.wikipedia.org/wiki/ANSI_escape_code . Estos son generalmente entendidos por xterm , por ejemplo.

Es posible que deba generar una secuencia adicional al principio y al final para ingresar y salir del modo "pantalla completa"; esto es necesario para xterm .

Finalmente, deberá hacer algo especial a 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 se repita, sea transparente y regresa inmediatamente En Linux, esto se hace usando ioctl . (De nuevo, no olvide restaurarlo cuando termine).


Aunque esta pregunta es un poco vieja, pensé que debería compartir un breve 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 raw, cambia a una pantalla de buffer alternativa (que guarda el estado del terminal antes de iniciarlo), habilita el rastreo del mouse e imprime el botón y las coordenadas cuando el usuario hace clic en algún lugar. Después de salir con Ctrl + 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:%u/n/rx:%u/n/ry:%u/n/n/r", 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 las secuencias de escape que he encontrado son esta y esta .


Para manipular el terminal, debes usar secuencias de control . Desafortunadamente, esos códigos dependen del terminal particular que está usando. Es por eso que terminfo (anteriormente termcap ) existe en primer lugar.

No dices si quieres usar terminfo o no. Asi que:

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

Como quiera esto para fines de aprendizaje, lo elaboraré en el segundo.

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

Puede descubrir las secuencias de control fácilmente con command tput . Pero a medida que los imprime en la consola, se aplicarán de inmediato, por lo que si realmente desea verlos, use:

$ 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 borrar la pantalla en un xterm , debe mostrar ESC [ H ESC [ 2J en un xterm pero ESC [ H ESC [ J en un terminal de linux.

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