¿Cómo conseguir un solo carácter sin pulsar Intro?
Pregunta
¿Cómo puedo obtener un solo carácter de teclado del terminal con Ruby sin presionar Intro?
Intenté Curses :: getch
, pero eso no me funcionó.
Solución
http: //blade.nagaokaut. ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/2999
#!/usr/bin/ruby
begin
system("stty raw -echo")
str = STDIN.getc
ensure
system("stty -raw echo")
end
p str.chr
(Probado en mi sistema OS X, puede que no sea portátil para todas las plataformas Ruby). Consulte http://www.rubyquiz.com/quiz5.html para obtener algunas sugerencias adicionales, incluso para Windows.
Otros consejos
Desde Ruby 2.0.0, hay una 'io / console' en la barra de datos con esta función
require 'io/console'
STDIN.getch
@Jay dio una gran respuesta, pero hay dos problemas:
- Puedes estropear el estado tty predeterminado;
- Ignora los caracteres de control (^ C para SIGINT, etc.).
Una solución simple para eso es guardar el estado anterior de tty y usar los siguientes parámetros:
-
-icanon
: deshabilita la entrada canónica (procesamiento ERASE y KILL); -
isig
: habilita la comprobación de los caracteres frente a los caracteres de control especiales INTR, QUIT y SUSP.
Al final, tendrías una función como esta:
def get_char
state = `stty -g`
`stty raw -echo -icanon isig`
STDIN.getc.chr
ensure
`stty #{state}`
end
Raw ( stty raw -echo
) desafortunadamente hace que el control-C se envíe como un carácter, no como un SIGINT. Entonces, si desea bloquear entradas como las anteriores, pero permitir que el usuario presione control-C para detener el programa mientras está esperando, asegúrese de hacer esto:
Signal.trap("INT") do # SIGINT = control-C
exit
end
Y si desea una entrada sin bloqueo, es decir, verifique periódicamente si el usuario ha presionado una tecla, pero mientras tanto, vaya a hacer otras cosas, entonces puede hacer esto:
require 'io/wait'
def char_if_pressed
begin
system("stty raw -echo") # turn raw input on
c = nil
if $stdin.ready?
c = $stdin.getc
end
c.chr if c
ensure
system "stty -raw echo" # turn raw input off
end
end
while true
c = char_if_pressed
puts "[#{c}]" if c
sleep 1
puts "tick"
end
Tenga en cuenta que no necesita un controlador SIGINT especial para la versión sin bloqueo, ya que tty solo está en modo raw por un breve momento.
Nota: Esta es una respuesta anterior y la solución ya no funciona en la mayoría de los sistemas.
Pero la respuesta aún podría ser útil para algunos entornos, donde los otros métodos no funcionan. Por favor, lea los comentarios a continuación.
Primero debes instalar highline:
gem install highline
A continuación, intente si el método de Highline funciona para usted:
require "highline/system_extensions"
include HighLine::SystemExtensions
print "Press any key:"
k = get_character
puts k.chr
Y si está creando la aplicación curses , debe llamar
nocbreak
http: //www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html#method-c-cbreak