Почему для ввода пароля в Perl с помощью Win32::Console требуется дважды нажать Enter?

Я новичок в Perl, и мне трудно понять поведение следующего фрагмента кода ввода пароля:

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;
    }
}

По сути, сценарий запрашивает у пользователя пароль и отображает * для каждого введенного символа, как и ожидалось, но требует двойного нажатия Enter, чтобы принять ввод. Однако, если я удалю второй цикл while (или заменю оператором print $password), для ввода потребуется только одно нажатие Enter.

Я также заметил, что во втором цикле while пользователю предлагается ввести y или n (без необходимости нажимать Enter), если пользователь вводит «y», затем строка Show password? [y/n] повторяется перед отображением пароля.

Некоторое понимание этого поведения будет оценено.


person xmechanix    schedule 27.06.2012    source источник
comment
@KenWhite Спасибо за редактирование. Это было обидно ;-)   -  person Sinan Ünür    schedule 28.06.2012


Ответы (1)


Первый Enter выводит вас из первого цикла while. Затем второй цикл while ожидает другого символа, прежде чем отобразить подсказку. Вы должны отобразить подсказку перед запросом другого символа (и отобразить ее только один раз).

Разбивка вещей на подпрограммы помогает построить базовые блоки.

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;
}
person Sinan Ünür    schedule 27.06.2012