Come ottenere un singolo personaggio senza premere Invio?
Domanda
Come posso ottenere un singolo carattere della tastiera dal terminale con Ruby senza premere Invio?
Ho provato Curses :: getch
, ma non ha funzionato davvero per me.
Soluzione
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
(Testato sul mio sistema OS X, potrebbe non essere portatile su tutte le piattaforme Ruby). Vedi http://www.rubyquiz.com/quiz5.html per alcuni suggerimenti aggiuntivi, tra cui per di Windows.
Altri suggerimenti
Da ruby ??2.0.0, c'è uno 'io / console' nello stdlib con questa funzione
require 'io/console'
STDIN.getch
@Jay ha dato un'ottima risposta, ma ci sono due problemi:
- È possibile incasinare lo stato tty predefinito;
- Si ignorano i caratteri di controllo (^ C per SIGINT, ecc.).
Una soluzione semplice è quella di salvare il precedente stato tty e utilizzare i seguenti parametri:
-
-icanon
- disabilita l'input canonico (elaborazione ERASE e KILL); -
isig
- abilita il controllo dei caratteri rispetto agli speciali caratteri di controllo INTR, QUIT e SUSP.
Alla fine avresti una funzione come questa:
def get_char
state = `stty -g`
`stty raw -echo -icanon isig`
STDIN.getc.chr
ensure
`stty #{state}`
end
La modalità Raw ( stty raw -echo
) sfortunatamente fa sì che control-C venga inviato come personaggio, non come SIGINT. Quindi, se vuoi bloccare l'input come sopra, ma consenti all'utente di premere control-C per arrestare il programma mentre è in attesa, assicurati di farlo:
Signal.trap("INT") do # SIGINT = control-C
exit
end
E se vuoi un input non bloccante, cioè controlla periodicamente se l'utente ha premuto un tasto, ma nel frattempo vai a fare altre cose, allora puoi farlo:
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
Si noti che non è necessario un gestore SIGINT speciale per la versione non bloccante poiché tty è in modalità raw solo per un breve momento.
Nota: questa è una vecchia risposta e la soluzione non funziona più sulla maggior parte dei sistemi.
Ma la risposta potrebbe ancora essere utile per alcuni ambienti, dove gli altri metodi non funzionano. Si prega di leggere i commenti qui sotto.
Per prima cosa devi installare highline:
gem install highline
Quindi prova se il metodo highline funziona per te:
require "highline/system_extensions"
include HighLine::SystemExtensions
print "Press any key:"
k = get_character
puts k.chr
E se stai creando un'applicazione maledizioni , devi chiamare
nocbreak
http: //www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html#method-c-cbreak