Enterを押さずに単一の文字を取得するにはどうすればよいですか?
質問
Enterを押さずにRubyを使用してターミナルから単一のキーボード文字を取得するにはどうすればよいですか?私は試した 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 以降、この機能を備えた 'io/console' が stdlib にあります。
require 'io/console'
STDIN.getch
@Jayはすばらしい答えを出しましたが、2つの問題があります:
- デフォルトのtty状態を台無しにすることができます。
- 制御文字を無視します(SIGINTの場合は^ Cなど)。
そのための簡単な修正は、以前のtty状態を保存し、次のパラメーターを使用することです:
-
-icanon
-正規入力を無効にします(消去およびキル処理); -
isig
-特殊制御文字INTR、QUIT、およびSUSPに対する文字のチェックを有効にします。
最終的には、次のような関数になります。
def get_char
state = `stty -g`
`stty raw -echo -icanon isig`
STDIN.getc.chr
ensure
`stty #{state}`
end
生モード( 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
次に、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