我试图获取光标的坐标中使用下面的代码VT100终端:
void getCursor(int* x, int* y) {
printf("\033[6n");
scanf("\033[%d;%dR", x, y);
}
我使用下面的ANSI转义序列:
设备状态报告 - ESC [6N
报告光标位置到应用程序作为(如同在键盘上键入)ESC [N; MR,其中n是行和m为列。
代码编译和ANSI序列被发送,但在接收到它时,终端打印^[[x;yR
字符串到stdout
,而不是stdin
使它IMPOSIBLE为我从节目检索:
显然,该字符串指定的程序,虽然如此,我一定要正确地做事。 有谁知道它是什么?
你的程序是工作,但正在等待EOL字符。
scanf
是面向行的,因此等待处理之前,新的生产线。 尝试运行您的程序,然后按下回车键。
该解决方案是使用别的东西,并不需要一个新的生产线来读取输入,然后使用sscanf的解析值了。
您还需要进行标准输入非阻塞或直到缓冲区已满或标准输入被关闭,你不会得到输入。 看到这个问题制作标准输入非阻塞
你也应该调用fflush(stdout);
后您的printf,以确保其实际写入(printf的往往是行缓冲,所以没有换行可能不刷新缓存)。
我问光标位置。 如果我没有答案100毫秒后(这是任意的),我想控制台是不是ANSI。
/* This function tries to get the position of the cursor on the terminal.
It can also be used to detect if the terminal is ANSI.
Return 1 in case of success, 0 otherwise.*/
int console_try_to_get_cursor_position(int* x, int *y)
{
fd_set readset;
int success = 0;
struct timeval time;
struct termios term, initial_term;
/*We store the actual properties of the input console and set it as:
no buffered (~ICANON): avoid blocking
no echoing (~ECHO): do not display the result on the console*/
tcgetattr(STDIN_FILENO, &initial_term);
term = initial_term;
term.c_lflag &=~ICANON;
term.c_lflag &=~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &term);
//We request position
print_escape_command("6n");
fflush(stdout);
//We wait 100ms for a terminal answer
FD_ZERO(&readset);
FD_SET(STDIN_FILENO, &readset);
time.tv_sec = 0;
time.tv_usec = 100000;
//If it success we try to read the cursor value
if (select(STDIN_FILENO + 1, &readset, NULL, NULL, &time) == 1)
if (scanf("\033[%d;%dR", x, y) == 2) success = 1;
//We set back the properties of the terminal
tcsetattr(STDIN_FILENO, TCSADRAIN, &initial_term);
return success;
}
我相信,你真的在标准输入预期的响应。 但是想象一下,到底发生了什么:
- 你发送一个请求作为转义序列到stdout
- 终端接收它并制定一个相应的答案为转义序列以及
- 答案发送到标准输入
- scanf函数被调用,标准输入通过其中readline库被用于交互式和可编辑的用户输入的壳重定向
- readline的捕获转义序列,而不是将它传递给终端
- 没有ESC字符,以防止控制序列的执行的readline重新制定它而是使它可读通过仅使用可打印字符
- 在挑起答案达到scanf函数,但为时已晚
- 在挑起答案也反映到标准输出,使用户可以即时看到她打字。
为了避免这种使用getc()
==fgetc(stdin)
)循环代替。 如果遇到ESC( 0x1B
比字符串转储以下字符),直到你找到ESC序列的最后一个分隔符(在你的案件'n'
)。 之后,你可以使用sscanf(esqString, formatString, ...)
但是,你遇到你需要在循环之前与termios的原始模式改变 (看下面的代码示例)。 否则不会有任何不同。