2
import java.util.Scanner;
import java.util.regex.Pattern;

public class dsr {
    final static String ESC = "\u001b";
    final static String ANSI_PREFIX = ESC + "[";
    final static String ANSI_DSR = ANSI_PREFIX + "6n";
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("1234567" + ANSI_DSR);
        System.out.println("@" + scan.next(Pattern.compile(".*")));
    }
}

output

This code tries to read the return from the terminal with a scanner, but the return is not captured and is displayed directly. The scanner waits for a keyboard entry. How to retrieve the returned value ^[[5;8R

ANSI_escape_code

seenukarthi
  • 8,241
  • 10
  • 47
  • 68
  • Tried doing the same -- you can read without echo using `System.console().readPassword()`, but the method waits for newline. If you press enter the control sequence `^[[5;8R` will be read. Haven't been able to figure out how to force a newline on stdin... – trozen Apr 21 '20 at 13:37

2 Answers2

0

You can construct a java.io.FileInputStream that reads from the FileDescriptor.in file descriptor - this will be able to read the output from the terminal (It's what System.console().readPassword() uses internally...)

Just use something like a java.io.InputStreamReader instance to read from the file input stream until you get an R character (which is the suffix for the cursor position response) - After that you can use regex or parse it yourself to obtain the cursor position...

I had this issue myself when trying to make an ANSI graphics library for Java, finally figured it out :)

Doom screenshot displayed in PowerShell 7.1.3 using ANSI graphics

bluelhf
  • 71
  • 1
  • 7
0

You have to disable canonical mode in terminal to be able to read input stream without blocking until the user press enter.

Here is the information about canonical mode: http://uw714doc.xinuos.com/en/SDK_sysprog/_TTY_in_Canonical_Mode.html

It's not possible to turn off the canonical mode using ANSI CSI

But you can use this hack, which I found in Lanterna source code:

It uses /dev/tty which is a special file, representing the terminal for the current process.

Here are the steps you have to do:

  1. Create a new process via ProcessBuilder and redirect input to dev/tty
  2. Run command /bin/stty -icanon which disables canonical mode and since you set redirect it will get applied to your current terminal session where your program runs.
ProcessBuilder pb = new ProcessBuilder(new String[] {"/bin/stty", "-icanon", "Joe"});
pb.redirectInput(Redirect.from(new File("/dev/tty")));

Process process = pb.start();

stty is a tool used to set the input and output settings for the terminal communication interface https://man7.org/linux/man-pages/man1/stty.1.html

You can also disable echo in order to hide the cursor position from the output.

Just run /bin/stty -echo, to enable it again run /bin/stty echo

Sergiy Kozachenko
  • 1,399
  • 11
  • 31