题
如何使用 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 ,包括视窗。
其他提示
从ruby 2.0.0开始,stdlib中有一个带有此功能的'io / console'
require 'io/console'
STDIN.getch
@Jay 给出了很好的答案,但有两个问题:
- 你可能会弄乱默认的 tty 状态;
- 您忽略控制字符(^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
原始模式( 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仅在原始模式下短暂停留。
注意:这是旧答案,解决方案不再适用于大多数系统。
但是答案对于某些环境仍然有用,其他方法不起作用。请阅读以下评论。
首先你需要安装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