如何检查是不是已在 Ruby 和 Windows 控制台中按下箭头键
Posted
技术标签:
【中文标题】如何检查是不是已在 Ruby 和 Windows 控制台中按下箭头键【英文标题】:How can I check if the arrow keys have been pressed in Ruby and Windows Console如何检查是否已在 Ruby 和 Windows 控制台中按下箭头键 【发布时间】: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 并将其文件包含在您的脚本中。
诅咒我该怎么做?
【参考方案1】:
我一直在尝试解决这个问题一段时间,这对我有用:
require 'io/console'
while true
user_input = $stdin.getch
case user_input
when 'q'
exit
when '['
print '' # I believe that by entering this block of code user_input drops the first char. What is left can be used to determine what key has been pressed.
else
case user_input
when 'A'
puts "up"
when 'B'
puts "down"
when 'C'
puts "right"
when 'D'
puts "left"
end
end
end
我正在使用 ruby 2.4.1。希望能帮助到你。
【讨论】:
以上是关于如何检查是不是已在 Ruby 和 Windows 控制台中按下箭头键的主要内容,如果未能解决你的问题,请参考以下文章
如何持续检查 AVAudioplayer 是不是已在 Swift 中播放完毕?
如何检查用户 JID 是不是已在 XMPPFrameWork 中使用