Pisanie" prawdziwego " interaktywnego programu terminalowego jak vim, htop, ... w C/C++ bez ncurses

Nie, Nie chcę używać ncurses , ponieważ chcę dowiedzieć się, jak terminal działa i baw się dobrze programując go na własną rękę. :) To nie musi być przenośny, musi działać tylko na emulatorach terminali opartych na Linuksie xterm.

Chcę zaprogramować interaktywną aplikację terminalową, taką jak htop i vim. Chodzi mi o to, że nie jest to wyjście znaków, które wyglądają jak pudełka lub ustawianie kolorów, jest to banalne; również, aby treść pasowała do rozmiar okna. What I need is

  1. Jak uzyskać interakcje z myszą , takie jak kliknięcie na znak i przewijanie kółka myszy (gdy mysz jest na określonym znaku), aby zaimplementować przewijanie [ EDIT: w emulatorze terminala oczywiście] i

  2. Jak caĹ 'kowicie zapisaÄ ‡ i przywrăłciä ‡ wyjĹ" Cie procesĂłw rodzicĂłw i oddzieliÄ ‡ drukowanie od jego wyjĹ "cia, wiÄ ™ c po opuszczeniu aplikacji nic poza poleceniem, ktĂłre wpisaĺ' em w powĺ ' Oce nie powinno bądź tam, jak podczas uruchamiania htop i zamykania go ponownie: nic nie jest już widoczne z tej aplikacji.

Naprawdę nie chcę używać ncurses. Ale oczywiście, jeśli wiesz, która część ncurses jest odpowiedzialna za te zadania, możesz mi powiedzieć, gdzie w kodzie źródłowym mogę go znaleźć, więc będę go badać.

Author: leemes, 2011-12-12

3 answers

Jestem trochę zdezorientowany. Mówisz o " aplikacji terminalowej", jak vim; aplikacje terminalowe nie dostają zdarzeń myszy i nie odpowiadaj na mysz.

Jeśli mówimy o prawdziwych aplikacjach terminalowych, które działają w xterm, Ważne jest, aby pamiętać, że wiele z przenośności problemy dotyczą terminala, a nie systemu operacyjnego. Terminal jest sterowany wysyłając różne sekwencje ucieczki. Które robią to, co zależy od terminala; kody escape ANSI są teraz dość szeroko rozpowszechnione, jednak zobacz http://en.wikipedia.org/wiki/ANSI_escape_code . są one ogólnie rozumiane przez xterm, Na przykład.

Może być konieczne wyjście dodatkowej sekwencji na początku i na końcu, aby wejść i wyjść z trybu "Pełny ekran"; jest to konieczne dla xterm.

Na koniec musisz zrobić coś specjalnego na poziomie wejścia/wyjścia, aby upewnić się, że sterownik wyjściowy nie dodaje żadnych znaków (np. nie odbija się echem, jest przezroczysty i natychmiast powraca. Pod Linuksem odbywa się to za pomocą ioctl. (Ponownie, nie zapomnij przywrócić go po zakończeniu.)

 4
Author: James Kanze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-12 15:22:19

Aby manipulować terminalem musisz użyć sekwencji sterujących. Niestety, te kody zależą od konkretnego terminala, którego używasz. Dlatego terminfo (poprzednio termcap) istnieje w pierwszej kolejności.

Nie mówisz, czy chcesz używać terminfo, czy nie. Więc:

  • jeśli użyjesz terminfo, poda ci prawidłową sekwencję kontrolną dla każdej akcji, którą obsługuje twój terminal.
  • jeśli nie używasz terminfo... trzeba ręcznie koduj każdą akcję w każdym typie terminala, który chcesz obsługiwać.
Jak chcesz to do celów edukacyjnych, rozwiążę to w drugim.

Możesz odkryć typ terminala, którego używasz ze zmiennej środowiskowej $TERM. W Linuksie najczęściej stosowane są xterm dla emulatorów terminali (XTerm, gnome-terminal, konsole) i linux dla terminali wirtualnych (tych, gdy X nie jest uruchomiony).

Możesz łatwo odkryć sekwencje sterowania za pomocą polecenia tput. Ale jako tput drukuje je na konsoli, zostaną zastosowane natychmiast, więc jeśli chcesz je naprawdę zobaczyć, użyj:

$ 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|

Oznacza to, że aby wyczyścić ekran w xterm musisz wyjść ESC [ H ESC [ 2J w xterm, ale ESC [ H ESC [ J w terminalu linuksowym.

O poszczególnych poleceniach, o które pytasz, powinieneś uważnie przeczytać man 5 terminfo. Jest tam dużo informacji.

 16
Author: rodrigo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-07 00:34:03

Chociaż jest to pytanie trochę stare, pomyślałem, że powinienem podzielić się krótkim przykładem, jak to zrobić bez użycia ncurses, to nie jest trudne, ale jestem pewien, że nie będzie tak przenośny.

Ten kod ustawia stdin w trybie surowym, przełącza się na ekran alternatywnego bufora (który zapisuje stan terminala przed uruchomieniem), włącza śledzenie myszy i wyświetla przycisk i współrzędne, gdy użytkownik gdzieś kliknie. Po zakończeniu z Ctrl+C program odwraca konfiguracja terminala.

#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;
}

Uwaga: nie będzie to działać poprawnie w przypadku terminali, które mają więcej niż 255 kolumn.

Najlepsze odniesienia do sekwencji ucieczki jakie znalazłem to ten i ten jeden.

 7
Author: santileortiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-21 09:01:42