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

时间:2013-04-16 00:33:01

标签: c terminal ncurses xterm ansi-escape

我正在尝试使用以下代码检索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,这使我无法检索来自该计划:

terminal window

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

4 个答案:

答案 0 :(得分:4)

我要求光标位置。如果我在100ms之后没有回答(这是任意的)我认为控制台不是ansi。

<svg xmlns="http://www.w3.org/2000/svg" width="28px" height="36px">
    <path d="M 19 31 C 19 32.7 16.3 34 13 34 C 9.7 34 7 32.7 7 31 C 7 29.3 9.7 28 13 28 C 16.3 28 19 29.3 19 31 Z" fill="#000" fill-opacity=".2"/>
    <path d="M 13 0 C 9.5 0 6.3 1.3 3.8 3.8 C 1.4 7.8 0 9.4 0 12.8 C 0 16.3 1.4 19.5 3.8 21.9 L 13 31 L 22.2 21.9 C 24.6 19.5 25.9 16.3 25.9 12.8 C 25.9 9.4 24.6 6.1 22.1 3.8 C 19.7 1.3 16.5 0 13 0 Z" fill="#fff"/>
    <path d="M 13 2.2 C 6 2.2 2.3 7.2 2.1 12.8 C 2.1 16.1 3.1 18.4 5.2 20.5 L 13 28.2 L 20.8 20.5 C 22.9 18.4 23.8 16.2 23.8 12.8 C 23.6 7.07 20 2.2 13 2.2 Z" fill="#18d"/>
    <text x="13" y="19" font-size="12pt" font-weight="bold" text-anchor="middle" fill="#fff">${text}</text>
</svg>

答案 1 :(得分:3)

您的程序正在运行,但正在等待EOL角色。

scanf面向行,因此在处理之前等待新行。尝试运行程序,然后按回车键。

解决方案是使用不需要新行的其他内容来读取输入,然后使用sscanf来解析值。

您还需要使stdin无阻塞,否则在缓冲区已满或stdin关闭之前您将无法获得输入。请参阅此问题Making stdin non-blocking

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

答案 2 :(得分:0)

我相信你真的得到stdin的预期反应。但想象一下实际发生了什么:

  • 您将请求作为转义序列发送到stdout
  • 终端接收它并制定相应的答案作为转义序列
  • 答案发送到stdin
  • 调用scanf并通过shell重定向stdin,其中readline库用于交互式和可编辑的用户输入
  • readline 捕获转义序列,而不是将其传递给终端
  • readline重新制定它,没有ESC字符,以防止执行控制序列,而是通过仅使用可打印字符使其可读
  • 这个怪癖的答案达到了scanf,但为时已晚
  • 这个怪异的答案也回应了stdout,以便用户可以即时看到她输入的内容。

要避免这种情况,请改用getc()==fgetc(stdin))循环。如果遇到ESC(0x1B)而不是在字符串中转储以下字符,直到找到ESC序列的最终分隔符(在您的情况下为'n')。之后,您可以使用sscanf(esqString, formatString, ...)

但在遇到循环之前,您需要change with termios to raw mode(请查看下面的代码示例)。否则没有什么不同。

答案 3 :(得分:0)

#include <stdlib.h>
#include <stdio.h>
#include <conio.h>

void readCoord(void* row, void* col){
    int i = 0;
    char* input = malloc(10);
    printf("\e[6n");
    while(!_kbhit()) _sleep(1);
    while(_kbhit()) *(input + (i++)) = getch();
    *(input + i) = '\0';
    sscanf(input, "\e[%d;%dR", row, col);
}

void main(void){
    int i = 0, r, c;
    char* coord = malloc(10);
    printf("Hello");
    readCoord(&r , &c);
    printf("\nYour coordinate is (%d, %d)", c, r);
}

_kbhit()用于检测输入(DSR被视为在键盘上输入),并且 getch()从标准输入中读取和删除字符

该程序依赖于conio.h,它不是标准的,因此不建议用于便携式C程序。