Table of Contents

curses.h

Writing raw escape sequences to position the cursor and handle keyboard input is painful and terminal-specific. curses.h (typically ncurses) abstracts all of that away: you tell it to put text at row 5, column 10, and it figures out the right escape sequence for whatever terminal the user has. It also tracks what is on screen so it only sends the changes on each refresh, rather than redrawing everything.

The core abstractions are windows (WINDOW *): rectangular regions of the screen you can draw into independently. stdscr is the default full-screen window. newwin(h, w, y, x) creates a subwindow; wrefresh(win) flushes it to the terminal.

move(y, x)              // move cursor on stdscr
mvaddch(y, x, ch)       // write a character at (y, x)
mvaddstr(y, x, str)     // write a string
mvprintw(y, x, fmt, .) // formatted write at (y, x)
getmaxyx(win, h, w)     // get terminal dimensions into h, w
attron(A_BOLD)          // enable bold attribute
attroff(A_BOLD)
init_pair(1, COLOR_RED, COLOR_BLACK)  // define a colour pair
attron(COLOR_PAIR(1))                 // switch to colour pair 1

ncurses consults the TERM environment variable and the terminfo database to translate portable abstractions into the right escape sequences for xterm, VT100, the Linux console, and so on.

The header is <ncurses.h> on Linux, but many projects use #include <curses.h>, which is typically a symlink or compatibility header that pulls in the same declarations.

Practice

// compile: gcc -o cursesdemo cursesdemo.c -lncurses
// run: ./cursesdemo   (requires a terminal, not a pipe)
// description: draw text at a specific position, wait for a keypress, then exit
 
#include <curses.h>
 
int main(void) {
    initscr();             // take control of terminal
    cbreak();              // get keypresses without waiting for Enter
    noecho();              // don't echo typed characters
    keypad(stdscr, TRUE);  // enable arrow keys and function keys
 
    int h, w;
    getmaxyx(stdscr, h, w);
 
    mvprintw(h/2,     w/2 - 10, "Hello, ncurses!");
    mvprintw(h/2 + 1, w/2 - 10, "Terminal: %d x %d", w, h);
    mvprintw(h/2 + 2, w/2 - 10, "Press any key to exit...");
    refresh();
 
    getch();
    endwin();
    return 0;
}

endwin() restores the terminal to normal mode — always call it before exiting, or the terminal will be left in raw mode with echo disabled. If you want to see the effect of not calling it, comment it out: the terminal will need a manual reset command to recover.