Pregunta

I am fairly new to Perl and am having a hard time grasping the behavior of the following password input code snippet:

use Win32::Console;

my $StdIn = new Win32::Console(STD_INPUT_HANDLE);
my $Password = "";

$StdIn->Mode(ENABLE_PROCESSED_INPUT());
local $| = 1;

print "Enter Password: ";
while (my $Data = $StdIn->InputChar(1)) {
    if ("\r" eq $Data ) {
        last;
    } 
    elsif ("\ch" eq $Data ) {
        if ( "" ne chop( $Password )) {
            print "\ch \ch";
        }
        next;
    }
    $Password .=$Data;
    print "*";
}

while (my $Data = $StdIn->InputChar(1)) {
    print "\nShow password? [y/n] ";
    if ("n" eq $Data) {
        last;
    }
    elsif ("y" eq $Data) {
        print "\nPassword: $Password\n";
        last;
    }
}

Basically what happens is that the script prompts the user for a password and displays * for every character input as expected but requires Enter to be pressed twice to accept the input. However, if I delete the second while loop (or replace with a print $password statement) the input only requires one press of Enter.

I have also noticed that in the second while loop, which prompts the user to enter y or n (without needing to press Enter) if the user enters 'y' then the line Show password? [y/n] is repeated before displaying the password.

Some insight on this behavior would be appreciated.

¿Fue útil?

Solución

The first Enter gets you out of the first while loop. The second while loop then waits for another character before displaying the prompt. You should display the prompt before asking for another character (and display it only once).

Breaking things into subroutines helps build on basic blocks.

use strict; use warnings;
use Win32::Console;

run();

sub run {
    my $StdIn = Win32::Console->new(STD_INPUT_HANDLE);
    $StdIn->Mode(ENABLE_PROCESSED_INPUT);

    my $Password = prompt_password($StdIn, "Enter Password: ", '*');

    if ( prompt_echo($StdIn, "\nShow password? [y/n] ") ) {
        print "\nPassword = $Password\n"
    }

    return;
}

sub prompt_password {
    my ($handle, $prompt, $mask) = @_;
    my ($Password);

    local $| = 1;
    print $prompt;

    $handle->Flush;

    while (my $Data = $handle->InputChar(1)) {
        last if "\r" eq $Data;

        if ("\ch" eq $Data ) {
            if ( "" ne chop( $Password )) {
                print "\ch \ch";
            }
            next;
        }

        $Password .= $Data;
        print $mask;
    }

    return $Password;
}

sub prompt_echo {
    my ($handle, $prompt) = @_;

    local $| = 1;
    print $prompt;
    $handle->Flush;

    while (my $Data = $handle->InputChar(1)) {
        return if "n" eq $Data;
        return 1 if "y" eq $Data;
    }

    return;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top