Forum: Ruby Non blocking keypress reading?

A80bfa5dddb90d68133a14c7803e1e43?d=identicon&s=25 Sard Aukary (sard)
on 2006-09-08 13:42
On Windows XP is there a way to test that a certain key has been pressed
without blocking?

Iâ??ve tried using curses but it blocks the current thread and any other
thread until a key is pressed.


I want to give the user 10 seconds so make a selection before a default
action is taken.

Here is the test code Iâ??ve got;


	require 'curses'
	include Curses
	init_screen
	noecho
	trap(0) { echo }

	t1 = Time.new
	Thread.new do

		#example timer thread
		while(true) do
		x = Time.new - t1
		h = 3+3
		setpos(12,10)

	  addstr("#{x}")

	end
	end

	setpos(1,5)
	addstr("Please select your location")
	setpos(3,5)
	addstr("  1 - Work")
	setpos(4,5)
	addstr("  2 - Home")
	setpos(6,5)
	addstr("Esc - Exit")
	while (c = getch) != ?\e do
	 # check what key is pressed and do stuff
	end
E3f82b918ccd3c6d7b63a54bea9ff60b?d=identicon&s=25 William Crawford (aladrin)
on 2006-09-08 13:52
Sard Aukary wrote:
> On Windows XP is there a way to test that a certain key has been pressed
> without blocking?

From my quick search, I didn't find a way.  Maybe this will help though?

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/...
97550977337c9f0a0e1a9553e55bfaa0?d=identicon&s=25 Jan Svitok (Guest)
on 2006-09-08 14:02
(Received via mailing list)
On 9/8/06, Sard Aukary <sardaukary@yahoo.co.uk> wrote:
> Here is the test code I've got;
>
>
>         end
search the archive for kbhit
86e33dee4a89a8879a26487051c216a8?d=identicon&s=25 Michael Fellinger (Guest)
on 2006-09-11 11:53
(Received via mailing list)
On Friday 08 September 2006 20:42, Sard Aukary wrote:
> On Windows XP is there a way to test that a certain key has been pressed
> without blocking?
>
> Iâ??ve tried using curses but it blocks the current thread and any other
> thread until a key is pressed.
>
>
> I want to give the user 10 seconds so make a selection before a default
> action is taken.

require 'timeout'
begin
  Timeout.timeout(10) do
    key = gets
  end
rescue Timeout::Error
  key = default
end

> 	t1 = Time.new
> 	end
> 	while (c = getch) != ?\e do
> 	 # check what key is pressed and do stuff
> 	end

--
Weez International Limited

East Roppongi Bldg 5F, 509
3-16-35 Roppongi, Minato-ku Tokyo #106-0032
Tel: 81-(0)3-3505-3881 Fax: 81-(0)3-3505-3883
E-mail: manveru@weez-int.com
Website: http://weez-int.com
38e4ddd3dc7770cc1e47164dc50debd7?d=identicon&s=25 Muriel Salvan (murielsalvan)
on 2014-03-26 12:55
Sard Aukary wrote in post #136581:
> On Windows XP is there a way to test that a certain key has been pressed
> without blocking?
>
> Iâ??ve tried using curses but it blocks the current thread and any other
> thread until a key is pressed.
>
>
> I want to give the user 10 seconds so make a selection before a default
> action is taken.
>
> Here is the test code Iâ??ve got;
>
>
>   require 'curses'
>   include Curses
>   init_screen
>   noecho
>   trap(0) { echo }
>
>   t1 = Time.new
>   Thread.new do
>
>     #example timer thread
>     while(true) do
>     x = Time.new - t1
>     h = 3+3
>     setpos(12,10)
>
>     addstr("#{x}")
>
>   end
>   end
>
>   setpos(1,5)
>   addstr("Please select your location")
>   setpos(3,5)
>   addstr("  1 - Work")
>   setpos(4,5)
>   addstr("  2 - Home")
>   setpos(6,5)
>   addstr("Esc - Exit")
>   while (c = getch) != ?\e do
>    # check what key is pressed and do stuff
>   end

I know this is an old post, but still appears among Google's top
results.

By combinig the various solutions I just read, I came up with a
cross-platform way to solve that problem.
Details here:
http://blog.x-aeon.com/2014/03/26/how-to-read-one-...

The relevant piece of code: a `GetKey.getkey` method
returning the ASCII code or `nil` if none was pressed.

Should work both on Windows and Unix.

module GetKey

  # Check if Win32API is accessible or not
  @use_stty = begin
    require 'Win32API'
    false
  rescue LoadError
    # Use Unix way
    true
  end

  # Return the ASCII code last key pressed, or nil if none
  #
  # Return::
  # * _Integer_: ASCII code of the last key pressed, or nil if none
  def self.getkey
    if @use_stty
      system('stty raw -echo') # => Raw mode, no echo
      char = (STDIN.read_nonblock(1).ord rescue nil)
      system('stty -raw echo') # => Reset terminal mode
      return char
    else
      return Win32API.new('crtdll', '_kbhit', [ ], 'I').Call.zero? ? nil
: Win32API.new('crtdll', '_getch', [ ], 'L').Call
    end
  end

end

And here is a simple program to test it:

loop do
  k = GetKey.getkey
  puts "Key pressed: #{k.inspect}"
  sleep 1
end

In the link provided above, I also show how to use the `curses` library,
but the result gets a bit whacky on Windows.

Hope this will help others.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.