【发布时间】:2015-03-22 20:33:55
【问题描述】:
我正在使用 Ruby 2.1.5 和 Windows 控制台。我需要能够在不停止执行的情况下扫描按键。我需要能够专门检测箭头键。我在其他问题上尝试了许多推荐的方法,但它们都不能在 Windows 控制台上工作或检测不到箭头键。
不显示箭头键
require 'io/console'
loop do
p STDIN.getch
end
运行没有错误,但似乎没有从输入缓冲区读取,因为在使用 Ctrl-C 退出程序后,所有按下的键都显示在控制台上
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
这个也可以正常运行,但需要按下回车键才能继续运行。我需要非阻塞输入
# read a character without pressing enter and without printing to the screen
def read_char
begin
# save previous state of stty
old_state = "stty raw -g"
# disable echoing and enable raw (not having to press enter)
system "stty raw -echo"
c = STDIN.getc.chr
# gather next two characters of special keys
if(c=="\e")
puts "checking for non alpha"
extra_thread = Thread.new{
c = c + STDIN.getc.chr
c = c + STDIN.getc.chr
}
# wait just long enough for special keys to get swallowed
extra_thread.join(0.00001)
# kill thread so not-so-long special keys don't wait on getc
extra_thread.kill
end
rescue => ex
puts "#{ex.class}: #{ex.message}"
puts ex.backtrace
ensure
# restore previous state of stty
system "stty #{old_state}"
end
return c
end
# takes a single character command
def show_single_key
c = read_char
case c
when " "
puts "SPACE"
when "\t"
puts "TAB"
when "\r"
puts "RETURN"
when "\n"
puts "LINE FEED"
when "\e"
puts "ESCAPE"
when "\e[A"
puts "UP ARROW"
when "\e[B"
puts "DOWN ARROW"
when "\e[C"
puts "RIGHT ARROW"
when "\e[D"
puts "LEFT ARROW"
when "\177"
puts "BACKSPACE"
when "\004"
puts "DELETE"
when /^.$/
puts "SINGLE CHAR HIT: #{c.inspect}"
else
puts "SOMETHING ELSE: #{c.inspect}"
end
end
show_single_key while(true)
这似乎是最后一个的变体,它适用于所有 ASCII 表示的键,但不适用于箭头键,并且输入有问题。
require 'io/console'
# Reads keypresses from the user including 2 and 3 escape character sequences.
def read_char
STDIN.echo = false
STDIN.raw!
input = STDIN.getc.chr
puts input
if input == "\e" then
puts "getting additional characters"
input << STDIN.read_nonblock(3) rescue nil
input << STDIN.read_nonblock(2) rescue nil
end
ensure
#STDIN.echo = true
STDIN.cooked!
return input
end
# oringal case statement from:
# http://www.alecjacobson.com/weblog/?p=75
def show_single_key
c = read_char
case c
when " "
puts "SPACE"
when "\t"
puts "TAB"
when "\r"
puts "RETURN"
when "\n"
puts "LINE FEED"
when "\e"
puts "ESCAPE"
when "\e[A"
puts "UP ARROW"
when "\e[B"
puts "DOWN ARROW"
when "\e[C"
puts "RIGHT ARROW"
when "\e[D"
puts "LEFT ARROW"
when "\177"
puts "BACKSPACE"
when "\004"
puts "DELETE"
when "\e[3~"
puts "ALTERNATE DELETE"
when "\u0003"
puts "CONTROL-C"
exit 0
when /^.$/
puts "SINGLE CHAR HIT: #{c.inspect}"
else
puts "SOMETHING ELSE: #{c.inspect}"
end
end
show_single_key while(true)
我还尝试了几个调用 Win32API 的方法,但它们都无法正常工作,并且有关于被弃用的警告。我想要一个跨平台的解决方案,但此时我会满足于它在 Windows 控制台上正常工作。我也不能为此使用任何 Ruby Gems。
【问题讨论】:
-
以前没有 Ruby 专家遇到过这种情况?
-
为什么不能使用宝石?这似乎是一个非常严格、任意的条件。正确的方法是使用 curses 库。有很多 gem 为此类库提供包装器,但我想您将不得不自己编写这样的包装器。从头开始。无缘无故。
-
有时您必须使用限制性的任意条件。我将无法访问将运行此代码的机器,也无法在其上安装任何 Ruby Gem。如果有一种方法可以包含 Gem 的功能并将它们与我的代码一起发送,而无需在另一台机器上安装 Gem,我会很乐意使用它们。我对 Ruby 有点陌生,但不是必须在运行程序的每台计算机上都有 gem,或者有没有办法将你的 ruby 代码“编译”到它将在每台具有 ruby 解释器的机器上运行的地方他们有什么宝石?
-
Gem 只是 Ruby 代码的集合,供您发送至
require。即使您无法使用包管理器正确安装 gem,也没有什么能阻止您手动下载 gem 并将其文件包含在您的脚本中。 -
诅咒我该怎么做?