Is it possible to know if a user pressed the ENTER key using the readline () method? - Java

advertisements

I want to recognize if a user sent a text, using readline method from BufferedReader. While the user didn't send anything, the Thread keeps sleeping. Is there a way to do this? I'm trying for a long time, but no success yet.. I guess I have to recognize if a ENTER key was pressed.. but I donwt know how to do this.. The interface of my program is the console..

The problem is: I have a client-server program. When a client enters a message, the message prompts on the screen of the another user/client. But, if the user doesn't send a message in 10 seconds, I want a message to appear on the screen.. So I have a Thread.sleep(1000). The problem is I don't know when to wakeuo the Thread.

while((mensagem == null) || (!mensagem.trim().equals(""))) {
      Thread.sleep(10000);
      sendToAll(output, "[Your turn] ", "");
      mensagem = input.readLine();
   }

The last line isn't correct also, because I don't want to force the user to type, and this way I'm forcing, 'cause I stop on input.readLine().

SOLUTION: I resolved the problem using the method setSoTimeout(10000).. This is the code:

public Server(Socket socket) throws SocketException{
   this.connection = socket;
   this.connection.setSoTimeout(10000);
}

public void run(){
   [...]
   while((msg != null) && !(msg.trim().equals(""))){
      try{
         msg = input.readLine();
     sendToAll(output, ": ", msg);
      } catch (SocketTimeoutException e) {
     sendToAll(output, "Time out ", "");
      }
}

Thank you all for the ideas!! :)


You need to understand what is going on here, on both the Java side and the console side.

On the Java side, the readLine() call is simply attempting to read characters until it sees either a valid "end of line" sequence, the end of the input stream. It is a blocking call, and there is no way to specify a timeout in the API that you are using.

On the Console side, console is watching for keyboard events and accumulating them in a line buffer:

  • When it sees a key event for a data character (a digit, letter, whatever), it adds the character to the buffer.
  • When it sees a meta character (e.g. a "delete") it performs the appropriate edit on the line buffer. For example, it might delete a character from the line buffer at the 'cursor' position.
  • When it sees an ENTER key, it adds an end-of-line sequence to the line buffer, and sends the line.

Details will depend on the console program and how the user has configured it. However, the fact remains that until the user types ENTER, nothing will be sent to the "pipe" that connects the console to the Java application. In short, the Java application won't see anything.

What this means is that the Java application can't tell if the user is typing or not.


So what can the Java application do?

  • You could use a Timer to send an interrupt to the blocked Java thread (the one doing the readLine() call) after a few seconds / minutes. This will cause the readLine() call to unblock and throw an IOException. However, there are problem with this approach:

    • There is a potential race condition where the timer fires after the readLine() call finishes, and the interrupt goes to application itself. This could cause problems, depending on what the application does with interrupts. You should be able to avoid this using a properly synchronized flag that the primary thread sets when the readLine call returns.

    • It is not entirely clear, but there are signs that if you get an interrupt on a pipe, the underlying channel is automatically closed. That would mean that you couldn't ask the user for any more input.

  • The second approach might be to replace your BufferedReader / readLine() code with something that uses NIO channel selectors. Among other things, a Selector allows you to wait with a timeout for a channel to have readable data. You'd then need to implement buffering and readline on top of that.

  • If you wanted to know if the user had typed at the console, you'd need to put the console into non-line-editing mode. This cannot be done in pure Java, but there are 3rd-party libraries that do this kind of thing.