
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.
Пока это работает, но, к сожалению, я получаю число, а не строку. вы знаете, как преобразовать число в правильный символ ascii?
Да, просто используйте str.chr, чтобы получить символ, соответствующий числовому значению. Я обновил сообщение, чтобы отразить это
К сожалению, поскольку вы находитесь в необработанном режиме, control-C отправляется как символ, а не как SIGINT. Поэтому, если вы хотите заблокировать ввод, как указано выше, но все же хотите, чтобы пользователь нажимал Ctrl-C, чтобы остановить программу во время ожидания, обязательно сделайте это: Signal.trap("INT") { exit } (см. Мой ответ ниже для версии с лучшим форматом)
Ответ Андрея (25 января 2013, 17:49) лучше.
Но ответ все же может быть полезен для некоторых сред, где другие методы не работают. Пожалуйста, прочтите комментарии ниже.
Для начала нужно установить highline:
gem install highline
Тогда попробуйте, подходит ли вам метод highline:
require "highline/system_extensions"
include HighLine::SystemExtensions
print "Press any key:"
k = get_character
puts k.chr
Предупреждение: недавняя фиксация удалила эту функцию из highline. См. github.com/JEG2/highline/issues/50
это НЕ работает: для этого нужно нажать клавишу <enter>. Кстати, он также принимает символ \ n.
Этот пример у меня работает на Ruby 2.0 в Windows 7.
Работает на Ruby 1.9.3 и Windows XP без необходимости нажимать клавишу ввода (проверено на pry). ps Спасибо!
Необработанный режим (stty raw -echo), к сожалению, приводит к тому, что control-C отправляется как символ, а не как SIGINT. Поэтому, если вы хотите заблокировать ввод, как указано выше, но разрешите пользователю нажать Ctrl-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 находится в необработанном режиме только на короткое время.
Отличный ответ, именно то, что я искал. Большое спасибо за исключительно функциональный код!
Signal.trap('INT') { exit } выполняет выход из программы при нажатии Ctrl-C (если это не обходится другими способами) и определенно работает в 1.9.2-p290, поэтому я не знаю, что могло означать «не сработало для меня»
Это работает в вашем примере, но определенно не работает, если вы используете STDIN.getch. Тогда ваш SIGINT интерпретируется как "\u0003". Или, может быть, что-то еще в зависимости от вашего терминала.
А если вы собираете приложение проклятия, вам нужно вызвать
nocbreak
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html#method-c-cbreak
@Jay дал отличный ответ, но есть две проблемы:
Простое решение - сохранить предыдущее состояние 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
Начиная с ruby 2.0.0, в stdlib есть 'io / console' с этой функцией.
require 'io/console'
STDIN.getch
Ссылка на документацию: ruby-doc.org/stdlib/libdoc/io/console/rdoc/…
Это сработало отлично, при условии, что вы потом проверите Control-C: exit(1) if char == "\u0003".
Мне даже require не понадобился :)
@philant nope, у меня есть скрипт, и вызов его через $ ruby script.rb работает.
Это, вероятно, лучший ответ на сегодняшний день, потому что, если функциональность должна быть изменена, команда ядра Ruby (например, nobu) может изменить / адаптировать ее. Это должно быть лучше в долгосрочной перспективе, ИМО.
возможный дубликат Немедленно получить одиночный символ из консоли