home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-28 | 6.1 KB | 191 lines | [TEXT/R*ch] |
- // (C) 1992-1995 Stuart Cheshire <cheshire@cs.stanford.edu>
- //
- // This is password entry dialog box code, with a special custom FilterProc to
- // do the 'blobby' password field because Apple provides no standard dialog item
- // to give that behaviour. More re-inventing the wheel. It also checks whether
- // any of the password is typed with Caps Lock pressed -- so that the user can
- // be given a hint about the probable reason if their password is rejected.
-
- #define USERNAME_RESOURCE_ID 128
- #define CAPS_LOCK 0x39
-
- // Dialogs in program
- enum { dialog_password = 128 };
-
- // Items in the password dialog
- enum { dlog_OK = 1, dlog_Cancel, dlog_useritem, dlog_username, dlog_password };
-
- typedef struct
- {
- Str255 user, pass;
- Boolean EnableOK;
- Boolean OutlineOK;
- Boolean OldOutlineOK;
- Boolean caps_pressed;
- } PromptInfo;
-
- local pascal void doOutlineOK(DialogPtr dlog, short item)
- {
- PromptInfo *info = (PromptInfo *)GetWRefCon(dlog);
- int i;
- short di_type;
- Handle di_handle;
- Rect di_box;
- GetDItem(dlog, dlog_OK, &di_type, &di_handle, &di_box);
- InsetRect(&di_box,-4,-4);
- PenNormal();
- PenSize(3,3);
- if (!info->OutlineOK) ForeColor(whiteColor);
- FrameRoundRect(&di_box,16,16);
- PenNormal();
- ForeColor(blackColor);
- info->OldOutlineOK = info->OutlineOK;
- }
-
- static Boolean ClickButton(DialogPtr dlog, EventRecord *event, short *itemHit, short item)
- {
- short di_type;
- ControlHandle di_handle;
- Rect di_box;
- GetDItem(dlog, item, &di_type, (Handle*)&di_handle, &di_box);
-
- // If button not disabled, click it
- if (di_handle[0]->contrlHilite != 255)
- {
- long finalTick;
- HiliteControl(di_handle, inButton);
- Delay(5, &finalTick);
- HiliteControl(di_handle, 0);
- *itemHit = item;
- return(true);
- }
- else // else, ignore the event
- {
- event->what = nullEvent;
- return(false);
- }
- }
-
- static void DeleteRange(unsigned char *buffer, short start, short end)
- {
- unsigned char *last = buffer + buffer[0];
- unsigned char *src = buffer + 1 + end;
- unsigned char *dest = buffer + 1 + start;
- while (src <= last) *dest++ = *src++; // Close up gap in string
- buffer[0] -= (end-start); // Adjust the buffer's length
- }
-
- static void InsertChar(unsigned char *buffer, short pos, char c)
- {
- register short i = buffer[0];
- if (i == 0xFF) return; // return if string already full
- while (i > pos) { buffer[i+1] = buffer[i]; i--; }
- buffer[pos+1] = c; // Fill in the new character
- buffer[0]++; // Add one to the length of the string
- }
-
- static pascal Boolean FilterProc(DialogPtr dlog, EventRecord *event, short *itemHit)
- {
- PromptInfo *info = (PromptInfo *)GetWRefCon(dlog);
- char key = event->message & charCodeMask;
- Boolean editing_password = (((DialogPeek)dlog)->editField == dlog_password-1);
-
- info->OutlineOK = info->EnableOK && (editing_password || info->pass[0]);
- if (info->OldOutlineOK != info->OutlineOK) doOutlineOK(dlog, 1);
-
- // Only do special processing for keyboard events
- if (event->what != keyDown && event->what != autoKey) return(false);
-
- // if in password field, or if password field is already filled in, Return & Enter
- // are equivalent to hitting the OK button
- // Otherwise they are equivalent to a TAB, to move us into the password field.
- // This is because Unix users often press return after entering their user name
- // instead of TAB -- no need to make there lives any harder.
-
- if (key==3 || key==13)
- {
- // If OK button is outlined, then pressing <Return> hits it
- if (info->OutlineOK) return(ClickButton(dlog, event, itemHit, 1));
- else { event->message = '\t'; return(false); }
- }
-
- // Escape or Command-Period hits cancel
- if (key==27 || (key == '.' && event->modifiers & cmdKey))
- return(ClickButton(dlog, event, itemHit, 2));
-
- // Ignore command keys
- if (event->modifiers & cmdKey) { event->what = nullEvent; return(false); }
-
- // All keys except Tab and cursor keys get our special treatment
- if (editing_password && key!='\t' && (key<28 || key>31))
- {
- short start = (*((DialogPeek)dlog)->textH)->selStart; // Get current selection
- short end = (*((DialogPeek)dlog)->textH)->selEnd;
- if (start > info->pass[0]) start = info->pass[0]; // Sanity checks,
- if (end > info->pass[0]) end = info->pass[0]; // just in case
- if (start != end) DeleteRange(info->pass,start,end); // If there's a selection, delete it
-
- // If not delete key then stash the key and change code to a blob, else
- // see if we have to delete a single character (when there is no selection)
- if (key != 8)
- {
- unsigned char km[16];
- GetKeys((unsigned long *)km);
- if (km[CAPS_LOCK>>3] & 1 << (CAPS_LOCK & 7)) info->caps_pressed = TRUE;
- InsertChar(info->pass,start,key);
- event->message = '•';
- }
- else if (start == end && start > 0) DeleteRange(info->pass,start-1,start);
- }
- return(false); // Let ModalDialog insert the fake char
- }
-
- static void do_dialog(void)
- {
- Handle username = GetResource('STR ', USERNAME_RESOURCE_ID);
- PromptInfo info;
- short di_type, item;
- Handle di_handle;
- Rect di_box;
- DialogPtr modal = GetNewDialog(dialog_password, NULL, (WindowPtr)(-1));
-
- GetDItem(modal, dlog_useritem, &di_type, &di_handle, &di_box);
- SetDItem(modal, dlog_useritem, di_type, (Handle)doOutlineOK, &di_box);
-
- GetDItem(modal, dlog_username, &di_type, &di_handle, &di_box);
- SetIText(di_handle, (StringPtr)*username); // Get username from resource
- GetIText(di_handle, info.user); // and initialize 'user' with it.
- SelIText(modal, dlog_username, 0, 32767);
-
- info.pass[0] = 0;
- info.EnableOK = (info.user[0] > 0);
- info.OutlineOK = info.OldOutlineOK = info.caps_pressed = FALSE;
- SetWRefCon(modal,(long)&info);
- ShowWindow(modal);
-
- while(TRUE)
- {
- SetPort(modal);
- GetDItem(modal, dlog_OK, &di_type, &di_handle, &di_box);
- HiliteControl((ControlHandle)di_handle, info.EnableOK ? 0 : 255);
-
- ModalDialog(FilterProc, &item);
- GetDItem(modal, dlog_username, &di_type, &di_handle, &di_box);
- GetIText(di_handle, info.user);
- info.EnableOK = (info.user[0] > 0);
-
- if (item == dlog_Cancel) break;
- else if (item == dlog_OK)
- {
- // do required stuff with (info.user, info.pass);
-
- // if password is bad, and info.caps_pressed is TRUE,
- // maybe warn the user and try again?
-
- break;
- }
- }
- ReleaseResource(username);
- DisposDialog(modal);
- }
-