Bug in JLine2? ConsoleReader.clearScreen - java

EDIT: This feature only occurs when I invoke the clearScreen method of ConsoleReader! Any other changes don't have an effect. Is this then a bug in JLine2?
JLine2:
Why, when I run this, do I get two console prompts directly following each other (----> ---->)?
Is it because two consoles are being created? I do not understand how.
What am I failing to see here?
import java.io.IOException;
import jline.console.ConsoleReader;
class TextUi implements Ui {
private static final String prompt1 = "----> ";
public void homeScreen() {
try {
ConsoleReader con = new ConsoleReader();
con.setPrompt(prompt1);
con.clearScreen();
System.out.println("Press any key to continue...");
con.readCharacter();
con.clearScreen();
System.out.println("Here is a prompt. Do something and press enter to continue...");
String line = con.readLine();
con.clearScreen();
System.out.println("You typed: ");
System.out.println(line);
System.out.println("Press any key to exit. ");
con.readCharacter();
con.clearScreen();
} catch (IOException e) {
e.printStackTrace();
}
}
public void exitSplash() {
System.out.println("Thank You. Goodbye.");
System.out.println("");
}
public void creditsScreen() {
}
public static void main (String argv[]) {
TextUi ui = new TextUi();
ui.homeScreen();
ui.exitSplash();
}
}

This is not a bug, you just need to call con.flush() after each time you call con.clearScreen().
The clearScreen method doesn't calls flush() automatically (it might work in some cases without flushing) but the readLine method does, so the screen is actually clearing only when you call con.readLine(). This is causing to the last System.out.println (before the readLine) to be cleared even it was called after con.clearScreen().
Your code inside the try block should be changed to:
ConsoleReader con = new ConsoleReader();
con.setPrompt(prompt1);
con.clearScreen();
con.flush();
System.out.println("Press any key to continue...");
con.readCharacter();
con.clearScreen();
con.flush();
System.out.println("Here is a prompt. Do something and press enter to continue...");
String line = con.readLine();
con.clearScreen();
con.flush();
System.out.println("You typed: ");
System.out.println(line);
System.out.println("Press any key to exit. ");
con.readCharacter();
con.clearScreen();
con.flush();

Related

User prompt is one line off for some reason?

I'm asking for user input, but I want it to follow the enter: prompt and be on the same line.
My code produces this as a result input from 'ok'
ok
enter: ok
ok
I would like the user input to start after enter: - hoping for this as a result...
enter: ok
ok
Here's my code:
private static Scanner u = new Scanner(System.in);
try{
while(u.hasNext() && !u.equals("exit")) {
System.out.printf("enter: ");
usrInput = u.next();
System.out.printf(usrInput + "\n");
System.out.println(findClosestMatch(usrInput.toLowerCase()));
}
} catch(NullPointerException e) {
System.out.println("Error - NullPointerException");
}
u.hasNext() is blocking on input before the prompt. It's unnecessary, since calling u.next() afterwards will block anyway. And you're comparing the actual Scanner object to "exit", which will never be true. Try this:
while (true) {
System.out.print("enter: ");
if (!u.hasNext() || (usrInput = u.next()).equals("exit")) {
break;
}
System.out.println(usrInput);
System.out.println(findClosestMatch(usrInput.toLowerCase()));
}

Java: How to Automatically Restart A Console Program If The "Else" Statement Is Triggered

