Как я могу получить один символ клавиатуры из терминала с помощью Ruby без нажатия клавиши ввода?
Я пробовал Curses::getch
, но это не помогло мне.
Как получить один символ без нажатия клавиши ввода?
Ответ 1
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.
Ответ 2
Так как ruby 2.0.0, в stdlib есть "io/console" с этой функцией
require 'io/console'
STDIN.getch
Ответ 3
@Jay дал отличный ответ, но есть две проблемы:
- Вы можете испортить состояние по умолчанию 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
Ответ 4
Примечание. Это и старый ответ, и решение больше не работает в большинстве систем.
Но ответ может быть полезен для некоторых сред, где другие методы не работают. Пожалуйста, прочитайте комментарии ниже.
Сначала вы должны установить highline:
gem install highline
Затем попробуйте, если метод highline работает для вас:
require "highline/system_extensions"
include HighLine::SystemExtensions
print "Press any key:"
k = get_character
puts k.chr
Ответ 5
Необработанный режим (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 находится только в сыром режиме на короткое время.
Ответ 6
И если вы создаете приложение curses, вам нужно позвонить
nocbreak
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html#method-c-cbreak