You can use the select
function to wait to see if there is something to read on stdin with a timeout that starts at 10 seconds. When it detects something, you read a character and check for errors or EOF. If all is good, then you call select
again, reducing the timeout by the elapsed time so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
struct timeval tdiff(struct timeval t2, struct timeval t1)
{
struct timeval result;
result.tv_sec = t2.tv_sec - t1.tv_sec;
result.tv_usec = t2.tv_usec - t1.tv_usec;
while (result.tv_usec < 0) {
result.tv_usec += 1000000;
result.tv_sec--;
}
return result;
}
int cmptimestamp(struct timeval t1, struct timeval t2)
{
if (t1.tv_sec > t2.tv_sec) {
return 1;
} else if (t1.tv_sec < t2.tv_sec) {
return -1;
} else if (t1.tv_usec > t2.tv_usec) {
return 1;
} else if (t1.tv_usec < t2.tv_usec) {
return -1;
} else {
return 0;
}
}
int main()
{
struct timeval cur, end, delay;
int rval, len = 0;
fd_set fds;
gettimeofday(&cur, NULL);
end = cur;
end.tv_sec += 10;
FD_ZERO(&fds);
FD_SET(0, &fds);
if (fcntl(0, F_SETFL, O_NONBLOCK) == -1) {
perror("fcntl failed");
exit(1);
}
do {
delay = tdiff(end, cur);
rval = select(1, &fds, NULL, NULL, &delay);
if (rval == -1) {
perror("select failed");
} else if (rval) {
char c;
len = read(0, &c, 1);
if (len == -1) {
perror("read failed");
} else if (len > 0) {
printf("c=%c (%d)\n", c, c);
} else {
printf("EOF\n");
}
} else {
printf("timeout\n");
}
gettimeofday(&cur, NULL);
} while (rval > 0 && len > 0 && cmptimestamp(end,cur) > 0);
return 0;
}
Note that this doesn't detect the keys as you press them, only after you've either pressed RETURN or stdin is closed.