NicM
NicM

Reputation: 179

Mask Password Input in a Console App

I am writing a console application using BDE 2006 and I want it to be able to prompt for a password string and mask it with "*" as the user is typing. I have looked around but I could not find examples of how to do this. Everything I saw was how to do this in TEdit. Any pointers on how to accomplish this?

Thanks in advance,

Nic

Upvotes: 11

Views: 3750

Answers (4)

Francesca
Francesca

Reputation: 21650

Here's a working solution:

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

function GetPassword(const InputMask: Char = '*'): string;
var
  OldMode: Cardinal;
  c: char;
begin
  GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), OldMode);
  SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), OldMode and not (ENABLE_LINE_INPUT or ENABLE_ECHO_INPUT));
  try
    while not Eof do
    begin
      Read(c);
      if c = #13 then // Carriage Return
        Break;
      Result := Result + c;
      if c = #8 then // Back Space
        Write(#8)
      else
        Write(InputMask);
    end;
  finally
    SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), OldMode);
  end;
end;

begin
  try
    Writeln(Format(sLineBreak + 'pswd=%s',[GetPassword]));
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Update: Note that the above code handles the BackSpaces visually, but keeps them embedded in the password, which might not be what you want.
In that case the following code would filter them out:

  if c = #13 then // Carriage Return
    Break;
  if (c = #8) and (Length(Result) > 0) then  // Back Space
  begin
    Delete(Result, Length(Result), 1);
    Write(#8);
  end
  else
  begin
    Result := Result + c;
    Write(InputMask);
  end;

Upvotes: 10

Andreas Rejbrand
Andreas Rejbrand

Reputation: 109158

This works.

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

const
  BUF_LEN = 1024;

var
  amt, i, cmode: cardinal;
  buf: packed array[0..BUF_LEN - 1] of char;

begin
  try

    Write('Enter password: ');
    GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), cmode);
    SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), cmode and not ENABLE_ECHO_INPUT);
    ReadConsole(GetStdHandle(STD_INPUT_HANDLE), @buf[0], BUF_LEN, amt, nil);
    SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), cmode);

    Writeln;
    Writeln;

    Writeln('You entered: ');
    for i := 0 to amt - 3 do
      Write(buf[i]);
    Writeln;
    Writeln;

    Writeln('Done');
    Readln;

  except
    on E:Exception do
    begin
      Writeln(E.Classname, ': ', E.Message);
      Readln;
    end;
  end;
end.

Upvotes: 2

jasonpenny
jasonpenny

Reputation: 3049

I have a unit with procedure ConsoleGetPassword(const caption: String; var Password: string); which does what you want

see http://gist.github.com/570659

Upvotes: 2

t0mm13b
t0mm13b

Reputation: 34598

Please see this article on CodeProject, it may be in C#, but it does give you the right clues and the direction to take, involving ReadConsoleInput and WriteConsole API

Upvotes: 0

Related Questions