[comp.sys.mac.programmer] suppress display of password entry

wade@sdacs.ucsd.EDU (Wade Blomgren) (05/18/88)

What is the best (easiest) way to allow entry of a password on the screen
while suppressing the display of the actual characters in the 
edittext item?  Use a dedicated font, like TOPS does? Or intercept 
all keydown events in a filter and change the key code to that of
a meaningless character like a bullet or hash?  The latter method
seems to be what is happening in, for example, AppleShare, but it
seems a bit difficult to keep track of the actual word that gets
typed if the person does any editing of the edittext item with
the mouse.  For example, if the user types "abc" and then clicks between
the a and the b, and inserts another letter, you would have a bit
of figuring to do if you wanted to figure out what the word entered
really was. What am I missing? Or is there yet another way to do this.
I suppose one solution is to avoid having an edited field at all and
just capture keydown events, but that seems somewhat inelegant.

Wade Blomgren
wade@sdacs.ucsd.edu

matthews@eleazar.dartmouth.edu (Jim Matthews) (05/19/88)

In article <536@sdacs.ucsd.EDU> wade@sdacs.ucsd.EDU (Wade Blomgren) writes:
>
>What is the best (easiest) way to allow entry of a password on the screen
>while suppressing the display of the actual characters in the 
>edittext item? 

It actually isn't very difficult to intercept the key events and keep 
a hidden copy of the password string.  It isn't necessary to remember
any context since you have access to the TextEdit record, and it tells
you what the current selection is.  The following routine is a filter
for a name/password dialog box.  It displays bullets (ala AppleShare)
and stores the real password in a global string, pwStr.  It also handles
hitting return or enter.

{ signonFilter -- dialog filter for doSignon, hides password }
FUNCTION signonFilter (dp : DialogPtr;
            VAR theEvent : EventRecord;
            VAR itemHit : integer) : boolean;
    CONST
        nameItem = 3;
        passwordItem = 4;
        bs = $08;
        tab = $09;
        cr = $0D;
        enter = $03;
        larrow = $1C;
        rarrow = $1D;
        uparrow = $1E;
        downarrow = $1F;
    VAR
        dpeek : DialogPeek;
        theChar : char;
        theStr : Str255;
        selStart, selEnd : integer;
        h : Handle;
        itemType : integer;
        box : Rect;
BEGIN
    signonFilter := false;
    dpeek := DialogPeek(dp);
    IF ((theEvent.what = keydown) OR (theEvent.what = autoKey)) THEN
        IF (dpeek^.editField = passwordItem - 1) THEN
        BEGIN
            theChar := char(BitAnd(theEvent.message, charCodeMask));
            selStart := dpeek^.textH^^.selStart;
            selEnd := dpeek^.textH^^.selEnd;
            CASE ord(theChar) OF
                bs :                { Backspace }
                    BEGIN
                        IF selEnd = selStart THEN  { back over a character }
                        BEGIN
                            IF selStart > 0 THEN
                                pwStr := concat(copy(pwStr,1, selStart - 1),
                                                  copy(pwStr, selStart + 1,
                                                   length(pwStr) - selStart));
                        END
                        ELSE            { delete the selection }
                            pwStr := concat(copy(pwStr, 1, selStart),
                             copy(pwStr, selEnd + 1,
                                   length(pwStr) - selEnd));
                    END;
                cr, enter :     { Return or Enter -- treat as "OK }
                    BEGIN
                        itemHit := ok;
                        signonFilter := true;
                    END; { cr, enter }
                tab, uparrow, downarrow, rarrow, larrow :
                    ;	     { just pass on tabs & arrows }
                OTHERWISE   { "normal" character }
                    BEGIN        { remember character, insert a bullet }
                        pwStr := concat(copy(pwStr, 1, selStart),
                         theChar,
                         copy(pwStr, selEnd + 1, length(pwStr) - selEnd));
                        theEvent.message :=
                         BitAnd(theEvent.message, $FFFFFF00) + ord('*');
                    END; { normal character }
            END; { case ord(theChar) of }
        END { in password field }
        ELSE     { not in password field -- still check for cr, enter }
            CASE BitAnd(theEvent.message, charCodeMask) OF
                cr, enter :
                    BEGIN
                        itemHit := ok;
                        signonFilter := true;
                    END; { cr, enter }
                OTHERWISE
                    ;
            END; { case BitAnd }
END; { signonFilter }

The bullet is replaced with an asterisk, since it's an 8-bit character.

Hope this helps,

Jim Matthews 
Software Development
jim.matthews@dartmouth.edu