redss has asked for the wisdom of the Perl Monks concerning the following question:

I want a program that will sleep waiting to be triggered by either an external event or user keypress.

The following code snippet uses Win32::Event and waits for an event, but is there a way for it to be interrupted by a user keypress?

use Win32::Event;

my $event = new Win32::Event( 0, 0, "MyEvent.$$" );

while (1) {
  $rv = $event->wait(1000);  # wait 1 sec

  if ($rv) {  
    print "called via event\n";
  } else {
    print "timeout\n";
  }
}

Replies are listed 'Best First'.
Re: Win32::Event question
by ikegami (Patriarch) on Jul 19, 2005 at 21:01 UTC
    I can think of three ways.

    1) Poll the keyboard

    use Win32::Event; # $end_time will be up to a second too short without Time::HiRes. use Time::HiRes; my $event = new Win32::Event( 0, 0, "MyEvent.$$" ); my $abort = 0; while (!$abort) { my $end_time = time + 1; # wait 1 sec while (1) { $rv = $event->wait(50); # Poll keyboard every 50ms if ($rv) { print "called via event\n"; last; } if (...a key is pressed...) { print "aborted by user\n"; $abort = 1; last; } if (time > $end_time) { print "timeout\n"; last; } } }

    2) Have a second thread monitor the keyboard. When a key is pressed, raise a "user aborted" event. The original thread now has to wait on two events (the original one and the "user aborted" event), but there's a function to do that.

    3) Use POE. I haven't checked if it can help you here, but I bet it can.

      Thanks for your response. It looks simplest to go with the first way. What is the code to check if a key is pressed?

        Try Term::ReadKey's ReadKey -1.

        There's also Win32::Console's PeekInput and Input.

        I haven't tried either. The second comes with ActivePerl.

      Well the more I think about it, I prefer option #2, since it would be best for the event not to timeout at a frequent polling interval. I'd rather have the event timeout at a larger interval and be interrupted when the user hits a key or aborts.

      The only issue is that the program would need to be able to determine whether it was interrupted by an external event, or by the "user aborted" or "user input" event".

      What kind of code would support that? Thanks!

        Check wait_any in Win32::IPC (which comes with ActivePerl for Windows). wait_any's return value states which event woke it up.