3

我正在尝试编写一个简单的小代码片段来响应箭头键按下。我知道 up 由 ^[[A 表示,并且我有以下代码来检查该序列:

     while( 1 )
     {
         input_char = fgetc( stdin );

         if( input_char == EOF || input_char == '\n' )
         {
             break;
         }

         /* Escape sequence */
         if( input_char == 27 )
         {
             input_char = getc( stdin );

             if( input_char == '[' )
             {
                 switch( getc( stdin ) )
                 {
                     case 'A':
                     printf("Move up\n");
                     break;
                 }
             }
         }
     }

每当我点击“向上”时,转义序列 (^[[A) 就会出现在屏幕上,但“向上移动”直到我点击回车才会出现。

最终目标是用其他数据替换当前行上的文本,所以我尝试这样做

printf("\r%s", "New Text");

代替“上移”,但直到按下回车后它仍然不显示。

我在字符中阅读的方式有问题吗?

谢谢!

编辑快速说明,它适用于 *nix 系统。

解决方案 感谢大家的指点。我选择了 stepanbujnak 的解决方案,因为它相当简单。我注意到的一件事是,修改字符串(退格等)的键的许多行为与您的预期不同。它将通过在线上的任何内容(包括 printf 的东西)退格,我必须考虑到这一点。在那之后,让其余的人排队并不算太糟糕:)

4

3 回答 3

10

stdingetc(stdin)是行缓冲的,因此fgetc(stdin)在您按下之前看不到这些字符,ENTER请参阅此链接了解更多详细信息

编辑:如果你不想进入ncurses还有其他有用的方法,比如将终端设置为原始模式等来克服这个限制。检查这个不错的SO帖子

从标准输入中捕获字符而无需等待按下回车键

于 2012-04-19T13:22:44.263 回答
4

您实际上只需要使用termios禁用行缓冲

这是一个例子:

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

int main() {
  struct termios old_term, new_term;
  char c;

  /* Get old terminal settings for further restoration */
  tcgetattr(0, &old_term);

  /* Copy the settings to the new value */
  new_term = old_term;

  /* Disable echo of the character and line buffering */
  new_term.c_lflag &= (~ICANON & ~ECHO);
  /* Set new settings to the terminal */
  tcsetattr(0, TCSANOW, &new_term);

  while ((c = getchar()) != 'q') {
    printf("You pressed: %c\n", c);
  }

  /* Restore old settings */
  tcsetattr(0, TCSANOW, &old_term);

  return 0;
}
于 2012-04-19T13:45:35.103 回答
1

查看curses用于捕获转义序列(例如箭头键)的库。

http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/keys.html

在大多数系统键(如箭头键、主页、向上翻页、中断等)上都是转义键,它们使用转义序列来识别自己。像 0x1B + 序列这样的东西,如果你想原始捕获它,你需要直接从文件描述符中读取输入并监听序列。上面的替代方法是使用 ncurses。

在使用 curses 之外,以下说明了如何使用系统调用来完成此操作,例如read

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd = 0x0; /* STDIN */
    size_t bytes_read;
    char buf[12];

    bytes_read = read(fd, buf, 3);
    printf("%02x %02x %02x\n", buf[0], buf[1], buf[2]);
    return 0;
}

按UP后输出

Lukes-ASA-Macbook:tmp luke$ gcc -o out test.c
Lukes-ASA-Macbook:tmp luke$ ./out
^[[A
1b 5b 41

这应该让你上路。

您可以缓冲输入查找0x1b,然后启用解析标志来查找字符的转义序列,以代替单字符解析。

于 2012-04-19T13:29:40.857 回答