【发布时间】:2021-07-16 14:53:55
【问题描述】:
我正在编写一个程序,它可以根据字符在终端中的位置来更改字符的颜色。为了做到这一点,我需要至少获得一次光标位置。我不需要行,只需要列。
我查了一下,发现ANSI转义序列ESC[6n应该返回stdin中光标的当前位置,格式如下:ESC[<row>;<col>R。
我写了一个小测试程序(很大程度上受到this answer的启发),通过它我试图隔离这个转义序列的行为,它能够正确获取行号,但是由于某种原因,列总是1.
这是一段相关的C代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
int main() {
// This will shift the cursor right a few places
printf("some text");
struct termios restore;
tcgetattr(0, &restore);
// Disable flags in order to read the response
struct termios term;
tcgetattr(0, &term);
term.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &term);
// Write ANSI escape sequence for cursor position
write(1, "\033[6n", 4);
// Read back response
char buffer[16] = { 0 };
int idx = 0;
char ch;
while (ch != 'R') {
read(0, &ch, 1);
buffer[idx] = ch;
++idx;
}
buffer[idx] = '\0';
// Restore original settings
tcsetattr(0, TCSANOW, &restore);
// +1 because the first character is ESC
puts(buffer + 1);
return 0;
}
在我的终端 (mintty) 上,此代码具有以下输出:
$ ./main
some text[3;1R
该行确实是 3。但是,由于之前打印的文本,该列应该是 10,而不是 1。这种行为的原因是什么?我的代码有问题,还是终端有问题?或者,是否有另一种标准/更正确的方法来获取光标所在的列?
提前致谢。
【问题讨论】:
-
我希望这是因为
printf()的输出被缓冲了。之后尝试fflush(stdout)。 -
@ssbssa 是的,这实际上解决了问题。非常感谢!我建议写一个答案,以便我可以将其标记为已接受。
标签: c terminal ansi-escape termios