3

I want to prompt the user to begin entering characters and I want them to be able to enter characters as long as they want until they hit control+d to exit.

For example, they can type a string of numbers like: 1234567 and as soon as they decide to hit control+d the line that they entered will be displayed (so without having to hit return)

I am thinking I'll need a buffered reader or something. Any suggestions?

Ken White
  • 123,280
  • 14
  • 225
  • 444
Corey
  • 771
  • 3
  • 14
  • 32
  • I don't have much experience in java, still, in C style I would use a single char read function to do the job in a while(key != ctrl+d) loop and them look for the key combination to make it stop (dunno how it is actually read in java) EDIT: Nvm that, it seems java has good methods to do that – John Apr 29 '11 at 22:05

6 Answers6

5

What rlibby said is spot on: the CTL-D will cause the terminal to flush buffered input to the JVM. However, the keypress event itself is captured and acted on by the terminal and not passed through.

Fortunately, though, it's easy to detect. If the user hits CTL-D on a line of its own, there is no input to flush...which to the JVM is indistinguishable from EOF. Accordingly, System.in.read() will return -1 per the contract of InputStream. If you've wrapped System.in with a BufferedReader, readLine() will return null.

This is my main loop for an interactive command line tool I just wrote:

BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));

String line;
while((line = systemIn.readLine()) != null) {
    // my program loop.
}

One thing worth pointing out is that if the user hits CTL-D after inputting characters (but before hitting return), you'll get those characters. I don't believe there's a way to detect CTL-D when it's not on a line of its own.

DISCLAIMER: I have no idea how this applies to Windows.

stevevls
  • 10,675
  • 1
  • 45
  • 50
3

http://download.oracle.com/javase/6/docs/api/java/io/BufferedInputStream.html#read%28%29

public class InputTest {
  public static void main(String[] args) throws IOException {
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    StringBuilder out = new StringBuilder();
    while (true) {
      try {
        int c = in.read();
        if (c != 4)  // ASCII 4 04 EOT (end of transmission) ctrl D, I may be wrong here
            out.append (c);
        else
            break;
      } catch (IOException e) {
        System.err.println ("Error reading input");
      }
    }
    System.out.println(out.toString());
  }
}
Aleadam
  • 40,203
  • 9
  • 86
  • 108
  • 04 seems correct, but it doesn't work, since System.in is buffered. I'm not sure whether it is possible to prevent buffering, or setting the buffersize to 1. – user unknown May 01 '11 at 05:01
  • @user I don't think it's because it's buffered (I may be wrong, though). I'm more inclined to an explanation such as the one posted by rlibby. Maybe the terminal does not even send that character? Perhaps the code should be changed to `if (c!=4 || c!=-1)`? – Aleadam May 01 '11 at 05:38
  • Maybe I'm wrong, but from the 'without hitting enter' I expect that he want's to read everything unbuffered. I don't see an advantage in hitting Ctrl-D instead of Enter. A normal 'readline' accepts the current buffer until ^D, doesn't it? – user unknown May 01 '11 at 06:01
  • @user Yes, it is "end of transmission" after all. Anyhow, the OP is quite cryptic about how this code would be used. We don't really know even if the OP is using a standard terminal :/ – Aleadam May 01 '11 at 06:09
3

You are confusing the roles of your Java program and of the terminal. The terminal buffers input and occasionally supplies it to the Java program, especially after line feeds. Ctrl+D also causes the terminal to make buffered input available, or, if nothing is buffered, to terminate the input. Asking for a program to do something on Ctrl+D is essentially asking it to do something when it reads all available input (and more may become available later). Buffering input on the Java side is going to make things more complicated, rather than less.

rlibby
  • 5,931
  • 20
  • 25
3

Just adding another option for people like me who turn up 9 or so years after the question was asked. If you are using java.util.Scanner, using a String input = in.next(); will drop a NoSuchElementException when Ctrl+d is used. In this case, you can use a try-catch block to catch that particular exception and end execution of your program (either by breaking or changing your iteration value to stop the loop).

import java.util.Scanner;

while (some condition) {
  try {
    (take your input using the in.next() function here)
    ...
  } catch (java.util.NoSuchElementException e) {
    (some condition) = false;
    //OR break;
  }
}
Julian
  • 31
  • 1
2

give this code a try. it actually worked for me

    // press ctrl+Z(windows) and ctrl+D(mac, linux) for input termination
    StringBuilder out = new StringBuilder();
    String text = null;
    Scanner scanner = new Scanner( System.in );
    while( scanner.hasNextLine() )
    {
        text = new String( scanner.nextLine() );
        out.append( text );
    }
    scanner.close();
    System.out.println( out );
    System.out.println( "program terminated" );
Deepika Lalra
  • 1,035
  • 1
  • 10
  • 24
0

In a GUI, you can use a KeyListener.

user unknown
  • 35,537
  • 11
  • 75
  • 121