Skip to main content
ansicode
C

ANSI escape codes in C

C has no string-escape for ESC — write `\x1b` (hex) or `\033` (octal). `printf` and `fputs` are byte-clean on every platform; on Windows 10+ enable virtual terminal processing via `SetConsoleMode(..., ENABLE_VIRTUAL_TERMINAL_PROCESSING)` first. For anything resembling a TUI (menus, windows, mouse) link `ncurses` rather than hand-rolling.

Recommended libraries

  • ncurses

    The standard C TUI library — windows, panels, menus, forms, colour pairs. Handles terminfo lookup and raw input. Abstracts you away from emitting ANSI directly.

  • termios

    POSIX terminal-attributes API in `<termios.h>` — switch to raw mode, disable echo, turn off ICANON to read single keystrokes. Required when reading mouse / focus / bracketed-paste escapes back from the terminal.

  • termcap / terminfo (term.h)

    `setupterm()` + `tigetstr()` look up capabilities like `setaf`, `cup`, `civis` and return the matching escape string for the current `$TERM`.

  • notcurses

    Modern ncurses successor — TrueColor, sixel/Kitty graphics, Unicode-aware. Use for new code that needs more than ncurses can give.

Idiomatic patterns

Direct printf
#include <stdio.h>

int main(void) {
    printf("\x1b[1;31merror:\x1b[0m permission denied\n");
    return 0;
}
Terminfo lookup with tigetstr
#include <stdio.h>
#include <term.h>
#include <stdlib.h>

int main(void) {
    setupterm(NULL, 1, NULL);
    char *red   = tigetstr("setaf"); // takes one parameter
    char *reset = tigetstr("sgr0");
    putp(tparm(red, 1));
    fputs("error: permission denied", stdout);
    putp(reset);
    putchar('\n');
    return 0;
}
/* link with: cc prog.c -lncurses */
Hide cursor for a progress bar, always restore
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

static void restore(int sig) { (void)sig; printf("\x1b[?25h"); _exit(0); }

int main(void) {
    signal(SIGINT, restore);
    signal(SIGTERM, restore);
    printf("\x1b[?25l");  // hide cursor
    for (int i = 0; i <= 100; i++) {
        printf("\r\x1b[K%d%%", i);
        fflush(stdout);
        usleep(20000);
    }
    printf("\n");
    printf("\x1b[?25h");  // show cursor
    return 0;
}
Raw mode for reading escape input
#include <termios.h>
#include <unistd.h>
#include <stdio.h>

int main(void) {
    struct termios orig, raw;
    tcgetattr(STDIN_FILENO, &orig);
    raw = orig;
    raw.c_lflag &= ~(ICANON | ECHO);     // no line-buffering, no echo
    tcsetattr(STDIN_FILENO, TCSANOW, &raw);

    /* now reads of stdin deliver single bytes including ESC sequences */
    int c;
    while ((c = getchar()) != 'q') { printf("0x%02x ", c); fflush(stdout); }

    tcsetattr(STDIN_FILENO, TCSANOW, &orig);  // always restore
    return 0;
}

Related sequences

Other languages