Как получить один символ без нажатия клавиши ввода? - PullRequest
39 голосов
/ 06 октября 2008

Как я могу получить один символ клавиатуры из терминала с помощью Ruby, не нажимая Enter? Я пытался Curses::getch, но это не помогло мне.

Ответы [ 6 ]

50 голосов
/ 19 ноября 2014

Начиная с ruby ​​2.0.0, в stdlib есть 'io / console' с этой функцией

require 'io/console'
STDIN.getch
33 голосов
/ 06 октября 2008

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.

19 голосов
/ 25 января 2013

@ Джей дал отличный ответ, но есть две проблемы:

  1. Вы можете испортить состояние tty по умолчанию;
  2. Вы игнорируете управляющие символы (^ 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
14 голосов
/ 26 ноября 2011

Режим 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 в течение краткого момента.

13 голосов
/ 21 октября 2010

Примечание. Это старый ответ, и решение больше не работает на большинстве систем.

Но ответ все еще может быть полезен для некоторых сред, где другие методы не работают. Пожалуйста, прочитайте комментарии ниже.


Сначала вы должны установить highline:

gem install highline

Тогда попробуйте, если метод highline работает для вас:

require "highline/system_extensions"
include HighLine::SystemExtensions

print "Press any key:"
k = get_character
puts k.chr
0 голосов
/ 01 декабря 2012

А если вы создаете curses приложение, вам нужно позвонить

nocbreak

http://www.ruby -doc.org / STDLIB-1.9.3 / libdoc / проклятий / RDoc / Curses.html # способ-с-CBREAK

...