【问题标题】:Calling "select" on fd 0 requires <Enter> to fire在 fd 0 上调用“select”需要 <Enter> 触发
【发布时间】:2022-01-14 21:51:35
【问题描述】:

我正在尝试使用“select()”来测试一个键是否被敲击然后读取它。它有点工作,但只有如果在字符后按下 {Enter}。
示例代码如下:

//  selectkb.c

#include <stdio.h>
#include <sys/select.h>

//@ Main program
int
main(
  int argc,
  char **argv)
{
    int n;
    fd_set readfds;

    FD_ZERO( &readfds );
    FD_SET( 0, &readfds );
    printf( "calling select on fd 0...\n" );
    n = select( 1, &readfds, NULL, NULL, NULL );
    printf( "select reports %d fd ready\n", n );

    if( FD_ISSET( 0, &readfds ) ) {
      char c;
      printf( "select reports fd 0 ready.\n" );
      c = getchar();
      printf( "getchar returned \"%c\"\n", c );
    }
    else {
      printf( "fd 0 not ready.\n" );
    }

    return( 0 );
}

如果我按 A 没有任何反应, 但如果我按 A{Enter},则输出为:

calling select on fd 0...
select reports 1 fd ready
select reports fd 0 ready.
getchar returned "A"

如果我按 ABC{Enter} 输出是一样的

为什么需要 {Enter}?

(注意:我知道还有其他方法可以做到这一点,但在我的实际应用中,我选择了一些套接字以及 fd0,但为了简洁起见,我省略了)

【问题讨论】:

  • 这能回答你的问题吗? Confusion about raw vs. cooked terminal modes?
  • 具体来说,在熟模式下,终端(或伪 tty)实际上不会将输入发布到您的stdin,直到用户按下 Enter。
  • @Ben,我认为你一针见血。现在我必须弄清楚如何解决它......

标签: linux select keystroke


【解决方案1】:

我根据@Ben Voigt 的回复找到了解决方案。显然,默认情况下,终端在“规范”(熟)模式下运行,其中内核在按下 {Enter} 之前不会传递字符。解决方案是将终端设置为非规范(原始)模式。最简单的方法是使用 termios,如下面的更新代码所示。完成后,字符会一个接一个地传递,并且 select() 会按照我的意愿行事。

//  selectkb.c

#include <stdio.h>
#include <sys/select.h>
#include <termios.h>


//@ Main program
int
main(
  int argc,
  char **argv)
{
    int n;
    fd_set readfds;
    struct termios attr;

    // SET RAW MODE
    tcgetattr( 0, &attr );
    attr.cflag &= ~ICANON;
    tcsetattr( 0, TCSANOW, &attr );

    FD_ZERO( &readfds );
    FD_SET( 0, &readfds );
    printf( "calling select on fd 0...\n" );
    n = select( 1, &readfds, NULL, NULL, NULL );
    printf( "select reports %d fd ready\n", n );

    if( FD_ISSET( 0, &readfds ) ) {
      char c;
      printf( "select reports fd 0 ready.\n" );
      c = getchar();
      printf( "getchar returned \"%c\"\n", c );
    }
    else {
      printf( "fd 0 not ready.\n" );
    }

    return( 0 );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-13
    • 2023-03-30
    • 2016-02-12
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 2014-05-06
    相关资源
    最近更新 更多