【发布时间】:2010-09-15 13:16:06
【问题描述】:
如何在不按 Enter 的情况下使用 Ruby 从终端获取单个键盘字符?
我尝试了Curses::getch,但这对我来说真的不起作用。
【问题讨论】:
如何在不按 Enter 的情况下使用 Ruby 从终端获取单个键盘字符?
我尝试了Curses::getch,但这对我来说真的不起作用。
【问题讨论】:
@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
【讨论】:
但是对于其他方法不起作用的某些环境,答案可能仍然有用。请阅读下面的cmets。
首先你必须安装highline:
gem install highline
然后试试 highline 方法是否适合你:
require "highline/system_extensions"
include HighLine::SystemExtensions
print "Press any key:"
k = get_character
puts k.chr
【讨论】:
从 ruby 2.0.0 开始,stdlib 中有一个具有此功能的“io/console”
require 'io/console'
STDIN.getch
【讨论】:
exit(1) if char == "\u0003"。
require :)
$ ruby script.rb 调用它。
如果您正在构建 curses 应用程序,则需要调用
nocbreak
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html#method-c-cbreak
【讨论】:
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
请注意,非阻塞版本不需要特殊的 SIGINT 处理程序,因为 tty 仅在短时间内处于原始模式。
【讨论】:
Signal.trap('INT') { exit } 使程序在按下 control-C 时退出(除非它被其他方式绕过)并且肯定在 1.9.2-p290 中有效,所以我不知道什么“不起作用”对我来说”可能意味着
STDIN.getch,它肯定不起作用。然后你的 SIGINT 被解释为"\u0003"。或者可能是其他东西,具体取决于您的终端。
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 的建议。
【讨论】:
Signal.trap("INT") { exit }(请参阅下面的答案以获得更好的格式版本)跨度>