Como saber que tecla presione en PROMPT antes de imprimirse?

Hola a todos, queriendo hacer un programa que corra sobre consola. Me tope con el problema que no se como captura un evento de teclado.
Es un AutoCompletador de consola lo que deseo hacer, muy parecido al que se usa en Linux, que con un tabulador puedo autocompletar la palabra.
Revise las clases de java.io, por que según yo cuando presiono por ejemplo la letra 'a' manda a llamar a java.lang.System.in osease un InputStream... y la verdad me quedo frito, no se como decirle a java que no imprima 'a', si no que haga algo antes y que no imprima dicha letra, intente con PushbackInputStream pero no supe como hacerle.

Gracias por la ayuda : D

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

System.console()

Si lo que quieres es algo como no imprimir un password, revisa System.console() (la clase Console, nueva en Java 6). Usando puro STDIN y STDOUT no puedes evitar que se impriman caracteres o reemplazarlos, etc sino que tienes que usar ya caracteres de control de TTY y cosas así. Me parece que hay algo en Apache Commons para eso.

Imagen de rodrigo salado anaya

@System.console()

Hola ezamudio... intente algo como esto (nota: es una aberración pero espero dejar clara la idea de lo que intento hacer)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static String TEXTO = "";

    public static void main(String args[]) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        ThreadTxt threadTxt = new ThreadTxt();
        Thread thread = new Thread(threadTxt);
        thread.start();

        while (true) {
            TEXTO = br.readLine();
            System.out.println(TEXTO);
        }
    }
}

Y

public class ThreadTxt implements Runnable {

    public void run() {
        while (true) {
            if (Main.TEXTO.endsWith("!")) {
                System.out.println("TIENE !");
            }
        }
    }
}

Ya había probado con System.console. Pero intentare con la foncion de readPassword() . Segun yo si primero leo el en String sin imprimirlo y con un hilo escribir lo que voy leyendo, y ya veo si tiene o no un tabulador.

Otra cosa que se me ocurre es escribir todo en un fichero y ver si su tamaño cambia revisarlo en busca de un tabulador.

Estoy aferrado con esto, espero explicarme lo mejor posible gracias por todo a todos bye : )

Imagen de ezamudio

buffer

El problema es que hay buffers. Si usas un BufferedReader por la comodidad de leer una linea entera con br.readLine() entonces pierdes algo de control; el control pasa a ese método hasta que el usuario da ENTER y entonces ya te regresa la cadena.

Para manejar un autocompletador necesitas manipular directamente System.in, que es un InputStream crudo, porque puede aceptar incluso datos binarios de un pipe o de un redireccionamiento en línea de comando. Necesitas hacer un read() de un solo caracter, y aún así luego no funciona como quieres porque hay un buffer a nivel sistema operativo. Por ejemplo este código:

System.out.printf("Teclea algo. Comenzamos %s%n", new Date());
ArrayList<Date> fechas = new ArrayList<Date>();
int b = System.in.read();
StringBuilder linea = new StringBuilder();
while (b >= 0 && b != '\n') {
  linea.append((char)b);
  fechas.add(new Date());
  b = System.in.read();
}
System.out.printf("Terminamos de leer linea %s%n", new Date());
System.out.printf("Tecleaste '%s'%nFechas en que tecleaste cada letra:", linea);
for (Date d : fechas) {
  System.out.println(d);
}

Cada que se lee un byte de System.in, se guarda la fecha en que se leyó ese byte, y se agrega la letra al StringBuilder. Al final, esperarías ver la linea que tecleaste hasta dar ENTER, y en las fechas, ver una lista de fechas distintas, sobre todo si a propósito tecleas muy lento y dejas pasar unos segundos entre un teclazo y otro. Pero no; córrelo y verás que las fechas salen todas iguales. Eso es porque el primer read() se queda esperando entrada; tú puedes teclear cosas durante una hora, y hasta que das ENTER se pasa todo lo que tecleaste al programa, que entonces lee byte por byte hasta encontrar el salto de linea (o un EOF), pero entonces cada read() se ejecuta uno tras otro. Todas las fechas que se imprimen (una por caracter capturado) son iguales a la que se imprime en la linea del mensaje de que ya se terminó de capturar.

Y si además analizas la cadena que leíste, o guardas cada valor leído como byte en vez de como parte de una cadena, verás que no se guardan los backspaces ni nada de eso. Es decir si tecleas "javax" y luego backspace, y luego "Mexico", lo que capturaste no incluye ni la x ni el backspace. Todo eso se manejó en la terminal/línea de comando/etc la cosa es que se quedó a nivel sistema operativo, no le llegó a tu programa.

Imagen de rodrigo salado anaya

@ezamudio

Sip... :'( hice una pruebas con todo lo que me dices (algo con CharArrayReader input = new CharArrayReader(charArray, 0, 1);) y ya me había dado cuenta que no se asignaba el contenido en entrada hasta un \n o EOF y en general lo que comentas de que ya es onda de SO.
No podre ( ' Yo ' que de seguro si se puede y si copio y pego la solución pues ya que chiste : P) hacer lo que deseo con java (desde consola).

Solo me queda probar con java.nio.CharBuffer (patadas de ahogado jejeje). Pero gracias por todo bye.