Entrada de console de caractere único em java/clojure
-
13-09-2020 - |
Pergunta
Como posso ler um único caractere/chave do console sem precisar pressionar Enter?Há um entrada antiga no banco de dados de bugs da Sun alegando que isso não pode ser feito em java puro.Eu encontrei essas abordagens
- JNI
- Linha J [http://jline.sourceforge.net/]
- Javacursos [http://sourceforge.net/projects/javacurses/]
Eu esperaria adicionar um único magic-readkey.jar
para o meu caminho de classe e escrever algumas linhas de código, como (def just-hit (com.acme.MagicConsole/read-char))
.
Solução
Aqui está um aplicativo de "eco imediato" usando JLine que irá imprimir int
s correspondentes a pressionamentos de tecla registrados, estruturados como um Leiningen projeto:
project.clj
:(defproject con "1.0.0-SNAPSHOT" :description "FIXME: write" :main con.core :dependencies [[org.clojure/clojure "1.1.0"] [org.clojure/clojure-contrib "1.1.0"] [jline "0.9.94"]])
src/con/core.clj
:(ns con.core (:import jline.Terminal) (:gen-class)) (defn -main [& args] (let [term (Terminal/getTerminal)] (while true (println (.readCharacter term System/in)))))
A funcionalidade em questão é fornecida pelo jline.Terminal
classe, que fornece um método estático getTerminal
retornando uma instância de uma subclasse específica da plataforma que pode ser usada para interagir com o terminal.Veja o Javadoc para mais detalhes.
Vamos ver o que asdf
parece...
$ java -jar con-1.0.0-SNAPSHOT-standalone.jar
97
115
100
102
(C-c ainda mata o aplicativo, é claro.)
Outras dicas
Para quem estiver lendo isso em 2015 e além, observe que as versões mais recentes do JLine não possuem mais o método Terminal/getTerminal
.Tenho certeza de que há outra maneira (possivelmente melhor) de fazer isso agora com JLine2, mas você pode simplesmente usar jline "0.9.94"
e a resposta aceita ainda funcionará, pelo menos até o Clojure 1.6 (observe que você não precisa mais exigir clojure.contrib
).
Como alternativa, recomendaria o excelente lanterna-clojure, que é um wrapper Clojure em torno do Java lanterna biblioteca.Como você pode ver em os documentos, há get-key
e get-key-blocking
funções para leitura em caracteres únicos de entrada.
Se você quiser usar o jline2, existe um ConsoleReader
classe disponível que faz praticamente a mesma coisa que Michał Marczyk explicou acima:
(ns con.core
(:import jline.console.ConsoleReader)
(:gen-class))
(defn -main [& args]
(while true (->> (ConsoleReader.) (.readCharacter) (println))))