Detect key press (non-blocking) w/o getc/gets in Ruby Detect key press (non-blocking) w/o getc/gets in Ruby ruby ruby

Detect key press (non-blocking) w/o getc/gets in Ruby


Here's one way to do it, using 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  endendloop 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!"endputs "Oh, I quit."

Bear in mind that even though this uses non-blocking IO, it's still buffered IO.That means that your users will have to hit Q then <Enter>. If you want to dounbuffered IO, I'd suggest checking out ruby's curses library.


You can also do this without the buffer. In unix based systems it is easy:

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

This will wait for a key to be pressed and return the char code. No need to press .

Put the char = STDIN.getc into a loop and you've got it!

If you are on windows, according to The Ruby Way, you need to either write an extension in C or use this little trick (although this was written in 2001, so there might be a better way)

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

Here is my reference: great book, if you don't own it you should


A combination of the other answers gets the desired behavior. Tested in ruby 1.9.3 on OSX and Linux.

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