Enterキーを押さずにRubyを使用して端末からキーボード文字を1つ取得するにはどうすればよいですか? 試してみCurses::getch
ましたが、うまくいきませんでした。
6 に答える
Ruby 2.0.0 以降、この機能を備えた stdlib に「io/console」があります。
require 'io/console'
STDIN.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 プラットフォームに移植できるわけではありません)。Windows 用を含む追加の提案については、 http://www.rubyquiz.com/quiz5.htmlを参照してください。
@Jay は素晴らしい答えを出しましたが、2 つの問題があります。
- デフォルトの tty 状態を台無しにすることができます。
- 制御文字 (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
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 ハンドラは必要ないことに注意してください。
注:これは古い回答であり、ソリューションはほとんどのシステムでは機能しなくなりました。
ただし、他の方法が機能しない一部の環境では、答えが依然として役立つ場合があります。以下のコメントをお読みください。
まず、highline をインストールする必要があります。
gem install 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