I am making a simple program that asks for a password before you can start the program. When my user inputs the wrong password, they get an "Access Denied," warning. I achieve this using an If/Else Statement. What I want to be able to do is to re-run my program if they enter the wrong password, as they cannot type in the console again if they get it wrong.
Here is my workspace:
import java.util.Scanner;
public class PasswordProtected {
public static void main (String args[]){
Scanner Password = new Scanner (System.in);
String mainpassword, userInput;
mainpassword = ("Jacob");
System.out.println("Please enter the password to continue.");
userInput = Password.nextLine();
System.out.println("Verifying Password");
if (userInput.equals(mainpassword)){
System.out.println("Access Granted");
System.out.println("Welcome!");
}else{
System.out.println("Access Denied");
}
}
}
I do realize that I could copy some thing like this over and over again, however, it is a waste of space is is not unlimited.
System.out.println("Please enter the password to continue.");
userInput = Password.nextLine();
System.out.println("Verifying Password");
if (userInput.equals(mainpassword)){
System.out.println("Access Granted");
System.out.println("Welcome!");
}else{
System.out.println("Access Denied");
}
}
Please note that I am new at programming, and may need a bit of extra help.
If the Else Statement is triggered, how can I fully restart my program without the use of manually clicking the run button again?
You don't need to restart your program. Use a loop to ask for the password again if it is incorrect. For example in semi-pseudo code with while statement:
userInput = input.nextLine();
while ( !userInput.equals(mainpassword) ){
userInput = input.nextLine();
}
Try while(true) loop
String mainpassword = ("Jacob");
String userInput = null;
Scanner Password = new Scanner (System.in);
while(true) {
userInput = Password.nextLine();
if (userInput.equals(mainpassword)){
break;
} else {
System.out.println("Access Denied");
}
}
System.out.println("Access Granted");
System.out.println("Welcome!");
If you still feel to restart any Java program, then the main() method can be called from anywhere else in your code. You can just call this method, passing in any necessary String parameters. Use a thread to do so, as below
Thread t = new Thread() {
public void run() {
String[] args = { };
PasswordProtected.main(args);
}
};
t.start();
If you want to re-launch your application in a new process, you can use
Runtime.getRuntime().exec(...);

Add History to Custom Shell

