More ANSI Code Cursor Manipulation

C is stream oriented, but in a terminal window you can use ANSI commands to provide more control. These commands can change text color as well as manipulate the cursor’s location, as covered in this month’s Exercise solution. The manipulation isn’t over yet!

Two of the many ANSI cursor control codes are:

  • ESC 7, to save the cursor’s current location
  • ESC 8, to restore the cursor’s saved location (from ESC 7)

When you save the cursor’s location and output text, the restore cursor location sequence moves the cursor back to its saved location. One of the ways to use this sequence is to erase a line of text, which was done in last week’s Lesson.

Suppose instead of backspacing to erase the line, you used the ANSI code ESC 7 to first save the cursor’s location, output text, then used ESC 8 to restore the location. The effect is similar, though to erase the line you must also output a new line of spaces or some other character. This last option is what I did in the following code:

2024_07_13-Lesson-a.c

#include <stdio.h>
#include <unistd.h>

int main()
{
    int x;

    printf("Prompt: ");
    printf("\e7");        /* save cursor position */

    /* output 20 Xs */
    for(x=0;x<20;x++)
        putchar('X');
    fflush(stdout);

    /* wait */
    sleep(1);

    /* output 20 Zs */
    printf("\e8");        /* restore cursor position */
    for(x=0;x<20;x++)
        putchar('Z');
    putchar('\n');

    return 0;
}

First a prompt is output and the cursor’s location saved, printf("\e7");. A line of 20 Xs is output, the buffer flushed (so that the output appears). The program pauses.

Next, the cursor’s location is restored, printf("\e8");, and a line of 20 Z characters is output.

The visual effect in the output is that a line of Xs appears, which is then overwritten with Z characters.

To erase the line and then output the Z characters, you must re-save the cursor’s location. Never assume that you use ESC 7 (to save the cursor’s location) once and then every subsequent use of ESC 8 (to restore) works. Here is the updated code:

2024_07_13-Lesson-b.c

#include <stdio.h>
#include <unistd.h>

int main()
{
    int x;

    printf("Prompt: ");
    printf("\e7");        /* save cursor position */

    /* output 20 Xs */
    for(x=0;x<20;x++)
        putchar('X');
    fflush(stdout);

    /* wait */
    sleep(1);

    /* erase the line */
    printf("\e8");        /* restore cursor position */
    printf("\e7");        /* save cursor position */
    for(x=0;x<20;x++)
        putchar(' ');
    fflush(stdout);

    /* wait */
    sleep(1);

    /* output 20 Zs */
    printf("\e8");        /* restore cursor position */
    for(x=0;x<20;x++)
        putchar('Z');
    putchar('\n');

    return 0;
}

In this program’s output, the row of Xs is output first. The program pauses one second. Then the line is erased. If you watch the output closely, you see the cursor restored. The code re-saves its location, then the line of Zs is output.

A good reference for ANSI codes can be found on GitHub. Even so, if you plan on doing this level of cursor manipulation I recommend that you look into the NCurses library. It provides for direct manipulation of the text screen as well as the keyboard. Plus, I’ve written a nifty eBook on the topic: click here.

Leave a Reply