Как получить один символ без нажатия клавиши ввода?
Как я могу получить один символ клавиатуры из терминала с помощью Ruby, не нажимая Enter? Я старался Curses::getch
, но это не сработало для меня.
6 ответов
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
(Протестировано на моей системе OS X, возможно, не переносимо на все платформы Ruby). Смотрите http://www.rubyquiz.com/quiz5.html для некоторых дополнительных предложений, в том числе для Windows.
Начиная с ruby 2.0.0, в stdlib есть 'io/console' с этой функцией
require 'io/console'
STDIN.getch
@Джей дал отличный ответ, но есть две проблемы:
- Вы можете испортить состояние tty по умолчанию;
- Вы игнорируете управляющие символы (^C для SIGINT и т. Д.).
Простым решением для этого является сохранение предыдущего состояния tty и использование следующих параметров:
-icanon
- отключить канонический ввод (обработка ERASE и KILL);isig
- включить проверку символов по специальным управляющим символам INTR, QUIT и SUSP.
В конце у вас будет такая функция:
def get_char
state = `stty -g`
`stty raw -echo -icanon isig`
STDIN.getc.chr
ensure
`stty #{state}`
end
Необработанный режим (stty raw -echo
) к сожалению заставляет control-C отправляться как символ, а не как SIGINT. Поэтому, если вы хотите заблокировать ввод, как описано выше, но разрешить пользователю нажимать control-C, чтобы остановить программу, пока она ждет, убедитесь, что сделали это:
Signal.trap("INT") do # SIGINT = control-C
exit
end
И если вы хотите неблокирующий ввод - то есть периодически проверяйте, нажал ли пользователь клавишу, а тем временем переходите к другим действиям - тогда вы можете сделать это:
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
Обратите внимание, что вам не нужен специальный обработчик SIGINT для неблокирующей версии, так как tty находится в режиме raw только на короткое время.
Примечание. Это старый ответ, и решение больше не работает на большинстве систем.
Но ответ все еще может быть полезен для некоторых сред, где другие методы не работают. Пожалуйста, прочитайте комментарии ниже.
Сначала вы должны установить Highline:
gem install highline
Затем попробуйте, если метод highline работает для вас:
require "highline/system_extensions"
include HighLine::SystemExtensions
print "Press any key:"
k = get_character
puts k.chr
И если вы создаете приложение curses, вам нужно позвонить
nocbreak
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html