I get that this isn't possible to do with normal java, although if there are any libraries out this it would be very useful.
Essentially, I'm designing a console app and running into an issue that when output happens while something is typed in the input line, that input text will move up and appear before the line that just got output. Is it possible to fix this in some form so that the text you are inputting that stays at the bottom?
EX:
I'm typing something as input into my commandline app, and then the program prints something WHILE I'm typing - this causes what was originally on the input line to be scrolled up with whatever the output text was. When you are trying to type something in this can obviously be detrimental. I know it's possible to prevent this.. (Other programs have done it... EX: Minecraft Server)
(If I need to be more descriptive I can.)
You could use the help of threads. One that listens to user input, the other process the actual output. This problem is similar to basic race condition problems when multiple threads attempt to read and write to a shared resource.
Your shared resource is that console. You need to keep the Input/Output operations synchronized. Have a look at race condition.
Related
I am trying to test a command line app that waits for the user input after every step. I am able to test the app using System Rules provided by Stefan Birkner. Currently, I provide inputs from the beginning to the end which works like a charm and I can assert the final output from system log.
However, I want to test for the negative cases before the end of the app for which I give invalid inputs in the beginning to evaluate the error message. When invalid inputs are given, the console prints an error message and keeps waiting for the user to provide a valid input. How do I send Ctrl+C using as shown below:
systemInMock.provideLines(Ctrl+C);
systemInMock.provideLines accepts only strings. Is there a way to send Ctrl+C signal?
An example of my junit test is shown below:
#Test
public void testInValidMarker() throws Exception{
systemInMock.provideLines("abc","def","1");
Main.main(new String[]{});
assertTrue(systemOutRule.getLog().contains("Invalid marker, try again"));
}
Appreciate your help!
If I'm not mistaken, when you do ctrl+c, it doesn't actually get written to console. If that's true, then in no case will your program ever be given ctrl+c, so provideLines will never be in a position where it is given ctrl+c.
For proof, open up cmd and type in a program with program arguments (in my case, I use ant). If you type ant and then ctrl+c, the cursor is moved to a new line.
There are two ways you can control termination behavior:
You can use a shutdown hook (found from this previously asked question ). Doing this will allow you to handle what happens (potentially with issues).
Or you could create your own termination argument like -q or q, which would trigger an action to end the program (maybe a System.exit(1)). This way you can mock that input.
In UNIX/Linux, when you type CTRL-C, your shell intercepts it and sends the process a SIGINT signal -- see: How does Ctrl-C terminate a child process?
Therefore the System Rules project doesn't have anything to help you -- in this situation the process doesn't receive any character input.
By default, the whole JVM shuts down when it receives SIGINT. This is obviously bad news for a running test.
The SO question Signal handling using "TERM" -- may be of use.
A side effect of Java's portability is that for some OS features, it either abstracts things away until they're unrecognisable, or doesn't expose them at all.
I suspect what you're asking for can't be achieved.
If you're allowed to change the requirements slightly, you could ask the user to close with CTRL-D -- this closes stdin with EOF.
Although it's quite the overkill, you could launch a whole new JVM running your program, using ProcessBuilder. You might imagine you'd get an API to send arbitrary signals to that process. But for portability reasons, all you can do is process.destroy(), which sends SIGTERM.
Tried this as a comment, but it didn't read right. It's not exactly an "Answer" though.
So Java is really bad at console input. It reads an entire line at once and you can't do anything about it--there is no way to trap special characters or even see any of the input before the user hits return. Also I think a ctrl-d will close your input session--(Add that test to your use case if you don't use any other suggestion here because it can put you into a state you didn't expect!)
Three suggestions:
The simplest: If you can use a GUI and aren't really looking for an ongoing input/response REPL the simplest answer is usually to use JOptionPane to throw up a quick dialog. It's a one-line solution to get some user input, but not so good for an ongoing command-driven system.
If you can't use swing (If you are running headless) then you may have little choice, but you can use the JLine library. That will give you a lot more flexibility. This is how Groovysh does it's REPL. It will let you see each character as it is typed and do things like completion where a user might type part of a file name and hit tab and you put the rest in for him.
If you don't want to use JLine but want a REPL feel there is also a more complex GUI solution--create a swing console window. A trivial solution would just be a text input box to allow typing and a text area to display results, but there are certainly libraries out there with more complete console solutions.
The point here is that using Java standard input alone is just not a good solution for anything beyond a trivial/personal script--and even then I avoid it. Perhaps not the answer you asked for, but maybe it's the one you need :)
Say I allow the user to edit something, like the phone number in an Address Book (actually, that's exactly what I'm doing). Is there something that I can add to println that will allow me to insert a variable to display as fully editable text? The assignment that I'm doing this for doesn't actually call for this, but I think it would be cool to have. I'm looking on Google but can't find anything, then again I don't really know what I'm looking for and whether or not I have the correct terms in mind ...
No, not using only what Java provides in the framework. Editing some text would require to
act on key press, which is not possible as in Java the input is buffered (i.e., wait for Enter to be pressed)
to move around in the text you output, which is also not possible
This could be done using some native code (ncurse on linux, ...), using JNI or JNA, but not that easily.
Note that there are some projects that aim to add those functionalities, so if you can use something outside of the core libraries, you could give them a tries... for instance http://code.google.com/p/java-console-api/
There are various options for this, in order of simplicity and portability to features and complexity:
Simply prompt for the information, reading a complete (return-terminated) line of response, and allow the normal terminal input facilities to be used for basic editing.
Use something like the gnu readline library to allow more advanced editing. You still won't have widgets (text input boxes at specific places on screen) as such though. There's a java implementation here: http://java-readline.sourceforge.net/
Use something like ncurses to specifically position the cursor, print text labels, handle keypresses, and implement your own text input box. Not fun.
Use a textual user interface library (TUI), like this one: http://www.bmsi.com/tuipeer/
If you opened a window that looks like the console window, and could react to keypress events, then you could do what you are asking, but, otherwise, if you are just running a program, the program will have ceased executing and returned control to your console, so it can't do anything else.
But, if you use a scriptable version of java you could write your own shell, and then you could do what you are asking, as the shell would not cease executing.
But, that will probably be beyond your course.
I have two threads - one awaits for input and the other is printing the debugging info.
However only one console window, so I can't type 'exit' (or whatever to stop the process), because System.out.println constantly prints the stuff. Can I have two separate console windows for each?
P.S. I wouldn't want to use Swing just for this purpose - there must be a way.
The only way I could think of would be to have two difference processes and a link betweeen the two processes. But I don't have a clue as to how to do that. Perhaps your best bet is to use the JOptionPane class.
While you stated that you don't want to use Swing, I believe that JOptionPane would be the best option for you. Simply using JOptionPane.showInputDialog is a fast way to solve your issue. Here's a link to JOptionPane's JavaDoc.
If you really can't use Swing, there's always the option to press Ctrl + C to stop the process.
A final option would be to buffer the output and only write it after the input. After you receive input, you would flush the buffer and then deal with the input. In this manner, you would prevent the application from closing before the buffer is flushed. There are two ways to do this:
You can use a BufferedWriter with a very large size (maybe 100,000?) and store this as a static variable. Instead of calling System.out.println(), you could call MyClass.out.println()
You could override System using System.setOut(). You would create your own PrintWriter that would take any input and send it to a LinkedList (or your own LinkedList designed for chars, if you choose). I suggest you use a linked list because appending is O(1) for a linked list while appending is O(n) for an array list.
Edit:
As for hmjd's suggestion (file writing), you would do that like this:
System.setOut(new FileWriter(new File(myFileName)));
Log to a file then go into another window and tail the file (in unix/mac use "tail -f filename", in another os--install unix/cygwin!)
This keeps your log separate from your console and makes it persistent as well.
There are a lot of logging utilities out there that will help with this and will even help a bit more by telling you what file a given line is coming from.
Your question is similar to this one, so I think the answer is the same. However, maybe this question might be right for you.
I am writing a program that takes commands via the console.
However, I do not want to press "enter" in order to send that command.
I want the code to constantly monitor what I am entering, and execute the code when I am finished.
The commands are coming as text from a speech recognition program, therefore, eliminating the need for the "enter" stroke is pretty key.
Any one have any ideas?
I have recently come to the knowledge of events in java and i believe this would help you. You would just need to associate the speech recognition printing to the screen with an event in java and it would have a listener to listen for the event and when it sees the event it would execute your desired code. I currently have a thread opened where im trying to get some good examples of this, perhaps that will help.
Java Events Question
Already answered here:
How to read a single char from the console in Java (as the user types it)?
No portable way to do it, depends on your platform.
I haven't worked with Java since college, but if you're reading from the command line, then you are using System.in.read() or something similar. Since these are blocking method calls, your application will never be notified about the new input until ENTER is pressed.
If I'm dead wrong, please let me know.
You're probably better off using a simple (possibly even hidden) that can take the user text and an event listener on the UI element that reads it in to the application's text processor.
Say I allow the user to edit something, like the phone number in an Address Book (actually, that's exactly what I'm doing). Is there something that I can add to println that will allow me to insert a variable to display as fully editable text? The assignment that I'm doing this for doesn't actually call for this, but I think it would be cool to have. I'm looking on Google but can't find anything, then again I don't really know what I'm looking for and whether or not I have the correct terms in mind ...
No, not using only what Java provides in the framework. Editing some text would require to
act on key press, which is not possible as in Java the input is buffered (i.e., wait for Enter to be pressed)
to move around in the text you output, which is also not possible
This could be done using some native code (ncurse on linux, ...), using JNI or JNA, but not that easily.
Note that there are some projects that aim to add those functionalities, so if you can use something outside of the core libraries, you could give them a tries... for instance http://code.google.com/p/java-console-api/
There are various options for this, in order of simplicity and portability to features and complexity:
Simply prompt for the information, reading a complete (return-terminated) line of response, and allow the normal terminal input facilities to be used for basic editing.
Use something like the gnu readline library to allow more advanced editing. You still won't have widgets (text input boxes at specific places on screen) as such though. There's a java implementation here: http://java-readline.sourceforge.net/
Use something like ncurses to specifically position the cursor, print text labels, handle keypresses, and implement your own text input box. Not fun.
Use a textual user interface library (TUI), like this one: http://www.bmsi.com/tuipeer/
If you opened a window that looks like the console window, and could react to keypress events, then you could do what you are asking, but, otherwise, if you are just running a program, the program will have ceased executing and returned control to your console, so it can't do anything else.
But, if you use a scriptable version of java you could write your own shell, and then you could do what you are asking, as the shell would not cease executing.
But, that will probably be beyond your course.