How to use select() to read input from keyboard in C
Asked Answered
G

3

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?

Gid answered 20/6, 2011 at 22:17 Comment(5)
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.Anxious
No need to use select( ), unless of course it's part of a homework assignment. You can just fread( STDIN ... ) or read( STDIN_FILENO ... ).Misdeal
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).Unsearchable
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.Brumal
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).Salpa
N
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;
}
Nidanidaros answered 21/6, 2011 at 2:36 Comment(1)
Thank you very much, this really clarified my question.Gid
V
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);
}
Violist answered 2/9, 2013 at 13:29 Comment(0)
B
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.

Bacterium answered 21/6, 2011 at 3:14 Comment(1)
Windows didn't even occur to me. Nice save: cover all angles.Nidanidaros

© 2022 - 2024 — McMap. All rights reserved.