Move the cursor in a C program Move the cursor in a C program shell shell

Move the cursor in a C program


Using termios and console-codes (VT100 compatible - not portable):

#include <stdio.h>#include <string.h>#include <termios.h>#include <unistd.h>#define cursorforward(x) printf("\033[%dC", (x))#define cursorbackward(x) printf("\033[%dD", (x))#define KEY_ESCAPE  0x001b#define KEY_ENTER   0x000a#define KEY_UP      0x0105#define KEY_DOWN    0x0106#define KEY_LEFT    0x0107#define KEY_RIGHT   0x0108static struct termios term, oterm;static int getch(void);static int kbhit(void);static int kbesc(void);static int kbget(void);static int getch(void){    int c = 0;    tcgetattr(0, &oterm);    memcpy(&term, &oterm, sizeof(term));    term.c_lflag &= ~(ICANON | ECHO);    term.c_cc[VMIN] = 1;    term.c_cc[VTIME] = 0;    tcsetattr(0, TCSANOW, &term);    c = getchar();    tcsetattr(0, TCSANOW, &oterm);    return c;}static int kbhit(void){    int c = 0;    tcgetattr(0, &oterm);    memcpy(&term, &oterm, sizeof(term));    term.c_lflag &= ~(ICANON | ECHO);    term.c_cc[VMIN] = 0;    term.c_cc[VTIME] = 1;    tcsetattr(0, TCSANOW, &term);    c = getchar();    tcsetattr(0, TCSANOW, &oterm);    if (c != -1) ungetc(c, stdin);    return ((c != -1) ? 1 : 0);}static int kbesc(void){    int c;    if (!kbhit()) return KEY_ESCAPE;    c = getch();    if (c == '[') {        switch (getch()) {            case 'A':                c = KEY_UP;                break;            case 'B':                c = KEY_DOWN;                break;            case 'C':                c = KEY_LEFT;                break;            case 'D':                c = KEY_RIGHT;                break;            default:                c = 0;                break;        }    } else {        c = 0;    }    if (c == 0) while (kbhit()) getch();    return c;}static int kbget(void){    int c;    c = getch();    return (c == KEY_ESCAPE) ? kbesc() : c;}int main(void){    int c;    while (1) {        c = kbget();        if (c == KEY_ENTER || c == KEY_ESCAPE || c == KEY_UP || c == KEY_DOWN) {            break;        } else        if (c == KEY_RIGHT) {            cursorbackward(1);        } else        if (c == KEY_LEFT) {            cursorforward(1);        } else {            putchar(c);        }    }    printf("\n");    return 0;}


A simple example using ANSI escape sequences:

#include <stdio.h>int main(){    char *string = "this is a string";    char input[1024] = { 0 };    printf("%s", string);    /* move the cursor back 5 spaces */    printf("\033[D");    printf("\033[D");    printf("\033[D");    printf("\033[D");    printf("\033[D");    fgets(input, 1024, stdin);    return 0;}

To do very much useful the terminal needs to be put into canonical mode with termios.h and/or curses.h/ncurses.h. This way the backspace key code can be caught and responded to immediately and the buffer drawn to screen accordingly. Here is an example of how to set the terminal into canonical mode with tcsetattr():

struct termios info;tcgetattr(0, &info);info.c_lflag &= ~ICANON;info.c_cc[VMIN] = 1;info.c_cc[VTIME] = 0;tcsetattr(0, TCSANOW, &info);

Another option might be to use the readline() or editline() library. To use the readline library specify -lreadline to your compiler. The following code snippet can be compiled with

cc -lreadline some.c -o some#include <stdio.h>#include <readline/readline.h>#include <readline/history.h>int main(){    char *inpt;    int i = 0;    while ( i < 10 )    {        inpt = readline("Enter text: ");        add_history(inpt);        printf("%s", inpt);        printf("\n");        ++i;    }    return 0;

}


Moves cursor right and left. stops input on newline or too many characters