I am creating a custom shell in Java. I have added history to it so that when up arrow is pressed it goes to the previous command, but the up arrow seems to not be working
Here is my code:
public class MyShell {
public static class JavaStringHistory
{
private List<String> history = new ArrayList<String>();
}
public static void main(String[] args) throws java.io.IOException {
JavaStringHistory javaStringHistory = new JavaStringHistory();
javaStringHistory.history.add("");
Integer indexOfHistory = 0;
String commandLine;
BufferedReader console = new BufferedReader
(new InputStreamReader(System.in));
//Break with Ctrl+C
while (true) {
//read the command
System.out.print("Shell>");
commandLine = console.readLine();
javaStringHistory.history.add(commandLine);
//if just a return, loop
if (commandLine.equals(""))
continue;
//history
if (commandLine.equals(KeyEvent.VK_UP))
{
System.out.println("up arrow");
}
//help command
if (commandLine.equals("help"))
{
System.out.println();
System.out.println();
System.out.println("Welcome to the shell");
System.out.println("Written by: Alex Frieden");
System.out.println("--------------------");
System.out.println();
System.out.println("Commands to use:");
System.out.println("1) cat");
System.out.println("2) exit");
System.out.println("3) clear");
System.out.println();
System.out.println();
System.out.println("---------------------");
System.out.println();
}
if (commandLine.equals("clear"))
{
for(int cls = 0; cls < 10; cls++ )
{
System.out.println();
}
}
if(commandLine.startsWith("cat"))
{
System.out.println("test");
//ProcessBuilder pb = new ProcessBuilder();
//pb = new ProcessBuilder(commandLine);
}
else
{
System.out.println("Incorrect Command");
}
if (commandLine.equals("exit"))
{
System.out.println("...Terminating the Virtual Machine");
System.out.println("...Done");
System.out.println("Please Close manually with Options > Close");
System.exit(0);
}
indexOfHistory++;
}
}
}
All I am getting is
Shell>^[[A
Incorrect Command
Shell>
Any thoughts?
There are several problems with your approach:
User blackSmith has mentioned before me that system console handling is platform-dependent when it comes to cursor key handling and similar topics.
BufferedReader.readLine is not a smart choice to use for history cycling in a shell because you want the shell to immediately react to cursor keys and not force the user to press Return or Enter. Reading whole lines is only required for user commands. Thus, you need to scan the keyboard input for each single character or key code and decide by yourself if it is e.g. a cursor key (up/down for history cycling, left/right for cursor movement within the command line) or delete/backspace for command line editing and so forth.
The text strings which are created by reading control characters via readLine can depend on the OS, maybe even on the shell and the character set (UTF-8, ISO-8859-1, US ASCII etc.) on the console.
Built-in shell editing functions like command history might get in the way with readLine, e.g. on Linux I see the "^[[A" stuff for cursor up, on Windows the cursor keys are passed through to the built-in command history feature of cmd.exe. I.e. you need to put the console in raw mode (line editing bypassed and no Enter key required) as opposed to cooked mode (line editing with Enter key required).
Anyway, so as to answer your initial question about how to find out which key codes are produced by BufferedReader.readLine, it is actually quite simple. Just dump the bytes to the console like so:
commandLine = console.readLine();
System.out.println("Entered command text: " + commandLine);
System.out.print ("Entered command bytes: ");
for (byte b : commandLine.getBytes())
System.out.print(b + ", ");
System.out.println();
Under Linux cursor up might be something like "27, 91, 65" or just "91, 65", depending on the terminal. cursor down ends with "66" instead on my system. So you could do something like:
public class MyShell {
private static final String UP_ARROW_1 = new String(new byte[] {91, 65});
private static final String UP_ARROW_2 = new String(new byte[] {27, 91, 65});
private static final String DN_ARROW_1 = new String(new byte[] {91, 66});
private static final String DN_ARROW_2 = new String(new byte[] {27, 91, 66});
// (...)
public static void main(String[] args) throws IOException {
// (...)
// history
else if (commandLine.startsWith(UP_ARROW_1) || commandLine.startsWith(UP_ARROW_2)) {
System.out.println("up arrow");
}
else if (commandLine.startsWith(DN_ARROW_1) || commandLine.startsWith(DN_ARROW_2)) {
System.out.println("down arrow");
}
// (...)
}
}
But all this is just for explanation or demonstration and so as to answer your question - I do like to get the bounty. ;-)
Maybe a way to go is not to re-invent the wheel and use the work of others, e.g. a framework like JLine. It is not perfect either from what I have heard, but goes way further than anything you can develop by yourself in a short time. Someone has written a short introductory blog post about JLine. The library seems to do just what you need. Enjoy!
Update: I gave JLine 2.11 a little try with this code sample (basically the one from the blog post plus tab filename completion:
import java.io.IOException;
import jline.TerminalFactory;
import jline.console.ConsoleReader;
import jline.console.completer.FileNameCompleter;
public class MyJLineShell {
public static void main(String[] args) {
try {
ConsoleReader console = new ConsoleReader();
console.addCompleter(new FileNameCompleter());
console.setPrompt("prompt> ");
String line = null;
while ((line = console.readLine()) != null) {
console.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
TerminalFactory.get().restore();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
It works nicely on Windows and Linux, but for me tab completion only works on Linux, not on Windows. Anyway, command history works well on both platforms.
VK_UP is an integer constant, while in.readLine() is a string.
They won't equal each other. Why don't you try to test for the code that appears in console usually when you click up arrow? So like:
if (in.readLine().equals("^[[A"))
and then you could clear the line, and write the command in the arraylist with the highest index.
Also, I tested this and found a bug. Change your if statements besides the first to else if; after any command it will eventually get to the else and display "Incorrect Command"

Hide input on command line

I know that command line interfaces like Git and others are able to hide input from a user (useful for passwords). Is there a way to programmtically do this in Java? I'm taking password input from a user and I would like their input to be "hidden" on that particular line (but not on all of them). Here's my code for it (though I doubt it would be helpful...)
try (Scanner input = new Scanner(System.in)) {
//I'm guessing it'd probably be some property you set on the scanner or System.in right here...
System.out.print("Please input the password for " + name + ": ");
password = input.nextLine();
}
Try java.io.Console.readPassword. You'll have to be running at least Java 6 though.
/**
* Reads a password or passphrase from the console with echoing disabled
*
* #throws IOError
* If an I/O error occurs.
*
* #return A character array containing the password or passphrase read
* from the console, not including any line-termination characters,
* or <tt>null</tt> if an end of stream has been reached.
*/
public char[] readPassword() {
return readPassword("");
}
Beware though, this doesn't work with the Eclipse console. You'll have to run the program from a true console/shell/terminal/prompt to be able to test it.
Yes can be done. This is called Command-Line Input Masking. You can implement this easily.
You can uses a separate thread to erase the echoed characters as they are being entered, and replaces them with asterisks. This is done using the EraserThread class shown below
import java.io.*;
class EraserThread implements Runnable {
private boolean stop;
/**
*#param The prompt displayed to the user
*/
public EraserThread(String prompt) {
System.out.print(prompt);
}
/**
* Begin masking...display asterisks (*)
*/
public void run () {
stop = true;
while (stop) {
System.out.print("\010*");
try {
Thread.currentThread().sleep(1);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
}
}
/**
* Instruct the thread to stop masking
*/
public void stopMasking() {
this.stop = false;
}
}
With using this thread
public class PasswordField {
/**
*#param prompt The prompt to display to the user
*#return The password as entered by the user
*/
public static String readPassword (String prompt) {
EraserThread et = new EraserThread(prompt);
Thread mask = new Thread(et);
mask.start();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String password = "";
try {
password = in.readLine();
} catch (IOException ioe) {
ioe.printStackTrace();
}
// stop masking
et.stopMasking();
// return the password entered by the user
return password;
}
}
This Link discuss in details.
JLine 2 may be of interest. As well as character masking, it'll provide command-line completion, editing and history facilities. Consequently it's very useful for a CLI-based Java tool.
To mask your input:
String password = new jline.ConsoleReader().readLine(new Character('*'));
There is :
Console cons;
char[] passwd;
if ((cons = System.console()) != null &&
(passwd = cons.readPassword("[%s]", "Password:")) != null) {
...
java.util.Arrays.fill(passwd, ' ');
}
source
but I don't think this works with an IDE like Eclipse because the program is run as a background process rather than a top level process with a console window.
Another approach is to use the JPasswordField in swing with the accompanying actionPerformed method:
public void actionPerformed(ActionEvent e) {
...
char [] p = pwdField.getPassword();
}
source
Here is an example using console.readPassword(...); in an IDE. I use Netbeans. Note: In your IDE, Scanner will be used and it will show the password!. In the console, console.readPassword(..) will be used and it will not show the password!.
public static void main(String[] args) {
//The jar needs to be run from the terminal for console to work.
Scanner input = new Scanner(System.in);
Console console = System.console();
String username = "";
String password = "";
if (console == null)
{
System.out.print("Enter username: ");
username = input.nextLine();
System.out.print("Enter password: ");
password = input.nextLine();
}
else
{
username = console.readLine("Enter username: ");
password = new String(console.readPassword("Enter password: "));
}
//I use the scanner for all other input in the code!
//I do not know if there are any pitfalls associated with using the Scanner and console in this manner!
}
Note: I do not know if there are any pitfalls associated with using the Scanner and console in this manner!
The class Console has a method readPassword() that might solve your problem.

Get input from the keyboard without pausing the program

I'm writing Java on Windows 7, and I want to be able to work with the input from the keyboard, which I can only presume is the standard input.
I've tried to use BufferedInput, System.in, and Scanner, but all of them require the program to pause and wait for an end of line or return! Is there anyway to just collect and record the data as it is used, and not have to wait for a return?
Here is a quick solution:
public static void main(String[] args) {
Thread inputThread = new Thread(new Runnable() {
#Override
public void run() {
Scanner scan = new Scanner(System.in);
String input = "";
while (true) {
System.out.println("Type something: ");
input = scan.nextLine();
System.out.println("Input: "+input);
}
}
});
inputThread.start();
while (true) {
System.out.println("");
System.out.println("test");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The main thread prints "test" every second. And the inputThread asks the user to type something then prints what he wrote. It's just a "visual" solution, you certainly don't want to print something while the user is typing.

Categories

Resources