set timeout for user's input
Asked Answered
F

3

14

Is it possible to set timer for user's input? Wait 10 seconds - do next operation and etc. I mean for example

 //wait several seconds{
 String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
 //wait server seconds}
 //next operation and etc.
Fra answered 7/4, 2012 at 23:1 Comment(0)
Q
7

Not right out of the box, no. Normally the Reader only breaks out of a read() call when another thread closes the underlying stream, or you reach the end of the input.

Since read() is not all that interruptible this becomes a bit of a concurrent programming problem. The thread that knows about the timeout will need to be able to interrupt the thread that's trying to read the input.

Essentially, the reading thread will have to poll the Reader's ready() method, rather than getting locked in read() when there's nothing to read. If you wrap this polling and waiting operation in a java.util.concurrent.Future, then you call the Future's get() method with a timeout.

This article goes into some detail: http://www.javaspecialists.eu/archive/Issue153.html

Quiet answered 7/4, 2012 at 23:20 Comment(0)
R
18

A slightly easier way to do this than Benjamin Cox's answer would be to do something like

int x = 2; // wait 2 seconds at most

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
long startTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - startTime) < x * 1000
        && !in.ready()) {
}

if (in.ready()) {
    System.out.println("You entered: " + in.readLine());
} else {
    System.out.println("You did not enter data");
}

This will, however consume more resources than his solution.

Rightist answered 7/4, 2012 at 23:57 Comment(6)
BufferedReader.ready() appears to return true if there are any bytes available, not necessarily including a newline. Consider the case where there is one character waiting without a trailing new line. in.ready() returns true, in.readLine() is called, but blocks indefinitely waiting for newline.Palazzo
@Palazzo But the standard System.in will only data if the user hits enter on the command line which provides the newline sequence.Rightist
@Rightist is that documented anywhere?Hallow
@Hallow Not really. The "standard" System.in for a user tends to be an interactive shell. AFAIK, the way every interactive shell works is that you're allowed to type a single line at a time and when you hit enter that line is made available to the program. There could always be an exception to this rule. And if you're worried about that exception, you can modify the above snippet to work without using BufferedReader::readLine.Rightist
@Rightist Could you please expand a note about "busy waiting" with that loop? Beginners who find this answer are unlikely to realise what the exact problem is and a simple Thread.sleep(100) inside will do the job.Heracles
Hi, this is a great solution however as Jeffrey himself mentioned, it is heavy on CPU resources (to keep in mind for production use).Osteoma
Q
7

Not right out of the box, no. Normally the Reader only breaks out of a read() call when another thread closes the underlying stream, or you reach the end of the input.

Since read() is not all that interruptible this becomes a bit of a concurrent programming problem. The thread that knows about the timeout will need to be able to interrupt the thread that's trying to read the input.

Essentially, the reading thread will have to poll the Reader's ready() method, rather than getting locked in read() when there's nothing to read. If you wrap this polling and waiting operation in a java.util.concurrent.Future, then you call the Future's get() method with a timeout.

This article goes into some detail: http://www.javaspecialists.eu/archive/Issue153.html

Quiet answered 7/4, 2012 at 23:20 Comment(0)
A
0
 BufferedReader inputInt = new BufferedReader(new InputStreamReader(System.in));
 Robot enterKey = new Robot();
 TimerTask task = new TimerTask() {
   public void run() {
                      enterKey.keyPress(KeyEvent.VK_ENTER);
                     }
 };

 Timer timer = new Timer();
 timer.schedule(task, 30 * 1000);
 userInputanswer = inputInt.read();
 timer.cancel();
Anurag answered 6/10, 2019 at 18:28 Comment(1)
This doesn't work if the terminal/console doesn't have the focus.Gratulant

© 2022 - 2024 — McMap. All rights reserved.