Como obter um único caractere sem pressionar entrar?
Pergunta
Como posso obter um único caractere do teclado do terminal com Ruby sem pressionar entrar?
Tentei Curses::getch
, mas que realmente não trabalho para mim.
Solução
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
(Testado no meu sistema OS X, pode não ser portátil para todas as plataformas Ruby). Consulte http://www.rubyquiz.com/quiz5.html para algumas sugestões adicionais, inclusive para do Windows.
Outras dicas
Desde ruby ??2.0.0, há um 'io / console' no stdlib com esse recurso
require 'io/console'
STDIN.getch
@Jay deu uma grande resposta, mas há dois problemas:
- Você pode atrapalhar estado tty padrão;
- Você ignora caracteres de controle (^ C para SIGINT, etc).
Uma solução simples para isso é para salvar estado tty anterior e uso os seguintes parâmetros:
-
-icanon
- Entrada canônica disable (ERASE e processamento matar); -
isig
-. Permitir a verificação dos personagens contra os caracteres especiais de controle INTR, sair, e SUSP
No final, você teria uma função como esta:
def get_char
state = `stty -g`
`stty raw -echo -icanon isig`
STDIN.getc.chr
ensure
`stty #{state}`
end
modo RAW (stty raw -echo
) infelizmente faz com control-C para se enviada em como um personagem, não como um SIGINT. Então se você quer bloquear entrada como acima, mas permitir que o usuário pressione Control-C para parar o programa enquanto ele está esperando, certifique-se de fazer isso:
Signal.trap("INT") do # SIGINT = control-C
exit
end
E se você quiser entrada non-blocking - isto é, verificar periodicamente se o usuário pressionou uma chave, mas, entretanto, ir fazer outras coisas - então você pode fazer isso:
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
Note que você não precisa de um manipulador de SIGINT especial para a versão sem bloqueio desde o tty é apenas no modo cru por um momento breve.
Nota:. Este é e velha resposta ea solução não funciona na maioria dos sistemas
Mas a resposta ainda poderia ser útil para alguns ambientes, onde os outros métodos não funcionam. Por favor, leia os comentários abaixo.
Primeiro você tem que instalar o highline:
gem install highline
Em seguida, tente se o método highline funciona para você:
require "highline/system_extensions"
include HighLine::SystemExtensions
print "Press any key:"
k = get_character
puts k.chr
E se você está construindo maldições aplicativo, você precisa chamar
nocbreak
http: //www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html#method-c-cbreak