Ncurses

De La Mouche VII
Aller à la navigationAller à la recherche


Compilation

  • Inclure <curses.h>.
  • Compiler avec l'option -lncurses (sur la ligne de commandes ou dans LDFLAGS).
  • Pour utiliser la bibliothèque Panel, utiliser également l'option -lpanel, de préférence avant -lncurses.

Notes et astuces diverses

  • Si une fonction nécessite un pointeur de fenêtre, c'est toujours son premier argument.
  • Pour réafficher l'écran à l'identique (tel que le programme pense qu'il doit être) : wrefresh(curscr)

Débogage

A cause du volume d'informations y apparaissant, les fichiers journaux obtenus lorsque l'on active la trace du programme peuvent être difficiles à décoder. Le script tracemunch inclus avec ncurses peut alléger le problème : il compacte les longues séquences d'opérations identiques en des "pseudo-opérations" d'une seule ligne (en majuscules).

Préfixes courants des fonctions

  • w : la fonction en question, mais avec une fenêtre-cible différente de stdcsr.
  • mv : se déplacer en (x,y) avant d'effectuer le traitement.
Exemple : move(y, x) ; addch(c) ; peut être remplacé par mvaddch(y, x, c) ;. De même, wmove(fenetre, y, x) ; waddch(fenetre, c) ; sera remplacé par mvwaddch(fenetre, y, x, c) ;.

Ouvrir un shell (ou autre programme en console)

Se référer à la section #Basculer entre les modes ncurese et console.

addstr("Ouverture d'un shell...") ;
def_prog_mode() ; // Sauvegarde de l'état du terminal (mode curses)
endwin() ; // Restauration de l'état du terminal (mode console)
system("sh") ; // Lancement du shell
addstr("Retour au mode curses.\n") ; // Prépare le message de retour
refresh() ; // Restaure le mode curses sauvegardé et réaffiche l'écran

ncurses sous Xterm

Lorsque l'on redimensionne Xterm, le signal SIGWINCH est envoyé à l'application s'exécutant dedans. ncurses propose un gestionnaire de signal expérimental, mais n'intercepte généralement pas le signal car il ne sait pas de quelle manière il doit réafficher. Il faut écrire le gestionnaire du signal SIGWINCH soi-même. Le plus facile est qu'il contienne un appel à endwin(), suivi d'un refresh() et d'un réaffichage de l'écran personnalisé. Le refresh() va lire la nouvelle taille de l'écran depuis l'environnement Xterm.

Cette méthode est la méthode standard (qui marche même sur certaines implémentations propriétaires de curses). L'inconvénient est que l'écran est complètement réaffiché mais que les sous-fenêtres ne sont pas redimensionnées. ncurses fournit une extension qui fonctionne mieux : resizeterm(). Cette fonction s'assure que toutes les fenêtres sont limitées à la nouvelle taille de l'écran, et complète avec des espaces si l'écran est plus large.

ncurses peut être configuré pour utiliser son propre gestionnaire de signal pour SIGWINCH, basé sur resizeterm().

Terminaux multiples

Si le programme doit ouvrir plusieurs terminaux, utiliser directement newterm() plutôt que initscr(). Voir #Début et fin de programme pour le descriptif des arguments. stdscr pointe vers le dernier terminal alloué. On bascule entre les différents terminaux grâce à la fonction set_term(). Note : il faut appeler soi-même def_shell_mode() et def_prog_mode() pour chaque terminal.

Vérifier les fonctionnalités du terminal

Faire : traduction

Sometimes you may want to write programs that test for the presence of various capabilities before deciding whether to go into ncurses mode. An easy way to do this is to call setupterm(), then use the functions tigetflag(), tigetnum(), and tigetstr() to do your testing.

A particularly useful case of this often comes up when you want to test whether a given terminal type should be treated as `smart' (cursor-addressable) or `stupid'. The right way to test this is to see if the return value of tigetstr("cup") is non-NULL. Alternatively, you can include the term.h file and test the value of the macro cursor_address.

Accélérer l'affichage

La fonction d'affichage de chaînes addchstr(), et ses petites camarades, fonctionnent plus rapidement que addstr() et consors. Voici les principales différences :

  • le curseur n'est pas avancé ;
  • les caractères spéciaux (comme \n) ne sont pas traités ;
  • la chaîne est tronquée à la fin de la ligne au lieu de continuer sur une nouvelle ligne.

De manière générale, pour améliorer la vitesse d'affichage, il faut essayer de ne pas changer trop souvent d'attributs de mise en forme (et de ne pas activer immedok(TRUE) !).

Fonctionnalités spéciales de ncurses

Faire : traduction

The wresize() function allows you to resize a window in place. The associated resizeterm() function simplifies the construction of SIGWINCH handlers, for resizing all windows.

The define_key() function allows you to define at runtime function-key control sequences which are not in the terminal description. The keyok() function allows you to temporarily enable or disable interpretation of any function-key control sequence.

The use_default_colors() function allows you to construct applications which can use the terminal's default foreground and background colors as an additional "default" color. Several terminal emulators support this feature, which is based on ISO 6429.

Ncurses supports up 16 colors, unlike SVr4 curses which defines only 8. While most terminals which provide color allow only 8 colors, about a quarter (including XFree86 xterm) support 16 colors.

Affichage

Attributs de texte

Il y a deux façons de faire un surlignement :

  1. Faire un ou logique du caractère à modifier et de la valeur du modificateur (commençant par "A_"), dans l'appel à addch() ou autre.
  2. Sélectionner la valeur courante de surlignement, grâce aux fonctions attron(), attroff() et attrset().

Les couleurs sont un type particulier de surlignement. Un surlignement est en fait une paire de couleurs, l'une pour le texte et l'autre pour le fond. On déclare ces couples grâce à init_pair().

Affichage de formes

La fonction addch() (et certaines autres comme box() et border()) peut accepter en argument des pseudo-caractères définis par ncurses (#define avec le préfixe "ACS_" dans <curses.h>). Ces pseudo-caractères permettent de dessiner des boîtes et autres sur l'écran.

Constantes et variables fournies

Définitions générales

  • #define bool : type booléen (char).
  • #define TRUE : booléen VRAI (1).
  • #define FALSE : booléen FAUX (0).
  • #define ERR : drapeau retourné en cas d'erreur par les routines.
  • #define OK : drapeau retourné par les routines quand tout va bien.

Description du terminal

  • int LINES : nombre de lignes du terminal.
  • int COLS : nombre de colonnes.

Note : éviter d'utiliser LINES et COLS ; il vaut mieux appeler la fonction getmaxyx() sur le stdscr.

Fenêtres standard

Deux fenêtres sont fournies par défaut :

  • struct WINDOW curscr : à quoi le terminal ressemble actuellement. Ne pas la modifier directement.
  • struct WINDOW stdscr : à quoi le terminal ressemblera au prochain raffraichissement. De nombreuses fonctions utilisent cette fenêtre par défaut (exemple : pour ajouter un caractère à stdscr, on peut utiliser addch(char c) ; pour utiliser une autre fenêtre on utilise waddch()).

Attributs de caractères

  • La liste des mises en valeur possibles (surlignement et couleurs) figure dans <curses.h> (préfixes "A_").

Fonctions

Début et fin de programme

  • initscr() : initialise curses. Récupère les caractéristiques terminal et alloue l'espace pour curscr et stdscr. Cette fonction doit toujours être appelée avant les fonctions qui affectent les fenêtres ou le terminal. Les seules fonctions pouvant être appelées avant initscr() sont : slk_init(), filter(), ripoffline(), use_env(), et, en cas d'utilisation de plusieurs terminaux, newterm() (initscr() utilise en fait newterm()).
  • SCREEN* newterm (char* type, FILE* out, FILE* in) : si le programme doit afficher sur plusieurs terminaux, il faut utiliser newterm() au lieu de initscr(). newterm() doit être appelé une fois par terminal. L'argument TYPE représente le type du terminal ; s'il est NULL, la variable d'environnement $TERM est utilisée. endwin() devra être appelée pour chaque terminal ouvert par newterm().
  • SCREEN* set_term(SCREEN* terminal) : bascule vers le terminal donné, ouvert préalablement avec newterm(). Cette fonction retourne le terminal duquel on vient de basculer.
  • delscreen(SCREEN* terminal) : désalloue les structures de données associée à un terminal. Cette fonction devrait être appelée après endwin() si un terminal n'est plus nécessaire.
  • keypad(stdscr, TRUE) : active le support du mappage des touches de fonction (flèches, etc.). Les valeurs de pseudo-caractères #define retournées sont listées dans <curses.h>.

Basculer entre les modes ncurese et console

  • endwin() : restaure le terminal tel qu'il était lors de l'appel à initsrc(). Cette fonction devrait toujours être appelée avant la fin du programme. Elle permet aussi de basculer entre le mode console et le mode curses ; une fois en mode console, un appel à refresh() ou doupdate() restaure la fenêtre curses telle qu'elle était avant l'appel à endwin().
  • bool isendwin() : retourne TRUE si le programme est en mode console (c'est-à-dire entre un appel à endwin() et un appel à refresh()), FALSE sinon.
  • def_prog_mode() : sauvegarde l'état du programme (mode curses).
  • def_shell_mode() : sauvegarde l'état du programme (mode console). Appélée automatiquement par initscr().
  • reset_prog_mode() : restaure l'état du programme (mode curses). Appelée automatiquement par doupdate(), et donc normalement pas appelée à la main.
  • reset_shell_mode() : restaure l'état du programme (mode console). Appelée automatiquement par endwin(), et donc normalement pas appelée à la main.

Accès bas niveau

setupterm(char* term, int filnum, int* errret) 
Appelée pour initialiser la description du terminal. Arguments :
  • term : chaîne de caractères représentant le nom du terminal utilisé (NULL pour utiliser le terminal désigné par $TERM).
  • filenum : descripteur de fichier du terminal utilisé pour la sortie.
  • "errret" : code de retour de la fonction (1 si tout va bien, 0 si le terminal n'a pas été trouvé, -1 en cas de problème pour trouver la base de données terminfo) ; on peut passer NULL si on ne veut pas récupérer le code d'erreur.
Après l'appel à setupterm(), la variable globale cur_term pointe vers la structure détaillant les paramètres du terminal courant. Appeler setupterm() pour chaque terminal et sauver et restaurer cur_term permet d'utiliser deux terminaux (ou plus) à la fois. setupterm() enregistre également, dans le tableau de caractères ttytype[] (global), la section de la description du terminal concernant les noms (ce tableau est écrasé à chaque appel à setupterm()).

Gestion des fenêtres

  • newwin() : créer une nouvelle fenêtre.
  • derwin()
  • subwin()
  • delwin() : "allow you to get rid of old windows"

Gestion du curseur

  • [w]move(int x, int y) : déplacer les coordonnées courantes (autrement dit le curseur) aux coordonnées (x,y) (colonne,ligne). L'origine est le coin supérieur gauche. Retourne ERR si l'on cherche à déplacer en dehors de la fenêtre.
  • leaveok() : placer le curseur à gauche plutôt qu'à l'endroit de la dernière action.

Entrées

  • char getch() : si l'écho est actif, appelle addch() pour afficher le caractère tapé. Si l'on active l'écho, il faut que le terminal soit en mode "raw" ou "cbreak" (par défaut, l'écho est actif et le mode du terminal est "cooked", il faut donc changer l'un ou l'autre avant d'appeler getch()).
  • [w]getstr(char* chaine) : récupère dans "chaine" la chaîne entrée.
  • [w]scanw() : même style que scanf(3).

Sorties

  • [w]addch(char c) : ajouter un caractère à la fenêtre.
  • [w]mvaddch(int x, int y, char c) : se placer en (x,y) puis ajouter c.
  • addstr(char* chaine) : ajoute une chaîne de caractères (fait appel à addch()).
  • printw() : (fait appel à addch()).

Attributs de caractères

  • [w]attrset(int attributs) : active les attributs donnés.
  • [w]attron(int attributs) : active les attributs donnés sans modifier les autres.
  • [w]attroff(int attributs) : désactive les attributs donnés sans modifier les autres.
  • [w]standend : désactive tous les attributs. Equivalent à attrset(A_NORMAL) ou attrset(0).
  • init_pair(int numero, int COLOR_TEXTE, int COLOR_FOND) : définit un surlignement, qui portera le numéro "numero". La définition est enregistrée au moment de la compilation dans la constante COLOR_PAIR(int numero).

Gestion de l'affichage

  • refresh() / wrefresh(win) : faire correspondre une section du terminal à ce que décrit une fenêtre (en clair : afficher la fenêtre à l'endroit prévu). Rafraîchit uniquement les parties modifiées. Elle fonctionne en faisant un appel à wnoutrefresh() puis à doupdate() ; quand il y a plusieurs modifications successives à faire, il est préférable de les faire via wnoutrefresh() puis d'appeler une seule fois doupdate().
  • wnoutrefresh(win) : copie la fenêtre donnée sur l'écran virtuel.
  • doupdate() : met à jour l'écran (affichage à proprement parler).
  • touchwin() : fait un "touch" sur toute la fenêtre, afin qu'elle soit réaffichée entièrement au prochain refresh().

Débogage

  • trace(int niveau) : définit le niveau de trace. Si le niveau est supérieur à zéro, l'exécution du programme générera un fichier nommé "trace" dans le répertoire courant. On peut choisir un niveau de détail plus ou moins élevé, se référer aux constantes #define dans <curses.h> dont le préfixe est "TRACE_". Note : il est également possible de définir un niveau de trace en assignant une valeur à la variable d'environnement NCURSES_TRACE.
  • _tracef() : affiche des informations de débogage personnalisées dans le fichier de trace, si l'option "-lncurses_g" est passée à l'éditeur de liens.

Divers

  • scrollok() : autoriser un écran à défiler.
  • box()
  • border()