Introduction to the Unix Curses Library

Curses -- Terminal independant console handling


The curses module provides an interface to the curses Unix library, the de-facto standard for portable advanced terminal handling. While curses is most widely used in the Unix environment, versions are available for DOS, OS/2, and possibly other systems as well.
 

Many widely-used programs need to make use of a terminal's cursor-movement capabilities. A familiar example is vi; most of its commands make use of such capabilities. For example, hitting the `j' key while in vi will make the cursor move up one line. Typing `dd' will result in the current line being erased, the lines below it moving up one line each, and the lines above it remaining unchanged.

A potential problem with all this is that different terminals have different ways in which to specify a given type of cursor motion.

For example, if a program wants to make the cursor move up one line on a VT100 terminal, the program needs to send the characters Escape, `[', and `A':

printf("%c%c%c",27,'[','A');   (the character code for the Escape key is 27).

But for a Televideo 920C terminal, the program would have to send the ctrl-K character, which has code 11:

printf("%c",11);


Clearly, the authors of programs like vi would go crazy trying to write different versions for every terminal, and worse yet, anyone else writing a program which needed cursor movement would have to ``re-invent the wheel,'' i.e. do the same work that the vi-writers did, a big waste of time.

That is why the curses library was developed.

When you log on, you have a terminal type, in the environment variable TERM that defines your current terminal properties.

The curses library consists of a number of functions which your program can call. Those functions know the various cursor-movement character sequences for a large variety of terminals (this information is in the file /etc/termcap). The important implication of that is that your program does not have to know that information; it simply calls the curses functions, and those functions will use your TERM value to check the /etc/termcap file and then send the proper cursor-movement characters.

For example, if your program wanted to clear the screen, it would not (directly) use any character sequences like those above. Instead, it would simply make the call

clear();

and curses would do the work on the program's behalf.

Here are some of the (curses) functions you can call:

      initscr()  --  REQUIRED; initializes the whole screen for curses

      endwin()  --  REQUIRED; resets the terminal, e.g. restores echo,
                    cooked (non-cbreak) mode, etc. 

      cbreak()  --  read characters from keyboard as they are typed,
                    without waiting for carriage return; backspace
                    and other control characters (including the carriage
                    return itself) lose their meaning;

      nocbreak()  --  restores normal mode

      noecho()  --  don't echo the input characters to the screen

      echo()  --  restores echo

      clear()  --  clear screen, and place cursor in upper-left corner

      move(int,int)  --  move the cursor to the indicated row (top
                         row is 0) and column (leftmost column is 0)

      addch(char)  --  write the given character at the current cursor
                       position, overwriting what was there before,
                       and moving the cursor to the right by one 
                       position

      insch(char)  --  same as addch(), but insert instead of overwrite;
                       all characters to the right move one space to the
                       right

      delch()  --  delete character at the current cursor position, 
                   causing all characters to the right moving one space 
                   to the left; cursor position does not change

      char getch()  --  read in one character from the keyboard

      char inch()  --  returns the character currently under the cursor

      scanw(), printw()  --  work just like scanf() and printf(), but
                             in a curses environment; avoid use of
                             scanf() and printf() in such an environment,
                             which can lead to bizarre results; note
                             that printw() [and scanw() if echo is on]
                             will do repeated addch() calls, so it will
                             insert, not overwrite

      refresh()  --  update the screen to reflect all changes we have
                     requested since the last call to this function


Para Mais Informações

Informação Detalhada sobre as Funções etc.

Para Utilizar Curses

1) #include <curses.h
2) Linking para a livraria /usr/lib/libcurses.a e /usr/lib/libtermcap.a

cc -o executavel ficheiro.c -lcurses


Exemplo

Em baixo é um programa  simples que mostre o funcionamento de Curses.
Devem copiar o programa para sua area na ciunix compilar e executar.
O codigo fonte está disponivel no ficheiro  ~crocker/prog3/curses/test.c

O programa utilize printw e scanw em vez de printf e scanf.
No entanto podem alterar o programa para usar para printf/scanf para ver as diferenças - tomando os cuidados necessários devido ao modo cbreak() - valores introduzidos serão seperadas/reconhecidos atraves um espaco e não o return etc.
 
 

   /* curses demonstration program; continues to read in row-column
   coordinates and puts asterisks at the indicated positions;

   echoing of those coordinates is suppressed with noecho
   instead coordinates are written on seperate line;

   program ends by entering a negative row */

#include <curses.h
main()
{
        int Row,Col;
        initscr();
        cbreak();  /* cuidado com scanf com esta opcao */
        noecho();  /*Experimente a diferenca */
        refresh();

        while(1)
        {
            move(18,2);
            printw("enter Row->");
            scanw("%d",&Row);
            if (Row < 0) break;

            move(18,2);
            printw("enter Col->");
            scanw("%d",&Col);

            move(Row,Col);
            delch();  insch('*');

            move(20,2);
            deleteln ();  /* apagar informacao velha nesta linha */
            printw("%d %d",Row,Col);

            refresh();
         }
}