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
initscr(); If your program
is going to write to several terminals, you should call newterm instead,
which is another story.
cbreak();
No echo. To suppress the automatic echoing of typed characters, you need to call
noecho();
keypad(stdscr, TRUE);
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.
0 <= y0 < LINES;
0 <= x0 < COLUMNS;
int h, w;
getmaxyx(stdscr, h, w);
wrefresh(win);
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.
int ch;
nodelay(stdscr, TRUE);
for (;;) {
if ((ch = getch()) == ERR) {
/* user hasn't responded
...
*/
}
else {
/* user has pressed a key ch
...
*/
}
}
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 send
For 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().
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.
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.
waddch(win, ch) a character value combined with
attribute. The other is setting the global window attribute.
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));
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().
0 <= n < COLORS
Example. 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_WHITE
You can use these names in init_pair() for
specifying foreground and background color.
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 line
Usually 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 */
...
}