web-dev-qa-db-ja.com

Enterキーを押さずに1つの文字を取得する方法は?

RubyでEnterキーを押さずに、ターミナルから単一のキーボード文字を取得するにはどうすればよいですか?Curses::getch、しかしそれは私には本当にうまくいきませんでした。

42
Nino

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を含む追加の提案。

35
Jay

Ruby 2.0.0なので、この機能を持つstdlibには 'io/console'があります。

require 'io/console'
STDIN.getch
60
iNecas

@Jayは素晴らしい答えを出しましたが、2つの問題があります。

  1. デフォルトのtty状態を台無しにすることができます。
  2. 制御文字(SIGINTの場合は^ C)を無視します。

そのための簡単な修正は、以前の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
19
Andrew

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

Ttyは一瞬だけrawモードであるため、非ブロッキングバージョン用の特別なSIGINTハンドラーは必要ありません。

14
AlexChaffee

注:これは古い回答であり、ソリューションはほとんどのシステムで機能しなくなります。

しかし、他の方法が機能しない一部の環境では、答えは依然として役立つ可能性があります。以下のコメントを読んでください。


まず、highlineをインストールする必要があります。

gem install highline

次に、highlineメソッドが機能するかどうかを試します。

require "highline/system_extensions"
include HighLine::SystemExtensions

print "Press any key:"
k = get_character
puts k.chr
13
mit

cursesアプリケーションを構築している場合は、

nocbreak

http://www.Ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html#method-c-cbreak

0
lzap