I would like to use a BufferedReader with a kind of readLine() (or similar) that can return an echo for every keystroke pressed.
It's for a remote terminal. Other way to ask it is how is implemented a console in java.
This is what came to mind but is too ugly. Is there any known library that implement something like this?
while(condition) {
nByteRead = in.read(buffer);
if (nByteRead != -1) {
// ECHO
out.write(buffer, 0, bytes_read);
// read bytes till NEW_LINE...
// etc...!
}
}
Of course I could encapsulate this behaviour in some thread and go on with a library for this, I just wonder if there is some wheel already invented.
Thanks for any hint!
Most terminals, including the default terminals in Ubuntu and Windows (I believe) won't pass on the characters to the JVM until the user hits return. (I.e., it is buffered on a full-line basis on a lower level in the system.)
If you need to read one character at a time from the terminal, you'll have to go with a lower level system library.
Related question:
Why can't we read one character at a time from System.in?
(disclamer, I'm not completely sure I understood your question correctly.)
There's:
JLine: http://jline.sourceforge.net/
Java Curses: http://sourceforge.net/projects/javacurses/
Related
I wrote multithreaded java server-client sockets app with messaging functionality but I encountered a problem with simultaneous console IO.Main server console is listening for keyboard input and simultaneously printing out messages from the clients. On client side there is a separate thread for printout.
Here is simplified code representation:
public class ServerThread{
....
BufferedReader in = ... (sock.getInputStream);
while(true){
System.out.println(in.readline());
....
public class ServerMain{
.....
BufferedReader keyb = ... (System.in);
while(true){
in = keyb.readLine();
....
The problem occurs while I'm typing something in the main server console and at the same time a message arrives from one of the clients.
That message is then concated to what I was typing on screen and cursor moves to the beginning of the next line waiting for input.
What was typed in previously is stuck in the keyboard buffer, and I cant edit it anymore. Same problem happens on client side.
The question is how can I print messages on screen without disrupting ongoing input?
(inputted text also needs to stay printed on screen as in readLine() default behavior)
I already tried some of the solutions suggested for other similar problems:
In Lanterna and JCurses libraries there's no support for native System.IO streams. I would have to reinvent the wheel and implement it all by myself manually from memory to screen, one char at a time plus build whole console GUI layer.
The other thing was using ANSI codes but I couldn't figure out how to do what I need with them. I could read one input char at a time instead of a whole line, then if message arrives clear the line, move cursor to the beginning and printout, but afterwards in nextline I don't know how to print previously buffered text and still be able to delete chars with backspace.
edit:
GUI is not an option as I want my code to be able to run on a headless server.(also assume that there will be only one terminal, console, shell, and app running per side)
A distinct non-answer, based on: there is only one console.
And that console is an artefact from times when multiple threads weren't a real problem. "Works nicely with multiple threads" was never a requirement for that low level console.
Thus: if you really want a sophisticated solution (that isn't a hack of some sort) simply consider: not using the stdin/stdout console(s).
Instead: write a simple Swing GUI application. Have one text entry field where input is collected, and one or maybe multiple text fields where your output goes. If you want to be fancy, make it a webapp. I am sure that using some framework, you could put together a working thing within a few hours. You will learn more valuable skills by doing that, instead of spending these hours "working around" the fact that you picked the wrong technology for your problem.
Update, given the comment by the OP: then the best I can think of: don't write to the console. Write to different files. Open multiple terminals, and use tools like "tail" to show you what is happening with your output file(s).
Ok, I found the ideal solution myself:
JLine library works in conjunction with default System.IO, also there is no need to create new Terminal objects (you can) or anything else. Simply instead of BufferedReader you use LineReader
String readLine(String prompt, Character mask, String buffer)
prompt (can be null) is the unexpanded prompt pattern that will be displayed to the user on the left of the input line
mask (can also be null) is the character used to hide user input (when reading a password for example)
buffer is the initial content of the input line
Edit: In JLine's docs i found an even better solution:
printAbove
void printAbove(AttributedString str)
Prints a string before the prompt and redraw everything. If the LineReader is not actually reading a line, the string will simply be
printed to the terminal.
Parameters:
str - the string to print*
I'm building a program in Java that uses menus with different colors using ANSI escape codes. Something like
System.out.println("\u001B[36m"+"Menu option"+"\u001B[0m");
The problem is that i want to check if the console where the code is going to be executed supports using this codes, so in case it doesn't, print an alternative version without the codes.
It will be something similar to:
if(console.supportsANSICode){
System.out.println("\u001B[36m"+"Menu option"+"\u001B[0m");
}
else{
System.out.println("Menu option");
}
Is there a method in java to check this?
A simple java-only solution:
if (System.console() != null && System.getenv().get("TERM") != null) {
System.out.println("\u001B[36m"+"Menu option"+"\u001B[0m");
} else {
System.out.println("Menu option");
}
The first term is there to check if a terminal is attached, second to see if TERM env var is defined (is not on Windows). This isn't perfect, but works well enough in my case.
I don't know if Java has some special way to deal with this, but there are two ways to deal with the problem itself. The usual method used (at least in the unix world) is to get the terminal used from the TERM environment variable and look up it's capabilities from the terminfo/termcap database (usually using curses or slang). Another more crude approach is to send the Device Status Report code ("\u001B[6n") and check if the terminal responds. This is of course a bit of a hack since a terminal that supports the DSR code might not support color for example.
I have been on this for a while now, and for the past three days have ripped apart the Internet for ways to effectively clear the console in Java.
Ways I have seen it "done"
This way
for(int x = 0; x!=100; x++){
System.out.println();
} Sucks, as you can just scroll up and see the printed statements again.
Console.Clear(); and all variations of it, have not worked for me.
Runtime.getRuntime().exec("cls"); has not worked in any cases i have tried to use it in.
(I use JCreator to code, I have no idea if this has anything to do with my issue)
This way by joesumbody122, looked interesting:
private static void clearLine()
{
Console.Write(new string(' ', Console.BufferWidth - Console.CursorLeft));
}
and
private static void clearLine(int left, int top)
{
int pLeft = Console.CursorLeft;
int pTop = Console.CursorTop;
Console.setCursorPosition(left, top);
Console.Write(new string(' ', Console.BufferWidth - Console.CursorLeft));
Console.setCursorPosition(pLeft, pTop);
}
But sadly i could not get it to work for me. It gave me errors that all the methods that he called from Console did not exist. java.io.*; was imported His method clears one line specifically, so if someone could get this working, (Again, I use JCreator to code, I have no idea if this has anything to do with my issue) I could see it being looped to clear all the lines.
Ways to make less sucky?
Back to this for(int x = 0; x!=100; x++){
System.out.println();
} Is there a way to prevent the user from scrolling up in the command line? To set the cursor to the top left of the prompt? That would make this method a whole lot more useful.
Another Theory
Is there a way to simply tell java to stop printing in one command line, start printing in another, and close the window of the first so it only appears to have cleared the console, but instead created an entirely new one? I have pondered this the last two hours, and in theory it would work, but i don't know if the code to do so even exists.
There is no reliable way that works everywhere. You've already mostly discovered this.
Generally, command-line output goes into a terminal scrollback buffer, of which only the last n lines are displayed, but previous lines are available through a scrolling mechanism. A command-line program does not write directly to this buffer, but writes to stdout which is, in most cases, piped to the terminal process which then displays the data.
Some terminal programs (i.e. those supporting ANSI escapes) might let you clear the visible portion of the screen. As far as I know, only Windows' cmd.exe responds to a 'clear screen' request by clearing the entire scrollback buffer. On Linux AFAIK it's not possible to discard the buffer completely. And, on Windows, cls is not an executable command but a shell builtin, so you cannot run it from Java System.exec().
Also, any command-line program can have its output redirected to a file with out the program being aware of it, in which case 'clear screen' doesn't have much meaning.
If you MUST have this level of control then you will have to write your own display window using Swing, AWT or GWT or whatever and manage all interaction there.
If it's a command-line app and the terminal/shell you're running the app in supports ANSI escape codes then you can just do this:
System.out.print("\033[H\033[2J");
System.out.flush();
The answer depends on weather or not you are using Linux or Windows OS. If you are using linux and want to clear the console then try:
try {
new ProcessBuilder("/usr/bin/clear").inheritIO().start().waitFor();
} catch(Exception e) {}
If you are using windows try:
try {
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
} catch(Exception e) {}
You can handle the exception any way you want.It does not matter becasue you will not get one.
I have been pulling my hair for this since quite long time. I have researched for an hour on how to clear a console in Java.
All I found was dirty hacking either by printing a bunch of lines or executing this
Runtime.getruntime.exec("cls/clear");
However, nothing seems to be working for me. Isn't there really any a way of clearing the console in Java like in C (clrscr();). Isn't there any external library by which this can be achieved.
Please let me know if anyone has ever done this before using a proper function, library etc. instead of dirty hacking.
If your terminal supports ANSI escape codes, this clears the screen and moves the cursor to the first row, first column:
System.out.print("\033[H\033[2J");
System.out.flush();
This works on almost all UNIX terminals and terminal emulators. The Windows cmd.exe does not interprete ANSI escape codes.
Try this code
import java.io.IOException;
public class CLS {
public static void main(String... arg) throws IOException, InterruptedException {
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
}
}
Now when the Java process is connected to a console, it will clear the console.
Runtime.getRuntime().exec("PlatformDepedentCode");
You need to replace "PlatformDependentCode" with your platform's clear console command.
The exec() method executes the command you entered as the argument, just as if it is entered in the console.
In Windows you would write it as Runtime.getRuntime().exec("cls");.
Use the following code:
System.out.println("\f");
'\f' is an escape sequence which represents FormFeed. This is what I have used in my projects to clear the console. This is simpler than the other codes, I guess.
You need to instruct the console to clear.
For serial terminals this was typically done through so called "escape sequences", where notably the vt100 set has become very commonly supported (and its close ANSI-cousin).
Windows has traditionally not supported such sequences "out-of-the-box" but relied on API-calls to do these things. For DOS-based versions of Windows, however, the ANSI.SYS driver could be installed to provide such support.
So if you are under Windows, you need to interact with the appropriate Windows API. I do not believe the standard Java runtime library contains code to do so.
You can easily implement clrscr() using simple for loop printing "\b".
If you are using windows and are interested in clearing the screen before running the program, you can compile the file call it from a .bat file.
for example:
cls
java "what ever the name of the compiles class is"
Save as "etc".bat and then running by calling it in the command prompt or double clicking the file
I want to execute this command:
/ceplinux_work3/myName/opt/myCompany/ourProduct/bin/EXECUTE_THIS -p cepamd64linux.myCompany.com:19021/ws1/project_name < /ceplinux_work3/myName/stressting/Publisher/uploadable/00000.bin >> /ceplinux_work3/myName/stressting/Publisher/stats/ws1.project_name.19021/2011-07-22T12-45-20_PID-2237/out.up
But it doesn't work because EXECUTE_THIS requires an input file via redirect, and simply passing this command to Runtime.exec doesn't work.
Side note: I searched all over on how to solve this before coming here to ask. There are many questions/articles on the web regarding Runtime.exec and Input/Output redirect. However, I cannot find any that deal with passing a file to a command and outputting the result to another file. Plus, I am totally unfamiliar with Input/Output streams, so I have a hard time putting all the info out there together for my specific situation.
That said, any help is much appreciated.
P.S. If there are multiple ways to do this, I prefer whatever is fastest in terms of throughput.
Edit: As discussed in my last question, I CANNOT change this to a bash call because the program must wait for this process to finish before proceeding.
Unless you are sending a file name to the standard input of the process, there is no distinction of whether the data came from a file or from any other data source.
You need to write to the OutputStream given by Process.getOutputStream(). The data you write to it you can read in from a file using a FileInputStream.
Putting that together might look something like this:
Process proc = Runtime.getRuntime().exec("...");
OutputStream standardInputOfChildProcess = proc.getOutputStream();
InputStream dataFromFile = new FileInputStream("theFileWithTheData.dat");
byte[] buff = new byte[1024];
for ( int count = -1; (count = dataFromFile.read(buff)) != -1; ) {
standardInputOfChildProcess.write(buff, 0, count);
}
I've left out a lot of details, this is just to get the gist of it. You'll want to safely close things, might want to consider buffering and you need to worry about the pitfalls of Runtime.exec().
Edit
Writing the output to a file is similar. Obtain a FileOutputStream pointing to the output file and write the data you read from Process.getInputStream() to that OutputStream. The major caveat here is that you must do this operation in a second thread, since accessing two blocking streams from the same thread will lead to deadlock (see the article above).