在 fd 0 上调用 "select" 需要 <Enter> 触发
Calling "select" on fd 0 requires <Enter> to fire
我正在尝试使用“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}?
(注意:我知道还有其他方法可以做到这一点,但在我实际的应用程序中,我 select 在一些套接字和 fd0 上,但为了简洁我省略了它)
我根据@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 );
}
我正在尝试使用“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}?
(注意:我知道还有其他方法可以做到这一点,但在我实际的应用程序中,我 select 在一些套接字和 fd0 上,但为了简洁我省略了它)
我根据@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 );
}