#!c:\strawberry\perl\bin\perl.exe -w # Name: gus_screensaver_defeat.pl # Copyright: Gan Uesli Starling, 2004-2012 # Purpose: Keeps Windows screensaver from tripping for as long as need be. # Changes: # Char string is now a pair of consecutive scroll locks. # Loop time shortened to one minute. # Added modification of Tye's jiggle-mouse function from PerlMonks.org # Skips current trip-loop if user has already moved mouse. my $version = "2012-01-31"; use Tk; use Win32::GuiTest qw< SendKeys GetCursorPos MouseMoveAbsPix >; ###################### # Begin user defaults # (Stuff you can change) ###################### my $jiggle_max = 20; # How many pixels max to randomly jiggle the mouse. my $loop_minutes = 1; # How many minutes between trips my $char_string = "{SCROLL}{SCROLL}"; # What char string to trip the shell with. my $exit_time_regex = "23:[0-9]{2}:[0-9]{2}"; # Exit program 11PM by default. my $tap_keyboard = 1; my $jiggle_mouse = 0; # For Tye's mouse-jiggle method, but a pattern of four diamonds around center. my($home_x, $home_y) = (0,0); # Set after user clicks Start. my($here_x, $here_y) = GetCursorPos(); # Set after user clicks Start. # A diamond shaped cloud of center positions from which to jiggle the mouse. my @dx= ( 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 0); my @dy= ( 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 0); ###################### # End user defaults # Begin GUS subs ###################### # Return Date Time Group in ISO 8601 approved fashion. sub update_DTG { my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time); my $DTG = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $year + 1900, $mon + 1, $mday, $hour, $min, $sec ); return ("$DTG"); } # Send trip any screensaver. sub trip_screensaver { SendKeys($char_string) if $tap_keyboard; jiggle_mouse() if $jiggle_mouse; } ###################### # End GUS subs # Begin Tye's sub ###################### # From Tye's mouse-jiggle script. # Modified for pseudo-random cloud versus repetitive diamond pattern. sub jiggle_mouse { my( $x, $y )= GetCursorPos(); if ($dx[0] == 0) {$x = $home_x; $y = $home_y} $x += $dx[0] * int(rand($jiggle_max)); push @dx, shift @dx; $y += $dy[0] * int(rand($jiggle_max)); push @dy, shift @dy; MouseMoveAbsPix( $x, $y ); } ###################### # End Tye's sub # Begin GUI stuff ###################### # First declare the main GUI frame and all her daughters. my $mw = MainWindow->new( -title => ' Screensaver Delay, Ver. ' . $version ); # Begin MENU BAR $mw->configure( -menu => my $menubar = $mw->Menu ); use subs qw/exit_menuitems/; map {$menubar->cascade( -label => '~' . $_->[0], -menuitems => $_->[1])} [ 'Stop', exit_menuitems ]; sub exit_menuitems { [ ['command', '00:00', -command => sub { $exit_time_regex = "00:[0-9]{2}:[0-9]{2}"} ], ['command', '03:00', -command => sub { $exit_time_regex = "15:[0-9]{2}:[0-9]{2}"} ], ['command', '06:00', -command => sub { $exit_time_regex = "06:[0-9]{2}:[0-9]{2}"} ], ['command', '09:00', -command => sub { $exit_time_regex = "09:[0-9]{2}:[0-9]{2}"} ], ['command', '12:00', -command => sub { $exit_time_regex = "12:[0-9]{2}:[0-9]{2}"} ], ['command', '15:00', -command => sub { $exit_time_regex = "15:[0-9]{2}:[0-9]{2}"} ], ['command', '18:00', -command => sub { $exit_time_regex = "18:[0-9]{2}:[0-9]{2}"} ], ['command', '21:00', -command => sub { $exit_time_regex = "21:[0-9]{2}:[0-9]{2}"} ], ['command', 'Never', -command => sub { $exit_time_regex = "This matches nothing"} ], ] } use subs qw/gus_or_tye/; map {$menubar->cascade( -label => '~' . $_->[0], -menuitems => $_->[1])} [ 'How', gus_or_tye ]; # Because Tk requires callbacks for each $foo->after() in sub def that follows. sub set_mouse_home_callback_0 { $last_trip = "Find mouse a home."; } sub set_mouse_home_callback_1 { ($home_x, $home_y) = GetCursorPos(); $last_trip = "Mouse home chosen."; } sub set_mouse_home_callback_2 { $last_trip = "SS Delay Started."; } # Give user time to set mouse somewhere convenient. sub set_mouse_home { if ($trip_flag){ $mw->after( 1_000, \&set_mouse_home_callback_0 ); # Tell user to set the mouse on 1st second. $mw->after( 5_000, \&set_mouse_home_callback_1 ); # Tell user mouse home is set on 5th second. $mw->after( 6_000, \&set_mouse_home_callback_2 ); # Tell user tripping has started on 6th second. } } sub gus_or_tye { [ ['command', 'Tap Keyboard', -command => sub { $tap_keyboard = 1; $jiggle_mouse = 0; } ], ['command', 'Jiggle Mouse', -command => sub { $tap_keyboard = 0; $jiggle_mouse = 1; set_mouse_home(); } ], ['command', 'Both', -command => sub { $tap_keyboard = 1; $jiggle_mouse = 1; set_mouse_home(); } ], ] } use subs qw/char_string/; map {$menubar->cascade( -label => '~' . $_->[0], -menuitems => $_->[1])} [ 'String', char_string ]; sub char_string { [ ['command', 'Caps Lock (on/off)', -command => sub { $char_string = "{CAPS}{CAPS}"} ], ['command', 'Insert (on/off)', -command => sub { $char_string = "{INSERT}{INSERT}"} ], ['command', 'Null', -command => sub { $char_string = "\000"} ], ['command', 'Numbers Lock (on/off)', -command => sub { $char_string = "{NUMLOCK}{NUMLOCK}"} ], ['command', 'Scroll Lock (on/off)', -command => sub { $char_string = "{SCROLL}{SCROLL}"} ], ['command', 'Space & Backspace', -command => sub { $char_string = ""} ], ] } my $fm_top = $mw->Frame( -relief => 'flat', -borderwidth => 5 ); # Make all the frames. my $fm_btm = $mw->Frame( -relief => 'flat', -borderwidth => 5 ); # Build the label and entry box widgets for the 'File path' frame. $fm_top->Entry( -textvariable => \$last_trip, -background => "white", -foreground => 'blue', -relief => 'sunken', -font => 'courier' )->pack( -side => 'left', -expand => 1, -fill => 'x' ); $fm_btm->Button( -text => ' Start ', -command => \&start_tripping, -background => 'gray', -activebackground => 'red', -relief => 'raised', )->pack( -side => 'left', -expand => 1, -fill => 'x' ); $fm_btm->Button( -text => ' Stop ', -command => \&stop_tripping, -background => 'gray', -activebackground => 'blue', -relief => 'raised', )->pack( -side => 'left', -expand => 1, -fill => 'x' ); $fm_btm->Button( -text => ' Exit ', -command => \&exit, -background => 'gray', -activebackground => 'green', -relief => 'raised', )->pack( -side => 'left', -expand => 1, -fill => 'x' ); # Pack all the frames last. $fm_top->pack( -side => 'top', -expand => 1, -fill => 'x' ); $fm_btm->pack( -side => 'top', -expand => 1, -fill => 'x' ); $trip_flag = 0; $last_trip = "Click any button!"; sub start_tripping { $trip_flag = 1; # Must preceed call to set_mouse_home() set_mouse_home() if $jiggle_mouse; $last_trip = "SS Delay Started."; } sub stop_tripping { $last_trip = "SS Delay Stopped."; $trip_flag = 0; } $mw->repeat( $loop_minutes * 60 * 1000, \&ss_trip ); # Empty sub def as callback to avoid GUI-freezing sleep effect of $foo->after() in sub def to follow. sub ss_trip_callback {} sub ss_trip { if (update_DTG =~ /$exit_time_regex/) { $last_trip = 'SS Delay Timeout'; } elsif ( $trip_flag # Tripping enabled && ( ($here_x, $here_y) == GetCursorPos() ) # Mouse not already moved by user. ) { # Trip once, twice or maybe three times in pseudo-random fashion. for (my $i=3; $i>0; $i-=int(rand(3))){ my $r = rand(5_000); $mw->after($r, \&ss_trip_callback); trip_screensaver(); $last_trip = update_DTG(); } } else { $last_trip = 'Mouse not idle.'; ($here_x, $here_y) = GetCursorPos(); } } MainLoop;