You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by Merlin Beedell <MB...@cryoserver.com> on 2015/04/27 11:57:32 UTC
Getting console input with a timeout
I am trying to get Console Input when running simple scripts that stop with questions for user input – but that a default response would be used after a short timeout. Thus a script could be run manually or run automatically.
I found a handy example here http://www.javaspecialists.eu/archive/Issue153.html from Dr. Heinz M. Kabutz.
However, I find that the keypresses are not echoed back to the user until the Enter key is pressed. This is a bit of a problem. It does this for both System.Console or System.in. I thought that adding thread “yield” calls might help, but they do not. I don’t know if this is a problem only when run under Groovy.
Anyway, I have tried to groovy-ize the Java version below. But I wonder if the System.in MetaClass could be extended to provide the timeout functionality, rather than wrapping things on top – and would that help? Or perhaps to find a way to inject keypresses into the System.in from a separate thread, to pop the Enter keypress after the timeout?
import java.util.concurrent.*;
ConsoleInput con = new ConsoleInput();
String input = con.readLine("What is your name? ", "Fred", 15);
//def input = con.br.readLine() //this does echo keystrokes
println("Done. Your input was: " + input);
input = con.readLine("What is your age? ", "50", 5);
println("Done. Your input was: " + input);
public class ConsoleInput {
private final TimeUnit unit = TimeUnit.SECONDS;
//Console cons = System.console()
BufferedReader br = new BufferedReader(System.console().reader());
//This is groovies weird syntax for implementing an interface. Each map entry is a closure implementing a method of that name.
// it supports the usual class implementation syntax as well, of course.
def myReader = [
call: {
String input;
try {
// wait until we have data to complete a readLine()
while (!br.ready()) {
Thread.yield();
Thread.sleep(200);
Thread.yield();
}
input = br.readLine();
} catch (InterruptedException e) {
return null;
}
return input;
}
] as Callable
public String readLine(String sPrompt, String sDefault, int timeout) throws InterruptedException {
print "$sPrompt [$sDefault]: "
ExecutorService ex = Executors.newSingleThreadExecutor();
String input = null;
//note: groovy does not support the do/while loop syntax. Strange!
try {
Future<String> result = ex.submit(
myReader);
try {
input = result.get(timeout, unit);
} catch (ExecutionException e) {
e.getCause().printStackTrace();
} catch (TimeoutException e) {
result.cancel(true);
println "" //user input always has a newline - so we must add one after timeout case
}
} finally {
ex.shutdownNow();
}
return input?:sDefault;
}
}
Merlin Beedell
RE: Getting console input with a timeout
Posted by Merlin Beedell <MB...@cryoserver.com>.
Sorry for the long delay in replying. I can confirm that the console Input with Timeout works – excellent! I now understand that the O/S buffers the keypresses, and only presents them to the console input stream when the ‘Enter’ key is pressed – and thus no feedback is provided when using this code until the enter key is pressed.
For the sort of requirements that I have (simple y/n answers – with a default option), this may not be an issue.
But to take this to the next level, to be able to capture keypresses as they occur would be even better. I think this requires an understanding of CURSES – for which the ‘charva’ and similar efforts are available. Just need to figure how they could be sensibly used with groovy scripts.
Merlin Beedell
From: Paco Zarate [mailto:contacto@nazcasistemas.com]
Sent: 28 May 2015 05:54
To: users <us...@groovy.incubator.apache.org>
Subject: Re: Getting console input with a timeout
Hello Merlin!
You should be able to compile the java classes that are shown in the example (http://www.javaspecialists.eu/archive/Issue153.html f) and then use the generated jars in the groovy scripts (including the jars in the classpath).
Also you can use this code directly in groovy, i tried it with groovy 2.3.9 JVM 1.8.40.
This app is waits for the user to provide an input (characters + enter) for 10 seconds, it the timeout is reached, it cancels the input:
File: readingConsoleWithTimeout.groovy
//-- Code starts here --//
import java.io.*;
import java.util.concurrent.*;
public class ConsoleInputReadTask implements Callable<String> {
public String call() throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
System.out.println("ConsoleInputReadTask run() called.");
String input;
// replacing do .. while
while (true) {
System.out.println("Please type something: ");
try {
// wait until we have data to complete a readLine()
while (!br.ready()) {
Thread.sleep(200);
}
input = br.readLine();
} catch (InterruptedException e) {
System.out.println("ConsoleInputReadTask() cancelled");
return null;
}
if (!("".equals(input))) break;
}
System.out.println("Thank You for providing input!");
return input;
}
}
public class ConsoleInput {
private final int tries;
private final int timeout;
private final TimeUnit unit;
public ConsoleInput(int tries, int timeout, TimeUnit unit) {
this.tries = tries;
this.timeout = timeout;
this.unit = unit;
}
public String readLine() throws InterruptedException {
ExecutorService ex = Executors.newSingleThreadExecutor();
String input = null;
try {
// start working
for (int i = 0; i < tries; i++) {
System.out.println(String.valueOf(i + 1) + ". loop");
Future<String> result = ex.submit(
new ConsoleInputReadTask());
try {
input = result.get(timeout, unit);
break;
} catch (ExecutionException e) {
e.getCause().printStackTrace();
} catch (TimeoutException e) {
System.out.println("Cancelling reading task");
result.cancel(true);
System.out.println("\nThread cancelled. input is null");
}
}
} finally {
ex.shutdownNow();
}
return input;
}
}
ConsoleInput con = new ConsoleInput(
1,
10,
TimeUnit.SECONDS
);
String input = con.readLine();
System.out.println("Done. Your input was: " + input);
//-- Code ends here --//
On Mon, Apr 27, 2015 at 3:57 AM, Merlin Beedell <MB...@cryoserver.com>> wrote:
I am trying to get Console Input when running simple scripts that stop with questions for user input – but that a default response would be used after a short timeout. Thus a script could be run manually or run automatically.
I found a handy example here http://www.javaspecialists.eu/archive/Issue153.html from Dr. Heinz M. Kabutz.
However, I find that the keypresses are not echoed back to the user until the Enter key is pressed. This is a bit of a problem. It does this for both System.Console or System.in. I thought that adding thread “yield” calls might help, but they do not. I don’t know if this is a problem only when run under Groovy.
Anyway, I have tried to groovy-ize the Java version below. But I wonder if the System.in MetaClass could be extended to provide the timeout functionality, rather than wrapping things on top – and would that help? Or perhaps to find a way to inject keypresses into the System.in from a separate thread, to pop the Enter keypress after the timeout?
import java.util.concurrent.*;
ConsoleInput con = new ConsoleInput();
String input = con.readLine("What is your name? ", "Fred", 15);
//def input = con.br.readLine() //this does echo keystrokes
println("Done. Your input was: " + input);
input = con.readLine("What is your age? ", "50", 5);
println("Done. Your input was: " + input);
public class ConsoleInput {
private final TimeUnit unit = TimeUnit.SECONDS;
//Console cons = System.console()
BufferedReader br = new BufferedReader(System.console().reader());
//This is groovies weird syntax for implementing an interface. Each map entry is a closure implementing a method of that name.
// it supports the usual class implementation syntax as well, of course.
def myReader = [
call: {
String input;
try {
// wait until we have data to complete a readLine()
while (!br.ready()) {
Thread.yield();
Thread.sleep(200);
Thread.yield();
}
input = br.readLine();
} catch (InterruptedException e) {
return null;
}
return input;
}
] as Callable
public String readLine(String sPrompt, String sDefault, int timeout) throws InterruptedException {
print "$sPrompt [$sDefault]: "
ExecutorService ex = Executors.newSingleThreadExecutor();
String input = null;
//note: groovy does not support the do/while loop syntax. Strange!
try {
Future<String> result = ex.submit(
myReader);
try {
input = result.get(timeout, unit);
} catch (ExecutionException e) {
e.getCause().printStackTrace();
} catch (TimeoutException e) {
result.cancel(true);
println "" //user input always has a newline - so we must add one after timeout case
}
} finally {
ex.shutdownNow();
}
return input?:sDefault;
}
}
Merlin Beedell
Re: Getting console input with a timeout
Posted by Paco Zarate <co...@nazcasistemas.com>.
Hello Merlin!
You should be able to compile the java classes that are shown in the
example (http://www.javaspecialists.eu/archive/Issue153.html f) and then
use the generated jars in the groovy scripts (including the jars in the
classpath).
Also you can use this code directly in groovy, i tried it with groovy 2.3.9
JVM 1.8.40.
This app is waits for the user to provide an input (characters + enter) for
10 seconds, it the timeout is reached, it cancels the input:
File: readingConsoleWithTimeout.groovy
//-- Code starts here --//
import java.io.*;
import java.util.concurrent.*;
public class ConsoleInputReadTask implements Callable<String> {
public String call() throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
System.out.println("ConsoleInputReadTask run() called.");
String input;
// replacing do .. while
while (true) {
System.out.println("Please type something: ");
try {
// wait until we have data to complete a readLine()
while (!br.ready()) {
Thread.sleep(200);
}
input = br.readLine();
} catch (InterruptedException e) {
System.out.println("ConsoleInputReadTask() cancelled");
return null;
}
if (!("".equals(input))) break;
}
System.out.println("Thank You for providing input!");
return input;
}
}
public class ConsoleInput {
private final int tries;
private final int timeout;
private final TimeUnit unit;
public ConsoleInput(int tries, int timeout, TimeUnit unit) {
this.tries = tries;
this.timeout = timeout;
this.unit = unit;
}
public String readLine() throws InterruptedException {
ExecutorService ex = Executors.newSingleThreadExecutor();
String input = null;
try {
// start working
for (int i = 0; i < tries; i++) {
System.out.println(String.valueOf(i + 1) + ". loop");
Future<String> result = ex.submit(
new ConsoleInputReadTask());
try {
input = result.get(timeout, unit);
break;
} catch (ExecutionException e) {
e.getCause().printStackTrace();
} catch (TimeoutException e) {
System.out.println("Cancelling reading task");
result.cancel(true);
System.out.println("\nThread cancelled. input is null");
}
}
} finally {
ex.shutdownNow();
}
return input;
}
}
ConsoleInput con = new ConsoleInput(
1,
10,
TimeUnit.SECONDS
);
String input = con.readLine();
System.out.println("Done. Your input was: " + input);
//-- Code ends here --//
On Mon, Apr 27, 2015 at 3:57 AM, Merlin Beedell <MB...@cryoserver.com>
wrote:
> I am trying to get Console Input when running simple scripts that stop
> with questions for user input – but that a default response would be used
> after a short timeout. Thus a script could be run manually or run
> automatically.
>
> I found a handy example here
> http://www.javaspecialists.eu/archive/Issue153.html from Dr. Heinz M.
> Kabutz.
>
> However, I find that the keypresses are not echoed back to the user until
> the Enter key is pressed. This is a bit of a problem. It does this for
> both System.Console or System.in. I thought that adding thread “yield”
> calls might help, but they do not. I don’t know if this is a problem only
> when run under Groovy.
>
>
>
> Anyway, I have tried to groovy-ize the Java version below. But I wonder if
> the System.in MetaClass could be extended to provide the timeout
> functionality, rather than wrapping things on top – and would that help?
> Or perhaps to find a way to inject keypresses into the System.in from a
> separate thread, to pop the Enter keypress after the timeout?
>
>
>
> import java.util.concurrent.*;
>
>
>
> ConsoleInput con = new ConsoleInput();
>
> String input = con.readLine("What is your name? ", "Fred", 15);
>
> //def input = con.br.readLine() //this does echo keystrokes
>
> println("Done. Your input was: " + input);
>
> input = con.readLine("What is your age? ", "50", 5);
>
> println("Done. Your input was: " + input);
>
>
>
> public class ConsoleInput {
>
> private final TimeUnit unit = TimeUnit.SECONDS;
>
> //Console cons = System.console()
>
>
>
> BufferedReader br = new BufferedReader(System.console().reader());
>
> //This is groovies weird syntax for implementing an interface. Each map
> entry is a closure implementing a method of that name.
>
> // it supports the usual class implementation syntax as well, of course.
>
> def myReader = [
>
> call: {
>
> String input;
>
> try {
>
> // wait until we have data to complete a readLine()
>
> while (!br.ready()) {
>
> Thread.yield();
>
> Thread.sleep(200);
>
> Thread.yield();
>
> }
>
> input = br.readLine();
>
> } catch (InterruptedException e) {
>
> return null;
>
> }
>
> return input;
>
> }
>
> ] as Callable
>
>
>
> public String readLine(String sPrompt, String sDefault, int timeout)
> throws InterruptedException {
>
> print "$sPrompt [$sDefault]: "
>
> ExecutorService ex = Executors.newSingleThreadExecutor();
>
> String input = null;
>
> //note: groovy does not support the do/while loop syntax. Strange!
>
> try {
>
> Future<String> result = ex.submit(
>
> myReader);
>
> try {
>
> input = result.get(timeout, unit);
>
> } catch (ExecutionException e) {
>
> e.getCause().printStackTrace();
>
> } catch (TimeoutException e) {
>
> result.cancel(true);
>
> println "" //user input always has a newline - so we must add
> one after timeout case
>
> }
>
> } finally {
>
> ex.shutdownNow();
>
> }
>
> return input?:sDefault;
>
> }
>
> }
>
>
>
> Merlin Beedell
>
>
>