Getting Input One Character at a Time

Problem

You e writing an interactive application or a terminal-based game. You want to read a users input from standard input a single character at a time.

Solution

Most Ruby installations on Unix come with the the Curses extension installed. If Curses has the features you want to write the rest of your program, the simplest solution is to use it.

This simple Curses program echoes every key you type to the top-left corner of the screen. It stops when you hit the escape key (e).[1]

[1] This code will also work in irb, but itll look strange because Curses will be fighting with irb for control of the screen.

	#!/usr/bin/ruby -w
	# curses_single_char_input.rb
	require curses
	include Curses

	# Setup: create a curses screen that doesn	 echo its input.
	init_screen
	noecho

	# Cleanup: restore the terminal settings when the program is exited or
	# killed.
	trap(0) { echo }

	while (c = getch) != ?e do
	 setpos(0,0)
	 addstr("You typed #{c.chr.inspect}")
	end

If you don want Curses to take over your program, you can use the HighLine library instead (available as the highline gem). It does its best to define a get_ character method that will work on your system. The get_ character method itself is private, but you can access it from within a call to ask:

	require 
ubygems
	require highline/import

	while (c = ask(\) { |q| q.character = true; q.echo = false }) != "e" do
	 print "You typed #{c.inspect}"
	end

Be careful; ask echoes a newline after every character it receives.[2] Thats why I use a print statement in that example instead of puts.

[2] This actually happens at the end of HighLine.get_response, which is called by ask.

Of course, you can avoid this annoyance by hacking the HighLine class to make get_character public:

	class HighLine
	 public :get_character
	end
	input = HighLine.new
	while (c = input.get_ 
character) != ?e do
	 puts "You typed #{c.chr.inspect}"
	end

Discussion

This is a huge and complicated problem that (fortunately) is completely hidden by Curses and HighLine. Heres the problem: Unix systems know how to talk to a lot of historic and modern terminals. Each one has a different feature set and a different command language. HighLine (through the Termios library it uses on Unix) and Curses hide this complexity.

Windows doesn have to deal with a lot of terminal types, but Windows programs don usually read from standard input either (much less one character at a time). To do single- character input on Windows, HighLine makes raw Windows API calls. Heres some code based on HighLines, which you can use on Windows if you don want to require HighLine:

	require Win32API

	def getch
	 @getch ||= Win32API.new(crtdll, \_getch, [], L)
	 @getch.call
	end

	while (c = getch) != ?e
	 puts "You typed #{c.chr.inspect}"
	end

HighLine also has two definitions f get_character for Unix; you can copy one of these if you don want to require HighLine. The most reliable implementation is fairly complicated, and requires the termios gem. But if you need to require the termios gem, you might as well require the highline gem as well, and use HighLines implementation as is. So if you want to do single-character input on Unix without requiring any gems, youll need to rely on the Unix command stty:

	def getch
	 state = `stty -g`
	 begin
	 `stty raw -echo cbreak`
	 $stdin.getc
	 ensure
	 `stty #{state}`
	 end
	end

	while (c = getch) != ?e
	 puts "You typed #{c.chr.inspect}"
	end

All of the HighLine code is in the main highline.rb file; search for "get_character".

See Also

  • Recipe 21.5, "Setting Up and Tearing Down a Curses Program"
  • Recipe 21.8, "Changing Text Color"


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net