4

I want to be able to use select() to work with entering a single char (no ENTER) from STDIN.

So, when a user press a single key, select() should return immediately, not waiting for the user to hit ENTER.

int main(void)
{
    fd_set rfds;
    struct timeval tv;
    int retval;

   /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);

   /* Wait up to 2 seconds. */
    tv.tv_sec = 2;
    tv.tv_usec = 0;

   retval = select(1, &rfds, NULL, NULL, &tv);

   if (retval == -1)
        perror("select()");
    else if (retval)
        printf("Data is available now.\n");
    else
        printf("No data within five seconds.\n");

   exit(EXIT_SUCCESS);
}

This works but you have to hit the ENTER key to finish. I just want the select not wait for the user to hit the key and ENTER.

Thanks.

JJ Liu
  • 1,351
  • 8
  • 20
  • 36

2 Answers2

3

I believe, when a key is entered into the terminal, it's buffered until you hit ENTER, i.e. as far as the program is concerned, you haven't entered anything. You might want to take a quick look at this question.

Community
  • 1
  • 1
Dan Fego
  • 13,644
  • 6
  • 48
  • 59
1

In a Unix-style environment, this can be accomplished through the termios functions.

You need to disable canonical mode, which is the terminal feature that allows for line-editing before your program sees input.

#include <termios.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    /* Declare the variables you had ... */
    struct termios term;

    tcgetattr(0, &term);
    term.c_iflag &= ~ICANON;
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &term);

    /* Now the rest of your code ... */
}

Catching the errors that could come from the tcgetattr and tcsetattr calls is left as an exercise for the reader.

David Brigada
  • 594
  • 2
  • 10
  • `term.c_iflag &= ~ICANON;` should be `term.c_lflag &= ~ICANON;`, according to the `man termios` page – origo Dec 22 '16 at 06:39