读取设备状态报告ANSI转义序列回复(Reading the Device Status Repor

2019-08-31 07:22发布

我试图获取光标的坐标中使用下面的代码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为我从节目检索:

显然,该字符串指定的程序,虽然如此,我一定要正确地做事。 有谁知道它是什么?

Answer 1:

你的程序是工作,但正在等待EOL字符。

scanf是面向行的,因此等待处理之前,新的生产线。 尝试运行您的程序,然后按下回车键。

该解决方案是使用别的东西,并不需要一个新的生产线来读取输入,然后使用sscanf的解析值了。

您还需要进行标准输入非阻塞或直到缓冲区已满或标准输入被关闭,你不会得到输入。 看到这个问题制作标准输入非阻塞

你也应该调用fflush(stdout); 后您的printf,以确保其实际写入(printf的往往是行缓冲,所以没有换行可能不刷新缓存)。



Answer 2:

我问光标位置。 如果我没有答案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;
}


Answer 3:

我相信,你真的在​​标准输入预期的响应。 但是想象一下,到底发生了什么:

  • 你发送一个请求作为转义序列到stdout
  • 终端接收它并制定一个相应的答案为转义序列以及
  • 答案发送到标准输入
  • scanf函数被调用,标准输入通过其中readline库被用于交互式和可编辑的用户输入的壳重定向
  • readline的捕获转义序列,而不是将它传递给终端
  • 没有ESC字符,以防止控制序列的执行的readline重新制定它而是使它可读通过仅使用可打印字符
  • 在挑起答案达到scanf函数,但为时已晚
  • 在挑起答案也反映到标准输出,使用户可以即时看到她打字。

为了避免这种使用getc() ==fgetc(stdin) )循环代替。 如果遇到ESC( 0x1B比字符串转储以下字符),直到你找到ESC序列的最后一个分隔符(在你的案件'n' )。 之后,你可以使用sscanf(esqString, formatString, ...)

但是,你遇到你需要在循环之前与termios的原始模式改变 (看下面的代码示例)。 否则不会有任何不同。



文章来源: Reading the Device Status Report ANSI escape sequence reply