If you have some beginning experience in Unix programming, you may have felt the need of some text user interface operations, such as moving the cursor on the screen, editing user input, using colors, ... Such terminal IO related operations are not portable and not defined in C language. You need to either use the low-level termcap library or the curses library. Using curses/ncurses library is much easier and more portable.
#include <curses.h>
To link
the programs you need to use the -lcurses or
-lncurses option, like
gcc -lncurses prog.c
This way the
program is dynamically linked to the ncurses library. To run it in another
computer, the system must have the ncurses library installed. If you want to
avoid the trouble, you may have it statically linked. To do that, find the file
libncurses.a in /usr/lib and do
gcc prog.c libncurses.a
Most Unix systems have curses or ncurses installed as a default option. To find out if it's installed, you can try man ncurses man curses or go to /usr/lib and /usr/include to list the files.
If you're installing Linux or FreeBSD on your own machine, be sure to install the ncurses-development package in order to do ncurses programming.
initscr();
If your program
is going to write to several terminals, you should call newterm instead,
which is another story.
One-character-a-time. To disable the buffering of typed characters by the TTY driver and get a character-at-a-time input, you need to call
cbreak();
No echo. To suppress the automatic echoing of typed characters, you need to call
noecho();
Special keys. In order to capture special keystrokes like
Backspace, Delete and the four arrow keys by
getch()
, you need to call
keypad(stdscr, TRUE);
Before exiting. Before the program is terminated, endwin() must be called to restore the terminal settings.
The default window. A default window called stdscr, which is the size of the terminal screen, is supplied. To use the stdscr window, you don't need to do any initializations. You can also divide the screen to several parts and create a window to represent each part.
Create a new window. The data structure of window is WINDOW, defined in ncurses.h. To declare and create a new window, do
WINDOW * win = newwin(nlines, ncols, y0,
x0);
The screen (stdscr) (0,0)*----------------------------------* (0, COLUMNS-1) | | | | | (y0,x0) | | --------------- | | | | | | | | | | | win |nlines | | | | | | | | | | | | | | --------------- | | ncols | | | *----------------------------------* (LINES-1, 0) (LINES-1, COLUMNS-1)All the 4 parameters are ints. Here nline is the height of the window -- number of lines, ncols is the width -- number of columns of the window. y0 and x0 are the coordinates of the upper left corner of win on the screen -- line y0 and columns x0. You should make sure that the area of the new window is inside the screen.
Height and width of the window. The size of the whole screen can be determined by the two global variables COLUMNS and LINES. y0 and x0 should satisfy
0 <= y0 < LINES;
0 <= x0 < COLUMNS;
In X window system, the actual xterm size might be changed leaving these two variables obslete. In this case you should use the macro void getmaxyx(WINDOW *, int y, int x) to get the size of the screen.
int h, w;
getmaxyx(stdscr, h, w);
No overlapping. Windows cannot overlap with each other. Therefore you have two options: only use stdscr and no other windows, or create several non-overlapping windows but do not use stdscr.
Refresh. If you make some change to a window, such as printing something or moving the cursor, the effect is not shown on the screen until you call the wrefresh() function
wrefresh(win);
Clear window. To erase everything written in the window win, call wrefresh(win). refresh() is equivalent to wrefresh(stdscr).
Delete window. If a window win is no longer needed, and you're going to create new windows to overlap it, you should call delwin(win) to delete the window (release the memory it is using).
To move the cursor to a new position on a window, use the function int wmove(WINDOW *win, int y, int x)
wmove(win, y, x);
where
(x, y) are the coordinates of the new position in the window. If
the window has nlines lines and ncolumns
columns, then 0 <= y < nlines 0 <= x < ncolumns
Refresh. The actual cursor motion is not shown on the screen untill you do a wrefresh(win).
move(y, x) is equivalent to the wmove(stdscr, y, x).
int getch(void)
. int ch = getch();No echoing. If you have called
noecho()
, the character ch
will not be printed on the screen, otherwise it will. Disabling automatic
echoing gives you more control over the user interface.
No buffering. If you have called cbreak(void)
each key the user hits is returned
immediately by getch()
. Otherwise the keys hit by
the user are queued until a newline is read. Then calls to getch()
take characters from the queue in FIFO manner until
the queue is empty and the next whole line is read.
No delaying. Usually a call to getch()
waits until a key is hit. If you have called nodelay(stdscr,
TRUE)
, then getch()
will work in a
non-blocking manner -- it will return ERR if the key input is
not ready. This is usually useful for writing game-like programs, where the
promptness of user response matters. For example
int ch; nodelay(stdscr, TRUE); for (;;) { if ((ch = getch()) == ERR) { /* user hasn't responded ... */ } else { /* user has pressed a key ch ... */ } }
Special keys. If you have called keypad(stdstr,
TRUE)
, then if the user hits a special key such as the Delete key, the arrow keys, Ctrl combined keys
and function keys, a single int value will be returned. Here is the definition
of several special keys
key code description KEY_DOWN The four arrow keys ... KEY_UP KEY_LEFT KEY_RIGHT KEY_HOME Home key KEY_BACKSPACE Backspace KEY_F(n) Function keys, for 0 <= n >= 63 KEY_DC Delete character KEY_IC Insert char or enter insert mode KEY_ENTER Enter or sendFor a complete list read the man page of
getch()
.
Catch special keys. To use these keys, you need to check the return
value of getch()
. For example
int ch = getch(); switch (ch) { case KEY_BACKSPACE: /* user pressed backspace */ ... case KEY_UP: /* user pressed up arrow key */ ... case KEY_DOWN: /* user pressed up arrow key */ ... case 'A' .... /* user pressed key 'A' */ ... }Read character from a window. The function
int
wgetch(WINDOW *win)
. reads a key from a window. The user input of
course comes from the keyboard and not the screen window. But the different
windows on the screen might have different delay modes and other properties,
therefore affect the behavior of wgetch()
.
Moving the cursor and read a character. There are also functions which combine cursor moving and character reading together
int mvgetch(int y, int x); int mvwgetch(WINDOW *win, int y, int x);
int waddch(WINDOW * win, chtype
ch)
adds a character on the window at the current cursor position,
and the cursor position is advanced then.
Wrap. If the new position of the cursor is out of the window, it wraps to the beginning of the next line.
Scroll. If the next line is out of the window, and you have called
scrollok(win, TRUE)
when the window was created, the
stuff in the window is scrolled up one line.
Character attribute. The parameter ch
is
of type chtype()
, which is the ASCII value of the
character combined with some video attributes such as colors. The combination is
through the logical OR of the character value and the attribute,
which I will talk about in the section.
Refresh. After a call to waddch
, the
screen is not updated until you call wrefresh(win)
.
mvwaddch(win, y, x, ch);
is equivalent to wmove(win, y, x); waddch(win, ch);
addch(ch);
is equivalent to waddch(stdscr, ch);
.
wechochar(win, ch);
function and echochar(ch)
are equivalent to waddch(win,
ch); wrefresh(win);
and addch(ch);
refresh();
respectively. But echochar
and
wechochar
may be more efficient.
int waddstr(WINDOW *win, const char *str)
and
int addstr(const char *str)
prints a null-terminated
string at the cursor position of the window, and advance the cursor position
accordingly.
The functions int wprintw(WINDOW *win, char *fmt
...)
and int printw(char *fmt ...)
do
formatted output in the same fashion as the analogous standard library function
printf
.
waddch(win, ch)
a character value combined with
attribute. The other is setting the global window attribute.
Character type. When calling waddch(win,
ch)
or addch(ch)
, logical
OR the character value with the attribute. For example, A_UNDERLINE
is the predefined attribute for underlining.
To print the character 'X' with underlining, do
waddch(win, 'X' | A_UNDERLINE);Using several attributes is of course possible. For example, to To print the character 'X' with highlight in color pair 3
waddch(win, 'X' | A_UNDERLINE | COLOR_PAIR(3));
Setting window attribute. int wattron(WINDOW *win,
int attr)
function to turn on an attribute attr
. Then anything printed by subsequent calls to waddch
, addstr
and waddstr
will have the attribute attr
, For example, to print a highlighted message on the
screen
attron(A_STANDOUT); addstr("I am highlighted!\n");Predefined attributes. Here is some attributes defined in ncurses.h
A_NORMAL Normal display (no highlight) A_STANDOUT Best highlighting mode of the terminal. A_UNDERLINE Underlining A_REVERSE Reverse video A_BLINK Blinking A_DIM Half bright A_BOLD Extra bright or bold A_PROTECT Protected mode A_INVIS Invisible or blank mode A_ALTCHARSET Alternate character set A_CHARTEXT Bit-mask to extract a character COLOR_PAIR(n) Color-pair number n
start_color()
.
When start_color()
is called, a set of
colors and color pairs are created which you can use. The number
of available colors and the number of the color pairs are stored in two global
variables COLORS
and COLOR_PAIRS
. To use an predefined color pair as an
attribute, you need to cal the macro COLOR_PAIR(n)
,
where n must satisfy
0 <= n < COLORSExample. To give a window the color attribute defined by color pair #2, so that each subsequent character printed in this window has the foreground and background color defined by color pair #2
wattron(win, COLOR_PAIR(2));The meaning of a color pair can be redefined. For example
init_pair(1,2,0);redefine the color pair #1 with foreground color #2 and background color #0. In the function
int init_pair(short n, short f, short
b)
the parameters must satisfy 0 <= n < COLORS 0 <= f < COLOR_PAIRS 0 <= b < COLOR_PAIRS
When start_color()
is called, 8 basic colors are
initialized
COLOR_BLACK COLOR_RED COLOR_GREEN COLOR_YELLOW COLOR_BLUE COLOR_MAGENTA COLOR_CYAN COLOR_WHITEYou can use these names in
init_pair()
for
specifying foreground and background color.
To find out what foreground color and background color is used by a color
pair, use the function int pair_content(short pair, short *f,
short *b)
. To find out the definition of a color use the function
int color_content(short color, short *r, short *g, short
*b)
Color can also be redefined by int init_color(short n, short
r, short g, short b)
, where n is the index of color, must be less
than COLORS. r, g, and b represent the intensity of red, green and blue. Each
value of r, g and b must be less than 1000.
ACS_BLOCK solid square block ACS_BOARD board of squares ACS_BTEE bottom tee ACS_BULLET bullet ACS_CKBOARD checker board (stipple) ACS_DARROW arrow pointing down ACS_DEGREE degree symbol ACS_DIAMOND diamond ACS_GEQUAL greater-than-or-equal-to ACS_HLINE horizontal line ACS_LANTERN lantern symbol ACS_LARROW arrow pointing left ACS_LEQUAL less-than-or-equal-to ACS_LLCORNER lower left-hand corner ACS_LRCORNER lower right-hand corner ACS_LTEE left tee ACS_NEQUAL not-equal ACS_PI greek pi ACS_PLMINUS plus/minus ACS_PLUS plus ACS_RARROW arrow pointing right ACS_RTEE right tee ACS_S1 scan line 1 ACS_S3 scan line 3 ACS_S7 scan line 7 ACS_S9 scan line 9 ACS_STERLING pound-sterling symbol ACS_TTEE top tee ACS_UARROW arrow pointing up ACS_ULCORNER upper left-hand corner ACS_URCORNER upper right-hand corner ACS_VLINE vertical lineUsually on terminals using these symbols can draw pretty windows and shapes. One place to use this is the
wborder
function, which draws borders for a window. See the man page for details about
the parameters, but usually do it the following way wborder(win, 0, 0, 0, 0, 0, 0, 0, 0);will make a good looking window.
To draw a horizontal line across the window, do
whline(win, ACS_HLINE, ncolumns);
#include <signal.h>
void* resizeHandler(int);
int main(void) {
...
signal(SIGWINCH, resizeHandler);
...
}
void* resizeHandler(int sig)
{
int nh, nw;
getmaxyx(stdscr, nh, nw); /* get the new screen size */
...
}