http://qs321.pair.com?node_id=11143390


in reply to Unable to capture mouse events in Win32::Console

Hi all, the following is what I put together based on all of the feedback that you've provided:

# This program displays details about console events that occur in +the window in # wnich this program is running. This program creates a file calle +d "event_log.txt" # in the current directory. # # References: # # https://docs.microsoft.com/en-us/windows/console/reading-i +nput-buffer-events # # Definitions and values of constants such as ENABLE_* are avail +able at the # following URL: # # https://docs.microsoft.com/en-us/windows/console/setconsol +emode # BEGIN { select STDERR; $|++; # do not buffer STDERR select STDOUT; $|++; # do not buffer STDOUT system ("cls"); print "\n\n\tInitializing the environment ...\n\n\t"; }; use strict; use warnings; # The following package provides access to basic information about t +he runtime environment # such as the release of Windows under which this program is running use Win32; # The following package provides access to console events such as ke +y presses and mouse clicks use Win32::Console; my $console; my @console_event; my @info; my $log_file = "event_log.txt"; my $fh_log_file; unless (open ($fh_log_file, ">", $log_file)) { print STDERR "\nCould not open $log_file: $!\n\n"; die; } unless ($console = Win32::Console -> new (STD_INPUT_HANDLE)) { print STDERR "\nSomething has gone wrong with the Win32::Conso +le constructor: $!\n\n"; die; } $console -> Flush (); my $starting_console_mode_setting = $console -> Mode; END {$console -> Mode ($starting_console_mode_setting)}; # The following instruction is based on expertise provided by vr # at https://www.perlmonks.org/?node_id=11143316 $console -> Mode ((($starting_console_mode_setting | 0x0010 ) & ~0x004 +0 ) & ~ENABLE_PROCESSED_INPUT); print "Perl version $^V running on ", join (" ", Win32::GetOSName), ". +\n\n"; print $fh_log_file "Perl version $^V running on ", join (" ", Win32::G +etOSName), ".\n\n"; # The following is to demonstrate that the $console environment has +been set up print "Your mouse has ", $console->MouseButtons(), " buttons.\n\n"; print $fh_log_file "Your mouse has ", $console->MouseButtons(), " butt +ons.\n\n"; print "Enter keyboard activity or mouse events ...\n\n"; print $fh_log_file "Enter keyboard activity or mouse events ...\n\n"; my $start_time = time (); my $when_to_stop_listening = $start_time + 15; while (time () < $when_to_stop_listening) { if ($console -> GetEvents ()) # This may be unnecessary, c +an simply invoke Input () # and check if it has return +ed anything { @console_event = $console -> Input (); print "A console event has been detected. Its attribu +tes are the following:\n\n"; print $fh_log_file "A console event has been detected. + Its attributes are the following:\n\n"; print "Time of event: ", time (), "\n"; print $fh_log_file "Time of event: ", time (), "\ +n"; print "Type of event: "; print $fh_log_file "Type of event: "; if (defined ($console_event [0])) { if ($console_event [0] == 1) { print "Keyboard event.\n"; print $fh_log_file "Keyboard event.\n" +; print "Key down: ", $console +_event[1], "\n"; print $fh_log_file "Key down: + ", $console_event[1], "\n"; print "Repeat count: ", $console +_event[2], "\n"; print $fh_log_file "Repeat count: + ", $console_event[2], "\n"; print "Virtual key code: ", $console +_event[3], "\n"; print $fh_log_file "Virtual key code: + ", $console_event[3], "\n"; print "Virtual scan code: ", $console +_event[4], "\n"; print $fh_log_file "Virtual scan code: + ", $console_event[4], "\n"; print "ASCII code: ", $console +_event[5], "\n"; print $fh_log_file "ASCII code: + ", $console_event[5], "\n"; print "ASCII code letter: ", chr $co +nsole_event[5], "\n"; print $fh_log_file "ASCII code letter: + ", chr $console_event[5], "\n"; print "Control key state: ", $console +_event[6], "\n"; print $fh_log_file "Control key state: + ", $console_event[6], "\n"; } elsif ($console_event [0] == 2) { print "Mouse event.\n"; print $fh_log_file "Mouse event.\n"; print "Mouse X coord: ", $console +_event[1], "\n"; print $fh_log_file "Mouse X coord: + ", $console_event[1], "\n"; print "Mouse Y coord: ", $console +_event[2], "\n"; print $fh_log_file "Mouse Y coord: + ", $console_event[2], "\n"; print "Mouse button state: ", $console +_event[3], "\n"; print $fh_log_file "Mouse button state +: ", $console_event[3], "\n"; print "Control key state: ", $console +_event[4], "\n"; print $fh_log_file "Control key state: + ", $console_event[4], "\n"; print "Event flags: ", $console +_event[5], "\n"; print $fh_log_file "Event flags: + ", $console_event[5], "\n"; } else { print "Unknown type \"$console_event[0 +]\".\n"; print $fh_log_file "Unknown type \"$co +nsole_event[0]\".\n"; } print "\nAdditional information:\n"; print $fh_log_file "A\ndditional information:\ +n"; @info = $console -> Info (); # @info is supposed to contain the following + elements: # # $info[0]: columns (X size) of the consol +e buffer. # $info[1]: rows (Y size) of the console b +uffer. # $info[2]: current column (X position) of + the cursor. # $info[3]: current row (Y position) of th +e cursor. # $info[4]: current attribute used for Wri +te. # $info[5]: left column (X of the starting + point) of the current console window. # $info[6]: top row (Y of the starting poi +nt) of the current console window. # $info[7]: right column (X of the final p +oint) of the current console window. # $info[8]: bottom row (Y of the final poi +nt) of the current console window. # $info[9]: maximum number of columns for +the console window, given the current buffer size, font and the scree +n size. # $info[10]: maximum number of rows for the + console window, given the current buffer size, font and the screen s +ize. # # but look at what is actually happening: print "The size of \@info is ", scalar @info, +".\n"; print $fh_log_file "The size of \@info is ", s +calar @info, ".\n"; print "The value of \$info[0] is \"", $info[0] +, "\".\n"; print $fh_log_file "The value of \$info[0] is +\"", $info[0], "\".\n"; print "\n"; print $fh_log_file "\n"; } else { print "undefined event type.\n"; print $fh_log_file "undefined event type.\n"; } print "\n"; print $fh_log_file "\n"; } } print "The time to stop listening has been reached. Program is ending +.\n\n"; print $fh_log_file "The time to stop listening has been reached. Prog +ram is ending.\n\n";

When I run this in my environment, I find that $console -> Info () returns only a one-element array the single member of which is an empty string. Because some of the Info () elements are critical to my real application, I looked again at Win32::GUI and found that it can be used with non-owned windows, i.e., windows that it did not create. A quick test program revealed that it provided all of the functionality that I need for my real project. Given that Win32::Console was written to be used with what Microsoft is now calling legacy consoles, whereas Win32::GUI was written in 2017 and seems to work exactly as its documentation describes, it seems that Win32::GUI is the better way to go, at least for now. One comment that was provided was that using the TCL module is actually the best way to go in the long run.

Thanks again for all of the very constructive feedback.