1
votes

I've done some research here and elsewhere covering this question's topic and I've discovered jline3, which certainly seems to be a clear solution and offers a great deal of significant cross-platform advantages and features.

However, as both a way to better understand how Java uses stream readers and input, including raw bytes, and to implement a basic text-based adventure game in a Linux terminal, I'd like to just be able to suppress or remove arrow key escape codes from stdin upon user input.

This doesn't seem to be possible via Scanner, and I'm not certain how to use Java to place the terminal into a raw input mode - if there is a way to implement that via shell script, I've been unable to find out how so far. I'm using a basic shell script to call my Java program and pass in some system properties, so that would be a fine solution as well.

I've used so far a combination of ByteBuffer, CharBuffer, Decoder, etc., that I've seen from other questions and through some initial research, but have been unable to achieve what I'm looking for.

How could I simply have my Java program await user input and not display or capture the arrow key escape characters (e.g., ^[[A, ^[[B)?

Thanks for any assistance or other resources to look into.

Edit/Update:

Thanks to everyone who tossed in their responses to this question. Ultimately I'm working on a solution that almost fits exactly what I wanted and is a combination of the Java Console class and its regex functionality.

A very basic framework is below. Essentially I opted for an exclude all, include some approach where all characters are banned but the ones I compile into a Pattern which are allowed to be printed to the screen.

This also lets me test for other important input keys like Enter to enter and exit the command mode of the game as I wanted the game to react to keys for "movement" and have the user be able to hit Enter and type out some command.

I had to fiddle with stty to allow for this solution and the Java application is launched via a bash script.

Bash Script:

#!/bin/bash

# Save current terminal settings
STTY_SAVE=$(stty -g)

# Disable need to press [Enter] in order to have input processed
stty cbreak
# Disable the echoing of input
stty -echo
# Tell the terminal that erasure on the console should produce a backspace cursor movement
stty erase ^H

# Execute application
java reader_testing.Main

# Restore saved terminal settings
stty $STTY_SAVE
exit 0

Note: stty erase ^H also seems to be what allows Console in Java to capture the backspace key character code \010 on *nix operating systems. Without that line it appears to perform a delete (?)

Java Code:

Console console = System.console();    

int symbol = 0;
char character = 0;

String matchString = new String();
StringBuilder input = new StringBuilder();

Pattern allowed = Pattern.compile( "[a-z0-9 !@#$%^&*()_+-=]" );
Matcher matcher = null;

while ( true ) { // This is an arbitrary loop for the example
    try {
        symbol = console.reader().read();

        if ( symbol == 10 ) { // 10 = Enter
            break;
        }

        character = (char) symbol;

        matchString = Character.toString( character );

        matcher = allowed.matcher( matchString );

        if ( matcher.find() ) {
            input.append( character );

            System.out.print( "\r" + input );
        }
    } catch ( IOException e ) {
        e.printStackTrace();
    }
}

System.out.println( "\nYou entered: " + input );

Problems:

  1. Still working on backspace functionality with rewriting the input StringBuilder object's characters with an "empty" character (e.g., char c = 0; and resizing it. This might ultimately not work at all.

  2. I've not been able to find a way to exclude capital A, B, C, and Ds which follow the escape code sequences representing arrow keys, so I had to ban all capital letters. I've tried to wait until the reader detects no more input and then parse that input, but haven't been able to successfully implement that.

  3. Special keys like Insert and Delete produce character codes that include numerals that still get printed. I'm not sure yet how to prevent this from happening without banning numerals (same as the issue with arrow keys and capital letters).

In the end, none of this might work or will be fairly limited, but it's been fun playing around with this and if worse comes to worst I can make backspace wipe out the whole input string. Typing in commands is not a major aspect of the game.

2

2 Answers

0
votes

You can use the java.io.Console class. The Console.writer() handle the underlying character encoding automatically. The Console.readLine() retrieve a single line of text from the user, and wait until he press the Enter key to terminate. There is also a bunch of other methods which can help you to make your Command-Line game.

0
votes

Change the Regex as per your need to accept what you think is right or wrong.

public class PasscodeScanner {

 public static void main(String args[]) {

    Scanner key = new Scanner(System.in);
    while(getInput(key)) {
        //keep doing until we you're good
    }
    System.out.println("Congrats, you're good.");
}

private static boolean getInput(Scanner key) {
    System.out.print("Enter your passcode: ");
    String sentence = key.nextLine();
    if(validate(sentence)) {
        System.out.println("You are cleared");
        return false;
    }
    return true;
}

private static boolean validate(String entered) {
    //change regex as per your need
    Pattern pattern = Pattern.compile("[a-z]");
    Matcher matcher = pattern.matcher(entered);
    if (matcher.find()) {
        return true;
    }
    return false;
}
}