Come leggere un singolo carattere dalla console in Java (mentre l'utente lo digita)?


110

C'è un modo semplice per leggere un singolo carattere dalla console mentre l'utente lo digita in Java? È possibile? Ho provato con questi metodi ma tutti aspettano che l'utente prema il tasto Invio :

char tmp = (char) System.in.read();
char tmp = (char) new InputStreamReader(System.in).read ();
char tmp = (char) System.console().reader().read();           // Java 6

Sto iniziando a pensare che System.in non sia a conoscenza dell'input dell'utente fino a quando non viene premuto Invio .

Risposte:


57

Quello che vuoi fare è mettere la console in modalità "raw" (modifica della riga ignorata e nessun tasto Invio richiesto) invece della modalità "cucinata" (modifica della riga con il tasto Invio richiesto). Sui sistemi UNIX, il comando 'stty' può cambiare modalità.

Ora, per quanto riguarda Java ... vedere Input da console non bloccante in Python e Java . Estratto:

Se il tuo programma deve essere basato su console, devi commutare il tuo terminale dalla modalità linea alla modalità caratteri e ricordati di ripristinarlo prima che il programma si chiuda. Non esiste un modo portabile per farlo tra i sistemi operativi.

Uno dei suggerimenti è usare JNI. Ancora una volta, non è molto portatile. Un altro suggerimento alla fine del thread, e in comune con il post sopra, è guardare come usare jCurses .


4
Nemmeno JCurses è molto portabile .... Dal README di JCurses: "JCurses consiste di due parti: la parte indipendente dalla piattaforma e la parte dipendente dalla piattaforma, che consiste in una libreria condivisa nativa che rende disponibili le operazioni di input e output primitive per la prima parte ".
Ryan Fernandes

6
@RyanFernandes suona abbastanza portabile per me - unico strumento che può essere eseguito su più sistemi (utilizzando dipendenze diverse)
Antoniossss

25

Devi mettere la tua console in modalità raw. Non esiste un modo integrato indipendente dalla piattaforma per arrivarci. jCurses potrebbe essere interessante, però.

Su un sistema Unix, questo potrebbe funzionare:

String[] cmd = {"/bin/sh", "-c", "stty raw </dev/tty"};
Runtime.getRuntime().exec(cmd).waitFor();

Ad esempio, se vuoi prendere in considerazione il tempo tra le sequenze di tasti, ecco il codice di esempio per arrivarci.


Ha funzionato bene per me sotto Linux
MrSmith42

4
Ha funzionato anche su Mac. Probabilmente vorrai menzionare che stty cooked </dev/ttydovrebbe essere eseguito quando il programma deve tornare alla modalità bufferizzata e sicuramente prima che il programma esca.
Kelvin

15

Non esiste un modo portatile per leggere i caratteri grezzi da una console Java.

Alcune soluzioni alternative dipendenti dalla piattaforma sono state presentate sopra. Ma per essere davvero portabile, dovresti abbandonare la modalità console e utilizzare una modalità a finestre, ad esempio AWT o Swing.


22
Non capisco bene perché ad esempio Mono (o CLR) ha il System.Console.ReadKeyche funziona su tutte le piattaforme. Java distribuisce anche JVM e JRE per ogni piattaforma con librerie e implementazioni dipendenti dalla piattaforma, quindi non è una scusa.
Martin Macak

13

Ho scritto una classe Java RawConsoleInput che utilizza JNA per chiamare le funzioni del sistema operativo di Windows e Unix / Linux.

  • Su Windows utilizza _kbhit()e _getwch()da msvcrt.dll.
  • Su Unix utilizza tcsetattr()per passare la console in modalità non canonica, System.in.available()per verificare se i dati sono disponibili e System.in.read()per leggere i byte dalla console. A CharsetDecoderviene utilizzato per convertire i byte in caratteri.

Supporta l'ingresso non bloccante e la modalità di mixaggio raw e l'ingresso in modalità linea normale.


Quanto è stato testato / sottoposto a stress test?
Finanzia la causa di Monica

2
@QPaysTaxes I test di stress sono difficili per l'input della console. Penso che in questo caso sarebbe più importante testarlo in vari ambienti (diverse versioni Windows / Linux, 64/32 bit, Linux tramite SSH, Telnet, porta seriale o console desktop, ecc.). Finora lo uso solo nei miei strumenti di test privati. Ma il codice sorgente è relativamente piccolo, rispetto ad altre soluzioni (come JLine2 che utilizza Jansi). Quindi non c'è molto che possa andare storto. L'ho scritto, perché JLine2 non supporta l'immissione di un singolo carattere senza blocco.
Christian d'Heureuse

Questo è ciò che intendevo per stressato - probabilmente è la parola sbagliata; colpa mia. Comunque bello! L'ho rubato ^ H ^ H ^ H ^ H ^ H ^ H usato in un mio progetto per la scuola e ha aiutato un sacco.
Finanzia la causa di Monica

Ehi, questa lezione sembra fantastica. Tuttavia: non riesco a farlo funzionare .. come dovrei usarlo? Ho riscontrato il blocco di System.in fino a quando non premo CTRL + D (su Linux) e ora ho letto delle modalità della console e simili. Penso che il tuo RawConsoleInput sia quello che sto cercando, ma come lo uso?
Igor

@Igor Chiama RawConsoleInput.read (booleano) per leggere un carattere della tastiera. È documentato nel codice sorgente (RawConsoleInput.java).
Christian d'Heureuse

8

Usa jline3 :

Esempio:

Terminal terminal = TerminalBuilder.builder()
    .jna(true)
    .system(true)
    .build();

// raw mode means we get keypresses rather than line buffered input
terminal.enterRawMode();
reader = terminal .reader();
...
int read = reader.read();
....
reader.close();
terminal.close();

Ho scoperto che le soluzioni basate su RawConsoleInput non funzionavano su MacOS High Sierra; tuttavia, questo funziona perfettamente.
RawToast

jline ha praticamente tutto il necessario per creare una console / un sistema terminale interattivo. Funziona alla grande su Linux. Per un esempio più completo, guarda: github.com/jline/jline3/blob/master/builtins/src/test/java/org/… . Ha il completamento automatico, la cronologia, la maschera della password, ecc.
Lepe
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.