i have two threads: one of them (server) is printing something to the console and the other (user) one is taking input from console. The problem occurs if the first thread prints something while user is typing into console. it looks like for example
command from usermessage from server
or if the user hasn't typed the command fully
commmessage from server
and it messes up the command from the user
is there a way to make it look like
message from server
command from user
or
message from server
comm
so to print one line above the currently typed text in the console and maintain the user input. i still want the first thread to print while the user is typing so locking this thread untill user enters the command isn't an option
[I want] to print one line above the currently typed text in the console and maintain the user input.
There are no easy answers here unfortunately. The user input being entered is actually being echoed by the terminal and not by the Java program. You have no control over the input and can't reprint it once the standard output is displayed.
The only way to do this otherwise is to turn off terminal echoing and control the user keystrokes in your program, but that makes it a lot more complicated. See: How to disable console echoing
You could also use some sort of Java dialog box and then pop the standard out message in another dialog or let it go to standard out.
i still want the first thread to print while the user is typing so locking this thread until user enters the command isn't an option
Yeah I fear that locking out the standard output messages is only way for you to do this unless you want to use a different mechanism to get your user input.
Related
I made a application that basically reads out data and prints it out on the raspbian Command Line Interface (CLI) using system.out.print. Printing text on the CLI using the mentioned method works regarding printing text.
After printing the text I want it also to behave like pressing enter button (submitting the data). Imagine you are prompted by the CLI to enter a value, the application prints the data and then I want the application to behave as if a user would press enter.
The application is a daemon process which prints data from an external device in the CLI. It could and does print this data at any time this is intentional. Sending the data to a specific application or a set of applications is not wanted because the application commanding the prompt could swap every x amount of time. With the newline command the cursor goes to the next line but it does not behave as if a user were to press the enter button of the keyboard.
I tried using \n which does move the cursor to the next line but it does not submit the data. In the end I want the data to be entered automatically without the user pressing the enter button manually.
After that I tried out awt.robot class but that doesn't work because it throws a headless exception and after googling a bit I believe it's related to a GUI or functionality which won't be installed and used on the Raspbian.
I've also found people mentioning JNA and JNI libraries but I can't find any example (at least not for linux devices) to simulate a enter press by the user.
Here is a more concrete example. The CLI prompts:
Weight:
The daemon process prints 0.233. So the CLI will look like:
Weight: 0.233
Then the application must behave as if a user presses enter. Using the newline character only moves the cursor and does not behave as if a user presses the enter button like:
Weight: 0.233
_ (representing cursor).
Smallest/simplest reproducible example:
public static void main(String[] args) {
while(true) {
//this moves the cursor to the next line and doesn't enter the line in a prompt.
System.out.println("abc");
//have to time that it goes into a prompt. I have a startup login prompt which I can test it with.
//or whatever suits your needs
Thread.sleep(20000);
}
}
I'm using java 8 and the Raspbian version is 8 and the raspberry version is 3.
Hopefully anyone knows what to do or what I'm missing. Any help is welcome.
After much experimenting I found out that the that's just the way the TTY interprets the /n nowadays. I had an older Linux installation which emulates a /n as a keyboard press but that doesn't happen in that raspbian version.
So basically I had to write directly to the correct IO channel same way as a keyboard does. The you cannot emulate a keyboard enter press directly to the terminal. Only by either writing directly to the correct IO channel or using a keyboard emulator.
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 :)
I am writing simple socket chat using console to output messages. The problem is that when one user types a message, and at the same time getting one, his input interrupted:
I: writing my input here, but
Other_user: hi! here is a message for you.
I: it splits to different lines, which is 1) very inconvenient 2) cannot see which simbols i deleted if press backspace
So, what i am asking is, how can I avoid this
(something like: if message is received, check input for symbols; if there are, remember them, delete last stroke in console, print message, and then recreate that stroke).
EDIT: attached picture
hard to tell without specific code, but an option is to use two threads, one to handle the socket input, one for output. attach these to System.in and System.out respectively. it seems like you might be using only one thread to do both.
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.
I want to add a "history" function to my java programm, like known from bash etc, so pressing the arrow keys should show previous send commands.
It's no problem to write the past commands to the default output, which will in three new lines if arrow up is hit three times and in not editable output. I want the output of the programm to be written in the input field so i just have to hit enter, to resend the command.
Is this possible?
Kind Regards
Take a look at JLine, which provides command history, tab completion and line editing.
If you want to roll your own solution, this will get you started.
You want to change from using a buffered input into a direct input. You can do this by interfacing with System.in directly. You should create a thread to handle this, and have it block on a call to System.in.read() in a loop, reading one byte at a time.
Each time a byte is read, keep your own buffer updated with the current command that's being read. Every character that gets typed, add it to the buffer. If the character is a \b, delete the last character in the buffer. When you detect a \r or \n, execute the command in the buffer and clear it.
If you receive an up or down arrow, send a number of \bs to System.out equal to the length of the buffer. This will erase the local copy of any current command being entered. Then print out the new command to System.out and enter it into the buffer, replacing whatever was there. This will allow the user to delete it, add to it, or just press enter to submit it. This mimics the functionality of bash.
You can also detect a \t (tab) character and implement a tab-completion function.