How to intercept a keypress in a Java application? - java

I'm creating a program that prints the sound of three bells.
I need to stop the process when the user types a key on the keyboard, how can I do?
Also, I would make sure that every bell show your sound in a random time, making use of the property Math.random(). You can associate a random time to a thread?
package campane;
import java.io.*;
import java.util.*;
public class GestioneCampane extends Thread {
public static void main(String [] args) {
BufferedReader tast = new BufferedReader(new InputStreamReader(System.in));
char pressione;
Campane campana = new Campane("DIN", 300);
Campane campana2 = new Campane("DON", 1000);
Campane campana3 = new Campane("DAN", 2000);
campana.start();
campana2.start();
campana3.start();
}
}
this is the second class
package campane;
public class Campane extends Thread {
private String campane; // word to print
private int delay;
public Campane(String whatToSay, int delayTime) {
campane = whatToSay;
delay = delayTime;
}
public void run() {
try {
while(true) {
System.out.print(campane + " ");
Thread.sleep(delay);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

You can stop a thread by interrupting it:
Thread.interrupt()
You can stop a thread for a given time, and continue with it after the time is consumed:
Long time = 15000L; // in milliseconds
Thread.sleep(time);
Use KeyBindings to intercept keys pressed and randomize your sound relevence, this example can save time

Related

How to make 2 threads share data? (Java)

I'm currently practicing Threads so I tasked myself to write a program that will create 2 threads. The first one will endlessly print a character and the second one will endlessly wait for input and then pass it to the first Thread. Then Thread #1 should print the passed character. Here's what I wrote:
public class A extends Thread {
public char dif;
Scanner stdin = new Scanner(System.in);
#Override
public void run() {
for (; ; ) {
dif = stdin.nextLine().charAt(0);
MyThread.setCh(dif);
}
}
}
This thread takes input and then passes it to this one:
public class MyThread extends Thread {
public static char ch;
public static void setCh(char cha) {
ch = cha;
}
public static char getCh() {
return ch;
}
#Override
public void run() {
for(;;) {
try {
Thread.sleep(300);
}
catch(InterruptedException e) {
e.printStackTrace();
}
System.out.print(getCh());
}
}
}
And what happens in the main():
MyThread endless = new MyThread();
MyThread.setCh('$');
A set = new A();
endless.start();
set.start();
However, this doesn't work as intended. No matter what I type, the program keeps printing $. Also for some reason the first time I type a character I get an Out of bounds exception.
Probably, the easiest way to approach this, is to use BlockingQueue.
Effectively, in your example the thread, that receives character from System.in is producer and the thread that prints received character is consumer.
So, here is the code that achieves your goal:
import java.util.*;
import java.util.concurrent.*;
class Setup {
public static void main(String[] args) {
BlockingQueue<Character> q = new LinkedBlockingQueue<>();
Producer p = new Producer(q);
Consumer c = new Consumer(q);
new Thread(p).start();
new Thread(c).start();
}
}
class Producer implements Runnable {
private final BlockingQueue<Character> queue;
private final Scanner scanner = new Scanner(System.in);
Producer(BlockingQueue<Character> q) { queue = q; }
public void run() {
try {
while (true) {
queue.put(produce());
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt(); // set interrupt flag
} finally {
scanner.close();
}
}
Character produce() {
return scanner.nextLine().charAt(0);
}
}
class Consumer implements Runnable {
private final BlockingQueue<Character> queue;
Consumer(BlockingQueue<Character> q) { queue = q; }
public void run() {
try {
while (true) {
consume(queue.take());
}
} catch (InterruptedException ex) {}
}
void consume(Character c) {
System.out.println("Received character: " + c);
}
}
The problem actually you have it is quite small delay in Thread.sleep(300);
Try to set sleep for a few seconds Thread.sleep(5000);. You have to type something before it will print previous char

Stop Scanner from waiting for input

Goal
I'm currently building (to practice with java) a basic command line multiplayer turn-based game. In this game, each player has 5 seconds to make his move. When he makes his move (or when the timer ends) the other player starts his turn, etc etc.
The server sends a TimerEnded message every time the timer ends.
My current goal is to achieve flawless input reading that could be interrupted when a TimerEnded message arrives to the client.
Design
To achieve this I created a singleton called InputManager. This class handles all the input reading stuff. I created a method called ask which takes a callback as parameter. In this method I create a new thread and inside it I wait for an input with Scanner.hasNextInt.
This class has also the method closeInput which sends an Interrupt message to the thread described above.
Here's the current implementation of the class:
class InputManager{
private Thread thread;
private InputManager(){}
private static InputManager instance;
private static InputManager getInstance(){
if(instance == null){
instance = new InputManager();
}
return instance;
}
/**
* Ask user to type a number.
* #param onSelected When the user has made his choice, this callback will be executed
*/
public static void ask( Consumer<Integer> onSelected){
getInstance().thread = new Thread(() -> {
System.out.println("Type a number:");
Scanner sc = new Scanner(System.in);
int selection = -1;
while (selection == -1) {
if(Thread.currentThread().isInterrupted()){
return;
}
if(sc.hasNextInt()){
selection = sc.nextInt();
onSelected.accept(selection);
} else {
sc.next();
selection = -1;
}
}
});
getInstance().thread.start();
}
/**
* Reset input stream (?)
*/
public static void closeInput(){
try {
getInstance().thread.interrupt();
} catch(NullPointerException e){
// do nothing
}
}
}
Problem
This code is extremely unreliable. I'll show you what I mean in just a moment.
I made a toy class called Client and in the main I simulated the TimerEnd message income with a timer.
class Client {
/**
* Ask user to type a number and send it to the server
*/
void makeRequest(){
InputManager.closeInput();
InputManager.ask((selected) -> {
System.out.println("Sent message: " + selected);
});
}
public static void main(String[] args) {
Client client = new Client();
client.makeRequest();
// Simulate Server messages
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
System.out.println("Message received");
client.makeRequest();
}
}, 5000, 5000);
}
}
Here's how it works in action:
Type a number:
2
Sent message: 2
Message received
Type a number:
3
Sent message: 3
Message received
Type a number: // Here I don't type anything
Message received
Type a number:
Message received
Type a number:
Message received
Type a number: // Here I can send multiple messages on the same "turn"
1
Sent message: 1
2
Message received
Non-educated guess
Currently, I guess that Scanner remains waiting for input and so the if(isInterrupted) statement is not hit until an input is given. If so, how can I avoid this behaviour?
I understand that this question is extremely (and maybe unnecessarily) long, and since you read it let me thank you for taking your time.
Minimal, Complete and Verifiable code
package com.company;
import java.util.*;
import java.util.function.Consumer;
class InputManager{
private Thread thread;
private InputManager(){}
private static InputManager instance;
private static InputManager getInstance(){
if(instance == null){
instance = new InputManager();
}
return instance;
}
/**
* Ask user to type a number.
* #param onSelected When the user has made his choice, this callback will be executed
*/
public static void ask( Consumer<Integer> onSelected){
getInstance().thread = new Thread(() -> {
System.out.println("Type a number:");
Scanner sc = new Scanner(System.in);
int selection = -1;
while (selection == -1) {
if(Thread.currentThread().isInterrupted()){
return;
}
if(sc.hasNextInt()){
selection = sc.nextInt();
onSelected.accept(selection);
} else {
sc.next();
selection = -1;
}
}
});
getInstance().thread.start();
}
/**
* Reset input stream (?)
*/
public static void closeInput(){
try {
getInstance().thread.interrupt();
} catch(NullPointerException e){
// do nothing
}
}
}
class Client {
/**
* Ask user to type a number and send it to the server
*/
void makeRequest(){
InputManager.closeInput();
InputManager.ask((selected) -> {
System.out.println("Sent message: " + selected);
});
}
public static void main(String[] args) {
Client client = new Client();
client.makeRequest();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
System.out.println("Message received: thread interrupted");
client.makeRequest();
}
}, 5000, 5000);
}
}
As I see it, you can use 3 types of threads:
The main thread switches between users, announces players to play, checks the winning condition and starts the timer at each turn.
A second thread reads constantly the user input. After reading user input, it notifies the main thread.
Finally a thread waits for 5 seconds and then notifies the main thread.
So I will use 2 Producers and 1 Consumer as follows:
A Producer which "produces" the scanned user input (it provides it to the Consumer).
A Producer which "produces" time out events (which notify the Consumer).
A Consumer which switches between players and starts the producers.
All this, so that you don't have to mess around with interrupting any running thread and there is no need to check if the Scanner is ready…
import java.util.Scanner;
public class Main {
private static final Scanner SCAN = new Scanner(System.in);
//This is the Scanner's input Producer:
private static class UserInputProducer extends Thread {
private final UserInputConsumer uInConsumer;
public UserInputProducer(final UserInputConsumer uInConsumer) {
this.uInConsumer = uInConsumer;
}
#Override
public void run() {
while (true) {
final int input = SCAN.nextInt();
SCAN.nextLine(); //Ignore the new line character.
uInConsumer.userInput(input); //Fire user input event (for the current user).
}
}
}
//This is the time out event Producer:
private static class TimeOutEventProducer {
private final UserInputConsumer uInConsumer;
private int validReportId = Integer.MIN_VALUE; //IDs starting from Integer.MIN_VALUE and
//going step by step to Integer.MAX_VALUE, which means about 4 billion resets can be done
//to this Producer before an unhandled overflow occurs.
public TimeOutEventProducer(final UserInputConsumer uInConsumer) {
this.uInConsumer = uInConsumer;
}
public synchronized void reset() {
new TimerOnce(this, ++validReportId).start(); //Start a new TimerOnce. Could be javax.swing.Timer with "setRepeats(false)".
}
/*sleepDone(...) is called by ALL TimerOnce objects... So we need an up-to-date id (the
reportId) to verify that the LAST one TimerOnce finished, rather than any other.*/
public synchronized void sleepDone(final int reportId) {
if (reportId == validReportId) //Only the last one timeout is valid...
uInConsumer.timedOut(); //Fire time out event (for the current user).
}
}
//This is just a "Timer" object which blocks for 5 seconds:
private static class TimerOnce extends Thread {
private final TimeOutEventProducer timeout;
private final int reportId;
public TimerOnce(final TimeOutEventProducer timeout,
final int reportId) {
this.timeout = timeout;
this.reportId = reportId;
}
#Override
public void run() {
try { Thread.sleep(5000); } catch (final InterruptedException ie) {} //Wait.
timeout.sleepDone(reportId); //Report that the time elapsed...
}
}
//This is the Consumer:
private static class UserInputConsumer {
private final String[] names;
private int input;
private boolean timedOut, hasInput;
public UserInputConsumer(final String[] names) {
this.names = names;
}
public synchronized int play() {
new UserInputProducer(this).start(); //Start scanning any user's input...
final TimeOutEventProducer timeout = new TimeOutEventProducer(this);
int i = -1;
do {
i = (i + 1) % names.length;
hasInput = false;
timedOut = false;
timeout.reset(); //Start the input wait timer...
System.out.print("User " + names[i] + " enter a number: "); //Clarify who's player is the turn.
while (!hasInput && !timedOut)
try { wait(); } catch (final InterruptedException ie) {} //Wait for user input or timeout.
//Interpret notification event (either user input, either timeout):
if (timedOut)
System.out.println("Sorry, out of time.");
else if (!hasInput)
throw new UnsupportedOperationException("Probably messed with the flags in the while-condition.");
}
while (input != 5); //Here you test the win/loss condition.
//Lets say, for example, the user that enters number '5' wins...
return i; //Return the winner's index.
}
public synchronized void timedOut() {
timedOut = true;
notify();
}
public synchronized void userInput(final int input) {
this.input = input;
hasInput = true;
notify();
}
}
public static void main(final String[] args) {
System.out.print("Enter number of players: ");
final int numPlayers = SCAN.nextInt();
SCAN.nextLine(); //Ignore the new line character.
final String[] names = new String[numPlayers];
for (int i=0; i<names.length; ++i) {
System.out.print("User " + (i+1) + " enter your name: ");
names[i] = SCAN.nextLine();
}
//Start the consumer (which in turn starts the producers) and start the main logic:
System.out.println(names[new UserInputConsumer(names).play()] + " wins!");
}
}
Note, the program never terminates because the Scanning is infinite. But you may alter this behavior by messing with the while (true) condition of the UserInputProducer.
Alright, I worked out a solution.
As I thought, the problem is that the while loop was (of course) blocking in Scanner.hasNext. To avoid blocking, I used a BufferedReader, which has this handy function, ready, which returns true whenever a new line is input in System.in.
Basically, I changed the InputManager.ask method to:
void ask(Consumer<Integer> onSelected){
getInstance().thread = new Thread(() -> {
System.out.println("Type a number:");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Scanner sc = new Scanner(reader);
int selection = -1;
try {
while (selection == -1) {
//While there is no input to be processed
while (!reader.ready()) {
//This lets throw an InterruptedException
Thread.sleep(100);
}
if (sc.hasNextInt()) {
selection = sc.nextInt();
onSelected.accept(selection);
} else {
sc.next();
selection = -1;
}
}
} catch (IOException | InterruptedException e) {
// do nothing: function ends
}
});
getInstance().thread.start();
}
I also added this (extremely ugly) piece of code to consume any input before resetting, to prevent any previous line to be detected as typed now (basically flush the last line).
(If anyone has a suggestion on how this can be done in a more elegant way, I'm more than happy to hear your thoughs)
public static void closeInput(){
try {
BufferedReader tmp = new BufferedReader(new InputStreamReader(System.in));
if(tmp.ready()){
tmp.readLine();
}
getInstance().thread.interrupt();
} catch(NullPointerException e){
// do nothing
} catch (IOException e) {
e.printStackTrace();
}
}

Jline input disrupted by System out

I'm having some trouble with Jline and not quite understanding how to work it properly, everything seems to work from the examples but when i attempt to move it into my console application things go weird.
I've come across two issues:
When you write input into the console while something else is logging a message via System out, the written input gets broken. (View: https://i.imgur.com/ZAJDjTI.png)
I attempted to sync the commands to the main thread since the reader thread will be blocking, but this time you'll find that this causes the output text to take over the commands input space.
((Green text is the input, white is output)View: https://i.imgur.com/CdKiIYy.png)
The output i expected was for input coming from the bottom of the console to be unaffected by the output of the console, leaving a smooth input text layer at the bottom. (View: https://i.imgur.com/HfH5l8U.png?1)
Here's an example class i wrote to demonstrate the two problems I'm having:
import jline.console.ConsoleReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantLock;
public class Example {
private ConsoleReader consoleReader;
private LinkedList<Runnable> syncQueue = new LinkedList<>();
private ReentrantLock lock = new ReentrantLock();
public Example() {
try {
this.consoleReader = new ConsoleReader();
this.consoleReader.setExpandEvents(false);
} catch (IOException e) {
e.printStackTrace();
}
//If you enable this, Jline seems to be disrupted by the System out.
// startStopwatch();
setupJline();
//Ticker, its ugly i know
while (true) {
lock.lock();
try {
while (syncQueue.size() > 0) {
Runnable runnable = syncQueue.poll();
try {
runnable.run();
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
lock.unlock();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void setupJline() {
new Thread("Console Thread") {
#Override
public void run() {
while (true) {
try {
String line = consoleReader.readLine(">");
if (line != null && line.trim().length() > 0) {
//Lets pass this on as an instruction to our program
//Sync seems okay, output wise
handleInstructionSynced(line);
//async seems to mess things up though, comment the handleInstructionSynced method and
//uncomment the Async one to see what i mean.
//handleInstructionAsync(line);
}
consoleReader.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
//Just a dummy example instruction handler
private void handleInstructionAsync(String input) {
System.out.println("You've input \"" + input + "\" as your instruction.");
}
private void handleInstructionSynced(String input) {
runSync(() -> System.out.println("You've input \"" + input + "\" as your instruction."));
}
private void runSync(Runnable runnable) {
lock.lock();
try {
syncQueue.add(runnable);
} finally {
lock.unlock();
}
}
private void startStopwatch() {
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
int time = 0;
#Override
public void run() {
System.out.println(time + " seconds counted");
time++;
}
};
timer.scheduleAtFixedRate(timerTask, 0, 1000);
}
public static void main(String[] args) {
new Example();
}
}
Any solutions?

Set Time Limit on User Input (Scanner) Java

So I'm trying to read user input using the Scanner class. Is there a simple way to make it so that after 10 seconds it moves onto the next block of code? Thanks
You can use Timer and TimerTask. TimerTask will allow you to run a task after a certain amount of time, in this case you can use this task to stop waiting for the user.
import java.util.Timer;
import java.util.TimerTask;
...
TimerTask task = new TimerTask()
{
public void run()
{
if( str.equals("") )
{
System.out.println( "you input nothing. exit..." );
System.exit( 0 );
}
}
};
...
Timer timer = new Timer();
timer.schedule( task, 10*1000 );
Scanner sc = new Scanner(System.in);
String in = sc.readLine();
timer.cancel();
So if the user doesn't respond within 10 seconds here, the timer will quit reading input. I stole/adapted this response from this initial post:
Time limit for an input
I found another approach where we can continue our flow after the timeout instead of terminating the program.
That can be done via ScheduledExecutorService class.
The logic implemented is
Initialize a variable for managing the input state and another one for storing the result. (The input I wanted was boolean)
Schedule the input task at a 0s delay (i.e ask for input immediately)
Schedule another task to check for the input status as per the specified delay
Wait for both the tasks to be completed
Return the result
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
...
//member variables of class
private static AtomicBoolean inputValue = new AtomicBoolean(true);
private static AtomicBoolean inputEntered = new AtomicBoolean(false);
private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
...
public static void main(String[] args) {
try {
boolean yes = getTimedInput("Enter yes or no", 5);
} catch (Exception e) {
e.printStackTrace();
}
}
...
public static boolean getTimedInput(String inputString, long timeoutInSeconds) throws Exception {
System.out.printf("%s [Y/n] [timeout=%ds] >> ", inputString.trim(), timeoutInSeconds);
scheduler.schedule(() -> {
try {
String s = br.readLine();
if (s != null) {
inputValue.set(s.trim().equalsIgnoreCase("y"));
}
inputEntered.set(true);
} catch (IOException e) {
}
}, 0, TimeUnit.SECONDS);
scheduler.schedule(() -> {
if (inputEntered.get()) {
inputEntered.set(false);
} else {
System.out.println("\nInput timed out. Considering it as Y");
inputValue.set(true);
}
}, 0, TimeUnit.SECONDS);
scheduler.awaitTermination(timeoutInSeconds + 1, TimeUnit.SECONDS);
System.out.println();
return inputValue.get();
}

Send stop signal for command from user input in java programatically

I am executing a simple command where user gives the options(args) and I made a logic to get the args in Java program in which I am using wait() for particular time so that command will take that much minimum time to execute.I am saving some data in a file after that.
Within this time if the user wants to end the process ,should be able to stop the process smoothly by giving input like "exit" in the command prompt.
Please help.
The standard way of interrupting a command line program is by adding a Ctrl-C handler to your app:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
// cleanup logic here
}
});
See this question for more details.
Since you insist. Here is an implementation when commands are executed in background threads. I hope the complexity of this example will deter you from implementing it:
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Shell {
private static final int NUM_PARALLEL_COMMANDS = 5;
private static final int SLEEP_DURATION = 1000;
public static void main(String[] args) throws InterruptedException {
ExecutorService executor =
Executors.newFixedThreadPool(NUM_PARALLEL_COMMANDS);
try (Scanner scanner = new Scanner(System.in)) {
String command = null;
int counter = 0;
do {
command = scanner.nextLine();
switch (command) {
case "DoStuff":
executor.submit(NewDoStuffCommand(++counter));
break;
}
} while (!command.equals("exit"));
}
executor.shutdownNow();
executor.awaitTermination(1, TimeUnit.SECONDS);
}
private static Runnable NewDoStuffCommand(final int counter) {
return new Runnable() {
#Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println(counter + ": Doing time consuming things...");
Thread.sleep(SLEEP_DURATION);
}
System.out.println(counter + ": Finished.");
} catch (InterruptedException e) {
System.out.println(counter + ": Command interrupted :(");
// do cleanup
Thread.currentThread().interrupt();
}
}
};
}
}

Categories

Resources