owl
owl copied to clipboard
Portable getch?
I’ve been unable to find a simple & portable getch
implementation for Elixir. The use case is to detect single keypress events, without needing the return key.
Comparable tools like inquirer/npm and tty/ruby use getch
to build features like type-ahead, pull-down menus, etc.
To implement getch
I've looked at ex_ncurses, rustler, System.cmd, Ports, etc. This is the best I’ve come up with so far:
#!/usr/bin/env elixir
ruby_cmd = ~S"""
ruby -e '
require "io/console"
@output = IO.new(4)
@output.sync = true
char = STDIN.getch
@output.write(char)
'
"""
IO.write("Press a key > ")
port = Port.open({:spawn, ruby_cmd}, [:binary, :nouse_stdio])
receive do
{^port, {:data, result}} -> IO.puts("\nChar: #{result}")
end
This works on my Linux dev machine, but depends on Ruby.
Does anyone know of a portable getch
implementation? Maybe with Rustler or precompiled binaries or ???
I found this crate https://crates.io/crates/getch it is quite small, we can play with it and Rustler and if it works okay, then implement as a separate package
@fuelen @andyl I tried using Rustler + getch but couldn't get it to work. I think it is due to BEAM blocking the stdin port (here).
So I came with a dirty solution that closes the stdin port opened by the user driver and re-opens it on a process I can control: https://gist.github.com/antedeguemon/565d65718a4625dcec2d83d51614a9c5
It works well but it has the big downside of overriding the IO port, meaning regular IO operations won't work. Here is an asciicast of the script:
Hey @antedeguemon
Cool, that's interesting. I went to Google to find what is tty_sl and quickly found this repo https://github.com/swalkerhppr/elixir-io_tty :)
Seems like manual stop of the port can be replaced with -noinput
flag. @andyl have you seen the repo?
@antedeguemon thanks for posting your code I was able to run it locally. Studying.
@fuelen - have not seen elixir-io_tty
before - it looks interesting!
I had another look - seems like tty_sl
is an Erlang module that makes it possible to read character-by-character, and is used in IEx.CLI.start
. I am unable to find any docs on tty_sl
. Anyone have a link for this?
Anyone have a link for this?
Unfortunately no
Here's a thread with some good resources:
https://groups.google.com/g/elixir-lang-talk/c/WtzbZcAk6XQ