10

I am trying to use select() to read keyboard input and I got stuck in that I do not know how to read from keyboard and use a file descriptor to do so. I've been told to use STDIN and STDIN_FILENO to approach this problem but I am still confused.
How can I do it?

rtruszk
  • 3,902
  • 13
  • 36
  • 53
drum
  • 5,416
  • 7
  • 57
  • 91
  • 4
    This is a fairly tricky thing to do if you are unfamiliar with POSIX programming in general. For one thing you have to set the terminal modes so the device doesn't buffer received characters. – antlersoft Jun 20 '11 at 22:25
  • 1
    No need to use select( ), unless of course it's part of a homework assignment. You can just fread( STDIN ... ) or read( STDIN_FILENO ... ). – Pete Wilson Jun 20 '11 at 22:26
  • 2
    If you need full terminal control (key presses etc.), you'll most likely be _much_ better off using a terminal library like **ncurses** (there are Windows ports, too). – Kerrek SB Jun 20 '11 at 22:37
  • Pete Wilson: fread(stdin ...) doesn't return as quickly as select, if a message arrives on a socket before the user hits a key. In Linux I used select. In Windows it's harder. – Windows programmer Jun 20 '11 at 23:33
  • Can you please clarify why would you need to go for select to read a keyboard input ? Normally select calls shall be used when you need to read from a range of descriptors or inputs as it allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). – Karthik Balaguru Oct 10 '14 at 05:49

3 Answers3

6

As it was already said, by using select you can just monitor e.g. stdin to check if the input data is already available for reading or not. If it is available, you can then use e.g. fgets to safely read input data to some buffer, like shown below:

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

int main(int argc, char *argv[])
{
    fd_set rfds;
    struct timeval tv;
    int retval, len;
    char buff[255] = {0};

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

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

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

    if (retval == -1){
        perror("select()");
        exit(EXIT_FAILURE);
    }
    else if (retval){
        /* FD_ISSET(0, &rfds) is true so input is available now. */

        /* Read data from stdin using fgets. */
        fgets(buff, sizeof(buff), stdin);

        /* Remove trailing newline character from the input buffer if needed. */
        len = strlen(buff) - 1;
        if (buff[len] == '\n')
            buff[len] = '\0';

        printf("'%s' was read from stdin.\n", buff);
    }
    else
        printf("No data within five seconds.\n");            

    exit(EXIT_SUCCESS);
}
jwaliszko
  • 16,942
  • 22
  • 92
  • 158
6

Youre question sounds a little confused. select() is used to block until input is available. But you do the actual reading with normal file-reading functions (like read,fread,fgetc, etc.).

Here's a quick example. It blocks until stdin has at least one character available for reading. But of course unless you change the terminal to some uncooked mode, it blocks until you press enter, when any characters typed are flushed into the file buffer (from some terminal buffer).

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

int main(void) {
    fd_set s_rd, s_wr, s_ex;
    FD_ZERO(&s_rd);
    FD_ZERO(&s_wr);
    FD_ZERO(&s_ex);
    FD_SET(fileno(stdin), &s_rd);
    select(fileno(stdin)+1, &s_rd, &s_wr, &s_ex, NULL);
    return 0;
}
luser droog
  • 18,988
  • 3
  • 53
  • 105
1

Perhaps, you want the way to peek keyboard input on "WINDOWS"? On windows, it can't get result from select() for STDIN. You should use PeekConsoleInput(). And use handle of stdin like following.

hStdin = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, ...

stdin may become pipe input. if so, you don't get any keyboard input.

P.S. If you don't ask about Windows, Sorry much.

mattn
  • 7,571
  • 30
  • 54