home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Information / Stuart's Tech Notes / Blobby password entry.c < prev    next >
Encoding:
Text File  |  1995-06-14  |  4.8 KB  |  142 lines  |  [TEXT/R*ch]

  1. // (C) 1992 Stuart Cheshire <cheshire@cs.stanford.edu>
  2. //
  3. // This is the user-entry dialog box code, with a special custom FilterProc to
  4. // do the 'blobby' password field because Apple provides no standard dialog item
  5. // to give that behaviour. More re-inventing the wheel. It also checks whether
  6. // any of the password is typed with Caps Lock pressed -- so that the user can
  7. // be given a hint about the probable reason if their password is rejected.
  8.  
  9. #define USERNAME_RESOURCE_ID 128
  10. #define CAPS_LOCK 0x39
  11. static Boolean caps_pressed = FALSE;
  12.  
  13. // Dialogs in program
  14. enum { dialog_password = 128 };
  15.  
  16. // Buttons in the password dialog
  17. enum { dlog_OK = 1, dlog_Cancel, dlog_useritem, dlog_username, dlog_password };
  18.  
  19. static void DeleteRange(unsigned char *buffer, short start, short end)
  20.     {
  21.     unsigned char *last = buffer + buffer[0];
  22.     unsigned char *src  = buffer + 1 + end;
  23.     unsigned char *dest = buffer + 1 + start;
  24.     while (src <= last) *dest++ = *src++;        // Close up gap in string
  25.     buffer[0] -= (end-start);                    // Adjust the buffer's length
  26.     }
  27.  
  28. static void InsertChar(unsigned char *buffer, short pos, char c)
  29.     {
  30.     unsigned char km[16];
  31.     register short i = buffer[0];
  32.     if (i == 0xFF) return;    // return if string already full
  33.     while (i > pos) { buffer[i+1] = buffer[i]; i--; }
  34.     buffer[pos+1] = c;        // Fill in the new character
  35.     buffer[0]++;            // Add one to the length of the string
  36.     GetKeys((long *)km);
  37.     if (km[CAPS_LOCK>>3] & 1 << (CAPS_LOCK & 7)) caps_pressed = TRUE;
  38.     }
  39.  
  40. static pascal Boolean FilterProc(DialogPtr dlog, EventRecord *event, short *itemHit)
  41.     {
  42.     char key = event->message & charCodeMask;
  43.     Boolean editing_password = (((DialogPeek)dlog)->editField == dlog_password-1);
  44.     
  45.     // Only do special processing for keyboard events
  46.     if (event->what != keyDown && event->what != autoKey) return(false);
  47.     
  48.     // if in password field, Return & Enter are equivalent to hitting the OK button
  49.     // otherwise they are equivalent to a TAB, to move us into the password field.
  50.     // This is because Unix users often press return after entering their user name
  51.     // instead of TAB -- no need to make there lives any harder
  52.     if (key==3 || key==13)
  53.         {
  54.         if (editing_password) { *itemHit = 1; return(true); }
  55.         else { event->message = '\t'; return(false); }
  56.         }
  57.     
  58.     // Escape hits cancel
  59.     if (key==27) { *itemHit = 2; return(true); }
  60.     
  61.     // Ignore command keys
  62.     if (event->modifiers & cmdKey) { event->what = nullEvent; return(false); }
  63.     
  64.     // All keys except Tab and cursor keys get our special treatment
  65.     if (editing_password && key!='\t' && (key<28 || key>31))
  66.         {
  67.         unsigned char *buffer = (unsigned char*)GetWRefCon(dlog);    // Get buffer's address
  68.         short start = (*((DialogPeek)dlog)->textH)->selStart;        // Get current selection
  69.         short end   = (*((DialogPeek)dlog)->textH)->selEnd;
  70.         if (start > buffer[0]) start = buffer[0];            // Sanity checks,
  71.         if (end   > buffer[0]) end   = buffer[0];            // just in case
  72.         
  73.         if (start != end) DeleteRange(buffer,start,end);    // If there's a selection, delete it
  74.             
  75.         // If not delete key then stash the key and change code to a blob, else
  76.         // see if we have to delete a single character (when there is no selection)
  77.         if (key != 8) { InsertChar(buffer,start,key); event->message = 'Ä'; }
  78.         else if (start == end && start > 0) DeleteRange(buffer,start-1,start);
  79.         }
  80.     return(false);         // Let ModalDialog insert the fake char
  81.     }
  82.  
  83. static pascal void OutlineOK(DialogPtr dlg, short item)
  84.     {
  85.     int i;
  86.     short    di_type;
  87.     Handle    di_handle;
  88.     Rect    di_box;
  89.     PenSize(3,3);
  90.     GetDItem(dlg, dlog_OK, &di_type, &di_handle, &di_box);
  91.     InsetRect(&di_box,-4,-4);
  92.     FrameRoundRect(&di_box,16,16);
  93.     PenNormal();
  94.     }
  95.  
  96. static void do_dialog(void)
  97.     {
  98.     Handle  username = GetResource('STR ', USERNAME_RESOURCE_ID);
  99.     Str255  user, pass;
  100.     short    di_type, item;
  101.     Handle    di_handle;
  102.     Rect    di_box;
  103.     DialogPtr modal = GetNewDialog(dialog_password, NULL, (WindowPtr)(-1));
  104.     
  105.     GetDItem(modal, dlog_useritem, &di_type, &di_handle, &di_box);
  106.     SetDItem(modal, dlog_useritem,  di_type, (Handle)OutlineOK, &di_box);
  107.  
  108.     GetDItem(modal, dlog_username, &di_type, &di_handle, &di_box);
  109.     SetIText(di_handle, (StringPtr)*username);    // Get username from resource
  110.     GetIText(di_handle, user);                    // and initialize 'user' with it.
  111.     SelIText(modal, dlog_username, 0, 32767);
  112.     
  113.     pass[0] = 0;
  114.     caps_pressed = FALSE;
  115.     SetWRefCon(modal,(long)pass);
  116.     ShowWindow(modal);
  117.  
  118.     while(TRUE)
  119.         {
  120.         SetPort(modal);
  121.         GetDItem(modal, dlog_OK, &di_type, &di_handle, &di_box);
  122.         HiliteControl((ControlHandle)di_handle, *user ? 0 : 255);
  123.         
  124.         ModalDialog(FilterProc, &item);
  125.         GetDItem(modal, dlog_username, &di_type, &di_handle, &di_box);
  126.         GetIText(di_handle, user);
  127.         
  128.         if (item == dlog_Cancel) break;
  129.         else if (item == dlog_OK)
  130.             {
  131.             if (!*user) continue;    // invalid choice if no name
  132.             // (Note: this test because pressing Return hits OK button even if disabled)
  133.             
  134.             // here do whatever stuff with (user, pass);
  135.             
  136.             break;
  137.             }
  138.         }
  139.     ReleaseResource(username);
  140.     DisposDialog(modal);
  141.     }
  142.