使用ANSI转义序列获得终端尺寸?



在研究这个问题时,在评论中我发现有人提到ANSI转义码来获得终端尺寸。由于我将使用ANSI转义序列,我认为这将是比ioctl()getenv()更优雅的方式来获得终端大小。

这是一篇关于ioctl()的很好的文章,这是引起我兴趣的评论:

只是偶然发现了这个答案,当我意识到getenv("COLUMNS")在watch(1)下运行时完美地工作时,我的下巴掉了下来。因此,现在我有了一组回退,全部从TIOCWINSZ ioctl,到获取tenv(如果不是tty),到经典的ANSI转义"将光标移动到9999,9999和查询光标位置。最后一个适用于嵌入式系统的串行控制台:)

现在,我确实找到了一些关于ANSI的帖子(1,2),但没有一个回答我的具体问题-如何实际做到这一点?

使用这个图表,我推断为了将光标移动到最右和最下的位置,我需要CUP(CSI n ; m H) "光标位置"命令,这可能会翻译成类似x1b[9999;9999H的东西。这是一个简单的部分,因为它是一个命令。

第二部分是我有一个大问题。即使我可以推断出我需要DSR(CSI 6n)"设备状态报告";命令,并且它去x1b[6n,这个查询是如何工作的,即,我如何将数据存储在一个变量中,最好不中断在终端上显示的其他数据?

#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 ( "33[2J"); //clear screen
printf ( "33[9999;9999H"); // cursor should move as far as it can
printf ( "33[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] = '';
}
}
}
printf ( "33[1;1H"); // move to upper left corner
if ( 2 == sscanf ( in, "[%d;%d", &rows, &cols)) {
printf ( "%d rowsn", rows);
printf ( "%d colsn", cols);
}
// restore terminal settings
tcsetattr( STDIN_FILENO, TCSANOW, &original);
return 0;
}

最新更新