How to get character from keyboard within a period of time

Mar 24, 2012 at 1:44am
Hi guys. I'm having a problem with my project. I'm writing a quiz game that player must type the answer in the console windows within 10 seconds. So how can i use the cin>>, scanf(), or are any other way to get character from the keyboard within 10s, and after that, the program will fill the default answer and continue to the next step without waiting forever?

ps: Sorry because my English is not good!
Mar 24, 2012 at 2:12am
Hmm, there are several answers to this, but the simplest is to only timeout if the user does not press any keys:
See http://cplusplus.com/forum/general/64802/#msg350595

The timeout is in milliseconds, so ten seconds is 10000. You might want to do a loop to give some countdown feedback.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;

// iskeypressed()           - is a key press waiting to be read right now?
// iskeypressed( 1000 )     - wait up to a second for a key press before timeout
//                            (specify max wait timeout in milliseconds)
// iskeypressed( INFINITE ) - wait for a key press with no timeout (i.e. forever)

#ifdef _WIN32

#define NOMINMAX
#include <windows.h>

bool iskeypressed( unsigned timeout_ms = 0 )
  {
  return WaitForSingleObject(
    GetStdHandle( STD_INPUT_HANDLE ),
    timeout_ms
    ) == WAIT_OBJECT_0;
  }

#else

#include <unistd.h>
#include <poll.h>

#define INFINITE (-1)

bool iskeypressed( unsigned timeout_ms = 0 )
  {
  struct pollfd pls[ 1 ];
  pls[ 0 ].fd     = STDIN_FILENO;
  pls[ 0 ].events = POLLIN | POLLPRI;
  return poll( pls, 1, timeout_ms ) > 0;
  }

#endif

bool countdown( unsigned seconds )
  {
  for (unsigned n = 0; n < seconds; n++)
    {
    cout << "\r" << setw( 2 ) << (seconds - n) << "> " << flush;
    if (iskeypressed( 1000 )) return true;
    }
  cout << "\r" << setw( 2 ) << 0 << "> " << flush;
  return false;
  }

int main()
  {
  cout << "What is my favorite color?\n";
  string answer = "orange";
  if (countdown( 10 )) getline( cin, answer );
  else                 cout << answer << "\n";

  if (answer == "green")
    cout << "Good job, my favorite color is green!\n";
  else
    cout << "Alas, you guessed wrong.\n";

  return 0;
  }

Notice that the user can still cause the game to wait forever by beginning to answer, but not pressing ENTER.

If you must have a more advanced timeout than that, let me know.
Mar 24, 2012 at 3:51am
cout << "\r" produces artifacts in the input.
Every second it sends me to the beginning, overwriting what I previously inputted.
Notice that the user can still cause the game to wait forever by beginning to answer, but not pressing ENTER.
Didn't observe that
Mar 24, 2012 at 4:21pm
I am exceedingly curious as to why my post was reported, and why, exactly?

Did I not directly answer the OP's exact question?
Did I abuse him?
Did I suggest incorrect or bad code?
Did I not explain the limitations of the code and offer to provide a more advanced example if this did not suffice?
Did I abuse the forum policies in any way?

@ne555
If you run the program exactly as I listed it above, the instant you press a key, the function terminates and returns you to main -- leaving nothing to be overwritten. If you are getting odd artifacts in your output, your terminal is one of: broken, improperly configured, or too old/dumb to understand one of the oldest, most universally-understood control codes in existence.

The purpose of "\r" is to return the cursor to the beginning of the line, so that the countdown is updated.
Mar 24, 2012 at 5:36pm
poll() is returning 0 till I press Enter.

Edit: http://www.cplusplus.com/forum/general/5304/#msg23940 needed to configure termios
Last edited on Mar 24, 2012 at 5:54pm
Mar 24, 2012 at 6:40pm
Ah, yes, that makes sense.
Mar 24, 2012 at 11:08pm
i tried that and it just waits for ever, doesn't do anything after 10 seconds, until i hit enter
Mar 24, 2012 at 11:54pm
Hmm... what OS/CC/and TERM?
Mar 25, 2012 at 12:25am
windows vista or 7, whats cc and term?

anywho no idea what is waitforsingleobject but i did get this to work:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <string>
#include <windows.h>
#include <iomanip>
using namespace std;

bool hasanykeybeenpressed()
{
    for (int i = 0; i < 255; ++i)
        if (GetAsyncKeyState(i))
            return true;
    return false;
}

bool my_timer(int seconds)
{
    int start_t = time(0);
    start_t %= 1000;
    int end = start_t + seconds; ++end;
    int previous = start_t;
    for(;;)
        {
            int local = time(0);
            local %= 1000;
            if (local > previous)
                {
                    previous = local;
                    int stp = time(0); stp %= 1000;
                    int check = end -stp;
                    if (check < 0)
                        return false;
                    cout << "\r" << setw(2) << (check) << "> " << flush;
                    if (hasanykeybeenpressed())
                        return true;
                }
        }
    return false;
}

int main()
{
    cout << "What is my favorite color?\n";
    string answer = "orange";
    bool pass = false;
    if (my_timer(10))
        {
            getline( cin, answer );
        }
    else pass = false;
    if (answer == "green")
        pass = true;
    if (pass == true)
        cout << "\nGood job, my favorite color is green!\n";
    else
        cout << "\nAlas, you guessed wrong.\n";
    cout << "Goodbye.\n" << flush << endl;
    return 0;
}


although I have to be careful because other programs can cause the status of getasynckeystate to change.
Topic archived. No new replies allowed.