Hey all, any tips about how to handle with terminal inputs on Clojure? I saw some old posts recommening the https://github.com/MultiMUD/clojure-lanterna library, but it seems to not being mantained. Is there any other option? My goal is to be able to get all user key pressed on terminal
Nice, thank you all, I'll try the suggestions ๐ My use case is very simple, just read the keys and need to clear the terminal also. But, I want to work on Windows also.
I asked chatgpt for a portable version of the hack above and it came up with this. FWIW, I didn't test it.
(require '[clojure.string :as str])
(defn read-char-portable []
(let [os (System/getProperty "os.name")]
(if (.startsWith os "Windows")
;; PowerShell ReadKey
(let [cmd (into-array String
["powershell" "-NoProfile" "-Command"
"$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').Character"])
pb (ProcessBuilder. cmd)]
;; IMPORTANT: let the subprocess read from the same TTY
(.redirectInput pb java.lang.ProcessBuilder$Redirect/INHERIT)
(let [p (.start pb)]
(with-open [r (.getInputStream p)]
(str/trim (slurp r)))))
;; POSIX: use stty + dd, with trap to restore terminal state
(let [bash-cmd "trap 'stty sane' EXIT; stty -echo -icanon time 0 min 1; dd bs=1 count=1 status=none 2>/dev/null"
cmd (into-array String ["bash" "-c" bash-cmd])
pb (ProcessBuilder. cmd)]
;; IMPORTANT: let the subprocess read from the same TTY
(.redirectInput pb java.lang.ProcessBuilder$Redirect/INHERIT)
(let [p (.start pb)]
(with-open [r (.getInputStream p)]
(str/trim (slurp r)))))))
;; Example:
(println "Press a key:")
(println "You pressed:" (read-char-portable))Without any second thoughts, I would look up how to do it in Java and would just do that. The goal is very simple, there's no need for any libraries to achieve that. Unless, of course, what Java offers is utterly incompetent somehow. Then there's no need for Clojure libraries here, some Java library probably already exists.
I believe this SO topic has some relevant code snippets: https://stackoverflow.com/questions/17538182/getting-keyboard-input tl;dr: Clojure doens't bring any tools for reading keys. You need to use http://java.io guts
thanks @p-himik @igrishaev,I'll take a look to Java ๐
Here's one workaround https://clojurians.slack.com/archives/CLX41ASCS/p1677150483083619
You can also use the Java โforeign memory apiโ to call out to any library / language that supports FFI you might find that does what you desire. https://docs.oracle.com/en/java/javase/21/core/foreign-function-and-memory-api.html
I have been actively working on this
or rather, i made some progress then someone else picked up my slack
I recently did something like that, see here:
https://github.com/gaverhae/misc/pull/363/files
Very similar to Borkdude's sample above, just using clojure.java.process instead. If you need something more complicated, JLine would be the first place I look.
(got distracted, forgot to link)
(1 sec)