Home > Back-end >  Get terminal size using ANSI escape sequences?
Get terminal size using ANSI escape sequences?

Time:11-15

While researching this problem, in the comments I found someone mentioning ANSI escape codes to get the terminal size. Since I will be using ANSI escape sequences, I thought this would be a much more elegant way to get the terminal size than ioctl() or getenv().

Here is a very good post about ioctl(), and here is the comment that piqued my interest.

Now, I did find some posts (1, 2) about ANSI, but none answer the specific question I have - how to actually do it?

Using this chart, I deduced that in order to move the cursor to the extreme right and down position, I would need the CUP (CSI n ; m H) "Cursor Position" command, which would probably translate to something like \x1b[9999;9999H. This is the easy part since it is a command.

The second part is where I have a big problem. Even if I could deduce that I need the DSR(CSI 6n) "Device Status Report" command, and that it goes \x1b[6n, I still don't know how this querying works and where the data is stored and how can I take the data and store it in a variable, preferrably without disrupting the other data that is being displayed on the terminal.

Please help me figure out how to do it.
Thank you!

CodePudding user response:

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

#define SIZE 100

int main ( void) {
    char in[SIZE] = "";
    int each = 0;
    int ch = 0;
    int rows = 0;
    int cols = 0;
    struct termios original, changed;

    // change terminal settings
    tcgetattr( STDIN_FILENO, &original);
    changed = original;
    changed.c_lflag &= ~( ICANON | ECHO);
    changed.c_cc[VMIN] = 1;
    changed.c_cc[VTIME] = 0;
    tcsetattr( STDIN_FILENO, TCSANOW, &changed);

    printf ( "\033[2J"); //clear screen

    printf ( "\033[9999;9999H"); // cursor should move as far as it can

    printf ( "\033[6n"); // ask for cursor position
    while ( ( ch = getchar ()) != 'R') { // R terminates the response
        if ( EOF == ch) {
            break;
        }
        if ( isprint ( ch)) {
            if ( each   1 < SIZE) {
                in[each] = ch;
                each  ;
                in[each] = '\0';
            }
        }
    }

    printf ( "\033[1;1H"); // move to upper left corner
    if ( 2 == sscanf ( in, "[%d;%d", &rows, &cols)) {
        printf ( "%d rows\n", rows);
        printf ( "%d cols\n", cols);
    }

    // restore terminal settings
    tcsetattr( STDIN_FILENO, TCSANOW, &original);

    return 0;
}
  •  Tags:  
  • c
  • Related