From: Dave Burt Date: 2006-06-08T18:07:19+09:00 Subject: Re: pausing until a character is received Sy Ali wrote: > Just for kicks I tried to better understand what's going on with trap. > Maybe I misunderstand what it's for, but it doesn't seem to work the > way I want. I can't seem to properly trap based on the signal name, > and reading through some docs led me to this type of code: Signals are used to asynchronously interrupt programs. For example when you press Ctrl+C, the operating system sends SIGINT (the "interrupt" signal) to whatever program's running. You can send signals programmatically, in Ruby using Process.kill(signal, process_id), and you set signal-handlers to deal with signals your program is sent using trap. In the case of SIGINT, Ruby would normally raise the exception Interrupt (a subclass of SignalException). As with any exception, if that's not handled, the program will terminate. So we specify alternate behaviour with trap. trap :INT, begin require 'termios' # http://raa.ruby-lang.org/project/ruby-termios/ c = Termios.tcgetattr(STDIN).cc[Termios::VINTR] proc { STDIN << c } rescue LoadError proc {} end The overall format is trap(:INT, ...) -- the return value of the begin..end block is being passed as the handler for trap. The simple case is just "trap(:INT, proc {}". That means, "if I get a SIGINT, do nothing." The termios stuff is only going to work on *nix and if the ruby-termios package is installed. It gets the character that the terminal converts into a SIGINT, and puts in on the input stream. (Because *nixes apparently don't send the character if it's the SIGINT character; Windows does.) Either way, the main point is simply to avoid Ctrl+C crashing the program. > Signal.trap(0, lambda { puts "interrupted.." ; exit }) > > Signal 0 seems to be a generic exit code. I can list the signals with > this: > > Signal.list.each { |i| > print i > puts "" > } > > but I don't know the correct signal to use. 0 is SIGEXIT. You'll get a SIGEXIT as your program terminates: C:\>ruby trap(:EXIT, proc {puts "bye"}) ^Z bye C:\> I'm tipping all you care about is SIGINT. > Now I'm going to give up, not just because it's almost 3am but because > catching 3 from read_char does the job for me. If/when I end up > working with signals I'll definitely need to revisit this stuff. Interesting... it appears no trap's necessary on Windows if you're using _getch. You can use ?\cC instead of 3. > ... > i = 1 > until i > 3 > a = read_char > if a == 3 then puts "Interrupt received. This shouldn't be > displayed.\n ... but it does." ; break ; end > puts "I received: " + a.to_s > i += 1 > end > > puts "This shouldn't display upon interrupt." > puts " ... but it always displays" > > Signal.trap(3, lambda { puts "interrupted.." ; exit }) Your trap isn't being added until it's too late. While you're in read_char, Windows' _getch function will return 3 rather than be interrupted, so that works fine anyway. Cheers, Dave