读取设备状态报告ANSI转义序列回复

Wit*_*iko 8 c terminal ncurses xterm ansi-escape

我正在尝试使用以下代码检索VT100终端中光标的坐标:

void getCursor(int* x, int* y) {
  printf("\033[6n");
   scanf("\033[%d;%dR", x, y);
}
Run Code Online (Sandbox Code Playgroud)

我正在使用以下ANSI转义序列:

设备状态报告 - ESC [6n

将光标位置报告给应用程序(就像键入键盘一样)ESC [n; mR,其中n是行,m是列.

代码编译并发送ANSI序列,但是,在接收到它之后,终端将^[[x;yR字符串打印到stdout而不是stdin使我无法从程序中检索它:

终端窗口

显然,字符串是为程序指定的,所以我必须做错误的事情.有人知道它是什么吗?

小智 6

我要求光标位置。如果我在 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;
}
Run Code Online (Sandbox Code Playgroud)


Cra*_*aig 5

您的程序正在运行,但正在等待 EOL 字符。

scanf是面向行的,因此它在处理之前等待新行。尝试运行您的程序,然后按 Enter 键。

解决方案是使用其他不需要换行的东西来读取输入,然后使用 sscanf 解析出值。

您还需要使标准输入非阻塞,否则在缓冲区已满或标准输入关闭之前您将无法获得输入。看到这个问题Making stdin non-blocking

您还应该fflush(stdout);在 printf 之后调用以确保它确实被写入(printf 通常是行缓冲的,因此如果没有换行符,它可能不会刷新缓冲区)。

  • 有没有办法让 ANSI 命令根本不将 `^[[x;yR` 写入终端?我想默默地检索坐标,而不会对终端屏幕进行任何可见的更改。但这会写入终端(创建文本 GUI 时不希望出现),从而改变光标的坐标(这使得它完全无用)。 (2认同)
  • 当然可以,但是 ncurses 完全是过时的软件。这就是为什么我正在编写自己的轻量级 ANSI 转义序列库,它仅支持 VT100。但是,是的,似乎我只需要 dl ncurses 并尝试对其进行逆向工程即可找到该问题的解决方案。 (2认同)