I was trying to implement this great response to my question about getting the terminal size with ANSI escape sequences. It didn't work, so I tried to see what the differences between the proposed code and mine were. I don't know if it is the main problem, but I followed the breadcrumbs to the one obvious differences (which I have also been able to replicate in a minimal example) - I use VMIN = 0, and the solution uses VMIN = 1.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>
#define SIZE 100
int main ( void) {
int ch = 0;
int i = 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[9999;9999H"); // cursor should move as far as it can
printf ( "\033[6n"); // ask for cursor position
printf ( "\033[2J"); //clear screen
printf ( "\033[1;1H"); // move to upper left corner
while ( ( ch = getchar ()) != 'R') { // R terminates the response
if ( EOF == ch)
break;
if ( isprint ( ch)) // print out only normal chars to not mess up display
printf("stdin[%d]\t==\t%d\t==\t%c\n", i, ch, ch);
else
printf("stdin[%d]\t==\t%d\t==\t\n", i, ch);
i ;
}
// restore terminal settings
tcsetattr( STDIN_FILENO, TCSANOW, &original);
return 0;
}
Here is a slightly shortened version of the proposed solution which showcases the problem. If you keep VMIN at 1, everything will work fine. However, if you set it to 0, you will lose the first part of ESC[rows;colsR
, and it will only get printed out after the program finishes.
My actual code is too big and fragmented to post here, but what I am experiencing is a total freeze of the program if I set VMIN to 1 (I am read()-ing STDIN(1) in an infinite loop), and nothing happens when I run \033[6n
(as if stdin is empty - I can get nothing out with getchar nor fread nor read)
If you have any info about this peculiarity, please share.
Thank you.
CodePudding user response:
Try a function that modifies the terminal settings, requests the cursor position, captures the position and restores the terminal settings.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>
#define SIZE 100
void getscrnsize ( struct termios *set, int *row, int *col) {
struct termios temp;
temp = *set;
temp.c_cc[VMIN] = 1;
tcsetattr( STDIN_FILENO, TCSANOW, &temp); // use temp settings
printf ( "\033[6n"); // ask for cursor position
scanf ( "\033[%d;%dR", row, col);
tcsetattr( STDIN_FILENO, TCSANOW, set); // restore settings
}
int main ( void) {
int row = 0;
int col = 0;
struct termios original, changed;
// change terminal settings
tcgetattr( STDIN_FILENO, &original);
changed = original;
changed.c_lflag &= ~( ICANON | ECHO);
changed.c_cc[VMIN] = 0;
changed.c_cc[VTIME] = 0;
tcsetattr( STDIN_FILENO, TCSANOW, &changed);
printf ( "\033[9999;9999H"); // cursor should move as far as it can
getscrnsize ( &changed, &row, &col);
printf ( "\033[2J"); //clear screen
printf ( "\033[1;1H"); // move to upper left corner
printf ( "rows %d\tcols %d\n", row, col);
// restore terminal settings
tcsetattr( STDIN_FILENO, TCSANOW, &original);
return 0;
}
CodePudding user response:
ncurses
is another option.
link with -lncurses
This uses the pipe character '|'
to exit.
#include <stdio.h>
#include <ncurses.h>
int main ( void) {
int ch = 0;
int row = 0;
int col = 0;
initscr ( );
halfdelay ( 2); // tenths of a second that getch waits for input
noecho ( );
getmaxyx ( stdscr, row, col);
move ( 1, 1);
printw ( "row %d\tcol %d\n", row, col);
while ( ( ch = getch ( ))) {
if ( ERR != ch) {
printw ( "%c", ch);
if ( '|' == ch) {
break;
}
}
}
getyx ( stdscr, row, col);
printw ( "\nrow %d \tcol %d", row, col);
printw ( "\n\npress enter\n");
while ( ( ch = getch ( ))) {
if ( '\n' == ch) {
break;
}
}
endwin ( );
return 0;
}