【问题标题】:Printing while reading characters in C在 C 中读取字符时打印
【发布时间】:2012-04-19 13:15:04
【问题描述】:

我正在尝试编写一个简单的小 sn-p 代码来响应箭头键按下。 我知道 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'd 的东西)退格,我必须考虑到这一点。在那之后让其余的人排队也不错:)

【问题讨论】:

    标签: c stream newline printf carriage-return


    【解决方案1】:

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

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

    Capture characters from standard input without waiting for enter to be pressed

    【讨论】:

    • 这是有道理的。从那个链接所说的,似乎没有诅咒就没有办法做到这一点?如果可能的话,我想远离诅咒/ncurses。 POSIX 文件 I/O 是否允许我正在寻找的行为?
    【解决方案2】:

    您实际上只需要使用 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;
    }
    

    【讨论】:

    • 这是为我做的。它需要一些额外的黑魔法来处理显示输入和处理退格等我需要的方式,但它的工作量最少。谢谢!
    【解决方案3】:

    查看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,然后启用解析标志以查找字符的转义序列以代替单字符解析。

    【讨论】:

    • 我试图避免 ncurses/curses,所以我将尝试将我的读取功能切换到 POSIX 调用,看看是否有帮助(无缓冲输入和所有爵士乐)
    • 因此,在缓冲区中创建一个大小为 12 和 read 的输入读取缓冲区,然后在缓冲区中查找 0x1b(转义),当您看到:开始解析转义序列时,所有其他字符都应该被视为 ASCII。这不是太难。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    相关资源
    最近更新 更多