Ncurses
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é parmvaddch(y, x, c) ;
. De même,wmove(fenetre, y, x) ; waddch(fenetre, c) ;
sera remplacé parmvwaddch(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 :
- Faire un ou logique du caractère à modifier et de la valeur du modificateur (commençant par "A_"), dans l'appel à
addch()
ou autre. - Sélectionner la valeur courante de surlignement, grâce aux fonctions
attron()
,attroff()
etattrset()
.
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 utiliseraddch(char c)
; pour utiliser une autre fenêtre on utilisewaddch()
).
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 pourcurscr
etstdscr
. 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 avantinitscr()
sont :slk_init()
,filter()
,ripoffline()
,use_env()
, et, en cas d'utilisation de plusieurs terminaux,newterm()
(initscr()
utilise en faitnewterm()
).
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>.
endwin()
: voir #Basculer entre les modes ncurese et console.
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()
oudoupdate()
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 parinitscr()
.reset_prog_mode()
: restaure l'état du programme (mode curses). Appelée automatiquement pardoupdate()
, et donc normalement pas appelée à la main.reset_shell_mode()
: restaure l'état du programme (mode console). Appelée automatiquement parendwin()
, 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. Appelersetupterm()
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, appelleaddch()
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'appelergetch()
). [w]getstr(char* chaine)
: récupère dans "chaine" la chaîne entrée.[w]scanw()
: même style quescanf(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)
ouattrset(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 constanteCOLOR_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 viawnoutrefresh()
puis d'appeler une seule foisdoupdate()
.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 prochainrefresh()
.
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()