我正在尝试使用以下代码检索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 ,这使我无法从程序中检索它:

终端窗口

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

===============>>#1 票数:4

我要求光标位置。 如果我在100ms之后没有回答(这是任意的)我认为控制台不是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;
}

===============>>#2 票数:3 已采纳

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

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

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

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

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

===============>>#3 票数:0

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

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

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

但在遇到循环之前,您需要将termios更改为原始模式 (请参阅下面的代码示例)。 否则没有什么不同。

===============>>#4 票数: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程序。

  ask by Witiko translate from so

未解决问题?本站智能推荐: