Как получить один символ, не нажимая клавишу enter?

StackOverflow https://stackoverflow.com/questions/174933

  •  05-07-2019
  •  | 
  •  

Вопрос

Как я могу получить один символ клавиатуры из терминала с помощью 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 дал отличный ответ, но есть две проблемы:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top