Как получить один символ, не нажимая клавишу enter?
Вопрос
Как я могу получить один символ клавиатуры из терминала с помощью Ruby, не нажимая enter?Я пытался Curses::getch
, но на самом деле у меня это не сработало.
Решение
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
@Jay дал отличный ответ, но есть две проблемы:
- Вы можете испортить состояние tty по умолчанию;
- Вы игнорируете управляющие символы (^C для SIGINT и т.д.).
Простое решение для этого - сохранить предыдущее состояние tty и использовать следующие параметры:
-icanon
- отключить канонический ввод (СТЕРЕТЬ и ПРЕКРАТИТЬ обработку);isig
- включить проверку символов на соответствие специальным управляющим символам INTR, QUIT и SUSP.
В конце концов, у вас будет такая функция, как эта:
def get_char
state = `stty -g`
`stty raw -echo -icanon isig`
STDIN.getc.chr
ensure
`stty #{state}`
end
Режим Raw ( 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#method-c-cbreak р>