如何在 Ruby 中从终端获取单个按键字符而无需按回车键?
我尝试使用 Curses::getch
,但对我来说并没有真正起作用。
自Ruby 2.0.0起,stdlib中有一个具有此功能的“io / console”
require 'io/console'
STDIN.getch
exit(1) if char == "\u0003"
。 - Aidan Feldmanrequire
:) - Lucas Caton$ ruby script.rb
调用它可以工作。 - Lucas Catonhttp://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。
Signal.trap("INT") { exit }
(有关更好格式化版本,请参见下面的答案) - AlexChaffee@Jay给出了很好的答案,但有两个问题:
解决这个问题的简单方法是保存之前的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仅在短暂的时间内处于原始模式。
Signal.trap('INT') { exit }
当按下 Ctrl-C 时使程序退出(除非通过其他方式绕过),并且在1.9.2-p290中肯定有效,因此我不知道“对我无效”可能意味着什么。 - AlexChaffeeSTDIN.getch
,它绝对不起作用。然后你的SIGINT被解释为"\u0003"
。或者根据你的终端可能是其他内容。 - Justin Force但在其他方法无法生效的某些环境中,该答案仍可能有用。请阅读下面的评论。
首先,您需要安装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