#include <stdio.h>#include <string.h>#include <termios.h>#include <unistd.h>#include <ctype.h>#include <sys/select.h>#include <sys/ioctl.h>#define ESC          27#define INSERT       50#define DELETE       51#define PGUP         53#define PGDN         54#define ARROWRIGHT   67#define ARROWLEFT    68#define END          70#define HOME         72#define OTHER        79#define BRACKETLEFT  91#define TILDE       126#define BACKSPACE   127#define SIZE         30static const int STDIN = 0;int kbhit(void){    int bytesWaiting;    ioctl(STDIN, FIONREAD, &bytesWaiting);    return bytesWaiting;}int main ( ) {    char input[SIZE] = {'\0'};    int insert = 0;    int each = 0;    int end = 0;    int to = 0;    int ch = 0;    int row = 0;    int col = 0;    struct termios oldattr, newattr;    //set terminal    tcgetattr( STDIN, &oldattr );    newattr = oldattr;    newattr.c_lflag &= ~( ICANON | ECHO );    tcsetattr( STDIN, TCSANOW, &newattr );    setbuf(stdin, NULL);    printf ( "\033[2J");//clear screen    printf ( "\033[25;1H");//move cursor to row 25 col 1    printf ( "OVW");    printf ( "\033[9;1H");//move cursor to row 9 col 1    printf ( "enter your text ");//prompt    //printf ( "%s", input);    printf ( "\033[9;17H");//move cursor to row 9 col 17    col = 17;    row = 9;    while ( ( ch = getchar ()) != '\n') {        if ( isprint( ch)) {            if ( insert && each < end && end < SIZE-3) {                //expand                end++;                for ( to = end; to >= each; to--) {                    input[to + 1] = input[to];                }                printf ( "\033[9;17H");//move cursor to row 9 col 12                printf ( "\033[K");//erase to end of line                printf ( "%s", input);            }            printf ( "\033[%d;%dH", row, col);            printf ( "%c", ch);            input[each] = ch;            each++;            if ( each > end) {                end = each;            }            col++;            if ( each == end) {                input[each] = '\0';            }            if ( each >= SIZE-1) {                break;            }            continue;        }        if ( ch == BACKSPACE) {            if ( each) {                each--;                col--;                //contract                for ( to = each; to <= end; to++) {                    input[to] = input[to + 1];                }                end--;                printf ( "\033[9;17H");//move cursor to row 1 col 7                printf ( "\033[K");//erase to end of line                printf ( "%s", input);                printf ( "\033[%d;%dH", row, col);            }        }        if ( ch == ESC) {            if ( !kbhit ( )) {                continue;            }            ch = getchar ( );            if ( ch == OTHER) {                ch = getchar ( );                if ( ch == HOME) {                    col -= each;                    each = 0;                    printf ( "\033[%d;%dH", row, col);                    ch = getchar ( );                }                if ( ch == END) {                    col += end - each;                    each = end;                    printf ( "\033[%d;%dH", row, col);                    ch = getchar ( );                }            }            if ( ch == BRACKETLEFT) {                ch = getchar ( );                if ( ch == INSERT) {                    ch = getchar ( );                    if ( ch == TILDE) {                        insert = !insert;                        printf ( "\033[25;1H");//move cursor to row 25 col 1                        if ( insert) {                            printf ( "INS");                        }                        else {                            printf ( "OVW");                        }                        printf ( "\033[%d;%dH", row, col);                    }                }                if ( ch == DELETE) {                    ch = getchar ( );                    if ( ch == TILDE) {                        //contract                        for ( to = each; to <= end; to++) {                            input[to] = input[to + 1];                        }                        end--;                        printf ( "\033[9;17H");//move cursor to row 10 col 1                        printf ( "\033[K");//erase to end of line                        printf ( "%s", input);                        printf ( "\033[%d;%dH", row, col);                    }                }                if ( ch == ARROWRIGHT) {                    if ( each < end) {                        printf ( "\033[C");//cursor right                        each++;                        col++;                    }                }                if ( ch == ARROWLEFT) {                    if ( each) {                        printf ( "\033[D");//cursor left                        each--;                        col--;                    }                }            }            else {                ungetc ( ch, stdin);            }        }    }    printf ( "\n\ninput was [%s]\n", input);    printf ( "\n\nbye\n");    //restore terminal    tcsetattr( STDIN, TCSANOW, &oldattr );    return 0;}