home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / The Hacks / ReaderMouse / MyCaptureAppShell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-06-26  |  12.2 KB  |  535 lines  |  [TEXT/CWIE]

  1. /*
  2.     ReaderMouse
  3.     
  4.     Written by Katherine Smith &
  5.                 Jesse Donaldson    
  6.     
  7.     We used a bit of apple sample source code, so portions are copyright Apple.
  8.     
  9. */
  10. #include    <Speech.h>
  11.  
  12. #include    "MyHeaders.h"
  13.  
  14. #include    "MyCaptureAppShell.h"
  15. #include    "LetterFind.h"
  16. #include    "WorkFunctions.h"
  17. #include    "MyUtils.h"
  18.  
  19. #define kMouseRegionWidth    120
  20. #define kMouseRegionHeight    50
  21.  
  22. #ifdef powerc
  23. //QDGlobals        qd;
  24. #endif
  25.  
  26. Boolean            gDone;            //    Set to true if you want to Application to kindly quit.
  27.  
  28. WindowPtr        gWin = 0;
  29.  
  30. GWorldPtr        gRecognizeThis = 0;
  31. unsigned long     gLastTicks = 0;
  32. Rect            gLastWordRect = {0,0,0,0};
  33. Point            gLastMousePos = {0,0};
  34. unsigned long    gLastMouseTicks = 0;
  35.  
  36. void DoStuffo(void);
  37. void DoWorkOnImageData(GWorldPtr inGWorld, Point* origin);
  38. void PostProcessWord(Str255 str);
  39. Boolean CheckMouse(void);
  40.  
  41. /* ------------------------------------------------------------------------- */
  42.  
  43. void main()
  44. {
  45.     EventRecord     myEvent;
  46.     long            yieldTime = 10;
  47.     WindowPtr        foundWindow;
  48.     short            windowPart;
  49.     Boolean            isEvent;
  50.     GrafPtr            savePort;
  51.     GDHandle        saveGD;
  52.     OSErr            err=noErr;
  53.  
  54.     //    Initialize here.  Set the yield time too.
  55.     // bestTimeBase
  56. //    err = ProfilerInit(collectDetailed,microsecondsTimeBase,50,10);
  57.     Initialize();
  58.  
  59.     //    Event loop.
  60.     for ( ; ; ) {
  61.  
  62.         //    Get the event.
  63.         isEvent = WaitNextEvent(everyEvent, &myEvent, yieldTime, nil);
  64.         
  65.         
  66.         if((TickCount() - gLastTicks) > (60*1))
  67.         {
  68.             DoStuffo();
  69.             gLastTicks = TickCount();
  70.         }
  71.         //    If the event is unhandled by app specific event handling, then we proceed.
  72.         if ( isEvent ) {
  73.             switch ( myEvent.what ) {
  74.  
  75.                 case mouseDown:
  76.                     //    Get current port and device.
  77.                     GetPort(&savePort);
  78.                     saveGD = GetGDevice();
  79.                     
  80.                     //    Set the port and gdevice to the window if we own the window.
  81.                     //    We can then assume anytime the event occured in one of our windows,
  82.                     //       that the port and gdevice are set correctly.
  83.                     windowPart = FindWindow(myEvent.where, &foundWindow);
  84.                     SetPort(foundWindow);
  85.                     SetGDevice(GetMainDevice());
  86.                     
  87.                     //    Handle the different mouse down events.
  88.                     switch ( windowPart ) {
  89.                         case inSysWindow:
  90.                             SystemClick(&myEvent, foundWindow);
  91.                             break;
  92.                         case inMenuBar:
  93.                             DoCommand(MenuSelect(myEvent.where));
  94.                             break;
  95.                         case inContent:
  96.                             break;
  97.                         case inDrag:
  98.                             //    If dragging one of the application's windows, then handle it.
  99.                             //    However, if we are dragging a zoomed window, we
  100.                             //    must remember to save the new window location into the
  101.                             //    zoomed rect in the data handle.  Otherwise, the event
  102.                             //    manager will think that we are no longer zoomed.
  103.                             {
  104.                                 WStateData    *zoomData;
  105.                                 Rect        windowRect;
  106.                                 
  107.                                 //    Get window location before drag.
  108.                                 GetGlobalWindow(foundWindow, &windowRect);
  109.                                 
  110.                                 //    Drag window.
  111.                                 DragWindow (foundWindow, myEvent.where, &qd.screenBits.bounds);
  112. //                                MyDrag(foundWindow, myEvent.where);
  113.  
  114.                                 //    If the windowRect in global coordinates matches the zoom rect,
  115.                                 //    then assume that we are dragging the zoomed window.  update
  116.                                 //    zoom rect.
  117.                                 zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
  118.                                 if ( EqualRect(&(zoomData->stdState), &windowRect) ) {
  119.                                     GetGlobalWindow(foundWindow, &windowRect);
  120.                                     zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
  121.                                     zoomData->stdState = windowRect;
  122.                                 }
  123.                             }
  124.                             break;
  125.                         case inGrow:
  126.                             break;
  127.                         case inGoAway:
  128.                             //    Handle clicking on the go away.  If it is the clip window,
  129.                             //    then hide it.
  130.                             if ( TrackGoAway (foundWindow, myEvent.where) ) {
  131.                                 BringToFront(foundWindow);
  132. //                                MyClose();
  133.                                 DisposeWindow(foundWindow);
  134.                                 if(foundWindow == gWin) gWin = 0;
  135.                             }
  136.                             break;
  137.                         case inZoomIn:
  138.                         case inZoomOut:
  139.                             break;
  140.                         default:
  141.                             break;
  142.                     }
  143.                     
  144.                     //    Restore port and device.
  145.                     SetPort(savePort);
  146.                     SetGDevice(saveGD);
  147.                     
  148.                     break;
  149.                 case keyDown:
  150.                 case autoKey:
  151.                     if ( myEvent.modifiers & cmdKey ) {
  152.                         if ( myEvent.what == keyDown ) {
  153.                             DoCommand(MenuKey(myEvent.message & charCodeMask));
  154.                         }
  155.                     }
  156.                     break;
  157.                 case updateEvt:
  158.                     //    Handle update events for window and clip window.
  159.                     foundWindow = (WindowPtr) myEvent.message;
  160.                     GetPort(&savePort);
  161.                     saveGD = GetGDevice();
  162.                     SetPort(foundWindow);
  163.                     SetGDevice(GetMainDevice());
  164.                     BeginUpdate(foundWindow);
  165.                     EndUpdate(foundWindow);
  166.                     SetPort(savePort);
  167.                     SetGDevice(saveGD);
  168.                     break;
  169.                 case diskEvt:
  170.                     //    This handles a bad disk.  Otherwise the disk will not eject.
  171.                     if ( myEvent.message >> 16 ) {
  172.                         Point    tempPoint;
  173.                         tempPoint.v = 50; tempPoint.h = 50;
  174.                         DIBadMount(tempPoint, myEvent.message);
  175.                     }
  176.                     break;
  177.                 case activateEvt:
  178.                     break;
  179.                 case app4Evt:
  180.                     switch ( myEvent.message >> 24 ) {
  181.                         case suspendResumeMessage:
  182. //                            yieldTime = MyYieldTime(myEvent.message & 0x01);
  183.                             break;
  184.                         default:
  185.                             DebugStr("\pUnexpected suspend/resume message.");
  186.                     }
  187.                     break;
  188.                 default:
  189.                     break;
  190.             }
  191.         }
  192.     
  193.         //    If DoneFlag set, then quit.
  194.         if ( gDone ) {
  195. //            err = ProfilerDump((unsigned char *)"\pProfileInfo");
  196. //            ProfilerTerm();
  197.             ExitToShell();
  198.         }
  199.     }
  200. }
  201.  
  202. /* ------------------------------------------------------------------------- */
  203.  
  204. void Initialize()
  205. {
  206.     OSErr                err;
  207.     Handle                myMenu;
  208.     Rect bounds;
  209.     
  210.     //    Initialize Managaer.
  211.     MaxApplZone();
  212.     MoreMasters(); MoreMasters();
  213.     MoreMasters(); MoreMasters();
  214.     MoreMasters(); MoreMasters();
  215.     MoreMasters(); MoreMasters();
  216.     InitGraf(&qd.thePort);
  217.     InitFonts();
  218.     FlushEvents(everyEvent, 0);
  219.     InitWindows();
  220.     InitDialogs(nil);
  221.     InitCursor();
  222.  
  223.     //    Set up menus.
  224.     myMenu = GetNewMBar(kMENUBAR);
  225.     SetMenuBar(myMenu);
  226.     DisposeHandle(myMenu);
  227.     AppendResMenu(GetMenuHandle(kMENU_APPLEID), 'DRVR');
  228.     DrawMenuBar();
  229.         
  230.     //    Setup other globals.
  231.     gDone = false;
  232.     
  233.     // Create window:
  234.     bounds.top = 50;
  235.     bounds.left = 50;
  236.     bounds.bottom = bounds.top + kMouseRegionHeight;
  237.     bounds.right = bounds.left + kMouseRegionWidth;
  238.     
  239.     gWin = NewCWindow(0, &bounds, "\pBits", true, documentProc, (WindowPtr)-1, true, 0);
  240.     SetPort(gWin);
  241.     
  242.     // Create gworld:
  243.     bounds.top = bounds.left = 0;
  244.     bounds.right = kMouseRegionWidth;
  245.     bounds.bottom = kMouseRegionHeight;
  246.     
  247.     err = NewGWorld(&gRecognizeThis, 16, &bounds, nil, nil, 0);    
  248.     
  249.     
  250.     //    Call app specific Intialization.
  251.     // Initialize Font data
  252.     err = InitializeFonts();
  253.     if (err != noErr)
  254.         DebugStr("\perror initializing...");
  255.     
  256.     
  257.     return;
  258. }
  259.  
  260. void DoCommand(long mResult)
  261. {
  262.     short             theMenu, theItem;
  263.     Str255            myStr;
  264.     GrafPtr            savePort;
  265.     GDHandle        saveGD;
  266.     
  267.     theItem = LoWord(mResult);
  268.     theMenu = HiWord(mResult);
  269.     
  270.     if ( theItem != 0 || theMenu != 0 ) {
  271.         switch ( theMenu ) {
  272.             case kMENU_APPLEID:
  273.                 if ( theItem == 1 ) {
  274.                     ParamText("\pSample QuickTime Recording Application", "\pUses Sequence Grabber.", nil, nil);
  275.                     Alert(kALERT_ABOUT, nil);
  276.                 } else {
  277.                     GetMenuItemText(GetMenuHandle(kMENU_APPLEID), theItem, myStr);
  278.                     GetPort(&savePort);
  279.                     saveGD = GetGDevice();
  280.                     (void) OpenDeskAcc(myStr);
  281.                     SetPort(savePort);
  282.                     SetGDevice(saveGD);
  283.                 }
  284.                 break;
  285.     
  286.             case kMENU_FILEID:
  287.                 switch ( theItem ) {
  288.                     case kMENU_FILENEW:
  289. //                        MyNew();
  290.                         break;
  291.                     case kMENU_FILECLOSE:
  292. //                        MyClose();
  293.                         break;
  294.                     case kMENU_FILEQUIT:
  295.                         gDone = true;
  296.                         break;
  297.                     default:
  298.                         ReportFatal("\pError in handling file menu:", theItem);
  299.                 }
  300.                 break;
  301.     
  302.             case kMENU_SETTINGSID:
  303. //                MySettings(theItem);
  304.                 break;
  305.     
  306.             case kMENU_RESIZEID:
  307. //                MyResize(theItem);
  308.                 break;
  309.     
  310.             case kMENU_SPECIALID:
  311. //                MySpecial(theItem);
  312.                 break;
  313.     
  314.             case kMENU_RECORDID:
  315. //                MyRecord();
  316.                 break;
  317.     
  318.             default:
  319.                 ReportFatal("\pError in handling menu:", theMenu);
  320.         }
  321.     }
  322.     HiliteMenu(0);
  323. }
  324.  
  325. void DoStuffo(void)
  326. {
  327.     Rect        srcRect, dstRect = {0,0,0,0};
  328.     Point        where;
  329.     
  330.     if(gWin == 0) return;
  331.     
  332.     SetPort(gWin);
  333.     GetMouse(&where);
  334.     LocalToGlobal(&where);
  335.     
  336.     // don't do any work if we're still 
  337.     // pointing at the last word we recognized.
  338.     if(PtInRect(where, &gLastWordRect)) return;
  339.     
  340.     // clear rectangle now that we've moved out of it.
  341.     gLastWordRect.top = gLastWordRect.left = 0;
  342.     gLastWordRect.bottom = gLastWordRect.right = 0;
  343.     
  344.     // abort if we moved the mouse.
  345. //    if( CheckMouse() ) return;
  346.     
  347. //    GetPort(&savePort);
  348. //    saveGD = GetGDevice();
  349. //    SetPort((GrafPort*)gWorkGWorldPtr);
  350.  
  351.     LockPixels(GetGWorldPixMap(gRecognizeThis));
  352.     
  353.     srcRect.left = where.h - (kMouseRegionWidth/2);
  354.     srcRect.right = srcRect.left + kMouseRegionWidth;
  355.     srcRect.top = where.v - (kMouseRegionHeight/2);
  356.     srcRect.bottom = srcRect.top + kMouseRegionHeight;
  357.     
  358.     dstRect.right = gWin->portRect.right - gWin->portRect.left;
  359.     dstRect.bottom = gWin->portRect.bottom - gWin->portRect.top;
  360.     
  361.     CopyBits (&qd.screenBits, (BitMap*)*GetGWorldPixMap(gRecognizeThis), 
  362.                 &srcRect, &dstRect, srcCopy, 0);
  363.     
  364.     CopyBits ((BitMap*)*GetGWorldPixMap(gRecognizeThis), &gWin->portBits, 
  365.                 &dstRect, &dstRect, srcCopy, 0);
  366.  
  367.     UnlockPixels(GetGWorldPixMap(gRecognizeThis));
  368.     
  369.     // convert 'where' to GWorld origin in global coords
  370.     where.h = srcRect.left;
  371.     where.v = srcRect.top;
  372.     
  373.     DoWorkOnImageData(gRecognizeThis, &where);
  374.     
  375. //    qd.screenBits
  376. }
  377.  
  378. Boolean CheckMouse(void)
  379. {
  380.     Point        where;
  381.     Boolean result;
  382.     
  383.     if(gWin == 0) return true;
  384.     
  385.     SetPort(gWin);
  386.     GetMouse(&where);
  387.     LocalToGlobal(&where);
  388.     
  389.     result = (where.h != gLastMousePos.h || where.v != gLastMousePos.v);
  390.     gLastMousePos = where;
  391.     
  392.     return result;
  393.     
  394. /*    // If we move the mouse, reset the position & countdown timer
  395.     if(where.h != gLastMousePos.h || where.v != gLastMousePos.v)
  396.     {
  397.         gLastMousePos = where;
  398.         gLastMouseTicks = TickCount();
  399.         return true;
  400.     }
  401. */
  402.  
  403.  
  404.     // Recognition takes long enough that we can remove the artificial delay,
  405.     // as well as the earlier check, and then just check if the mouse
  406.     // has moved before we speak the string...
  407.     
  408.     // If the mouse hasn't moved for 20 ticks, 
  409.     // go ahead & recognize the pixels.
  410. /*    if((TickCount() - gLastMouseTicks) < 20)
  411.     {
  412.         return true;
  413.     }
  414.     else
  415.     {
  416.         gLastMousePos = where;
  417.         gLastMouseTicks = TickCount();
  418.     }
  419. */
  420.     return false;
  421. }
  422.  
  423. /*
  424.     Do post processing on string to make a good guess whether
  425.     a glyph is a capitol i or a lowercase L.
  426. */
  427. void PostProcessWord(Str255 str)
  428. {
  429.     Boolean allCaps, allLower;
  430.     short i, len;
  431.     Boolean letter2IsVowel;
  432.     
  433.     len = str[0];
  434.     
  435.     allCaps = true;
  436.     allLower = true;
  437.     
  438.     // Word is all capitol letters?
  439.     for(i=1; i<=len; i++)
  440.     {
  441.         if(str[i] < 'A' || str[i] > 'Z')
  442.         {
  443.             if(str[i] != 'l') allCaps = false;
  444.         }
  445.     }
  446.     
  447.     // Word is all lowercase letters?
  448.     for(i=1; i<=len; i++)
  449.     {
  450.         if(str[i] < 'a' || str[i] > 'z')
  451.         {
  452.             if(str[i] != 'L') allCaps = false;
  453.         }
  454.     }
  455.     
  456.     // Determine if 2nd letter is a vowel.        
  457.     if(len <= 1) letter2IsVowel = false;
  458.     else if(str[2] == 'a' || str[2] == 'e' || str[2] == 'i' || 
  459.             str[2] == 'o' || str[2] == 'u')
  460.         letter2IsVowel = true;
  461.     else letter2IsVowel = false;
  462.     
  463.     // Post process L's and i's.
  464.     for(i=1; i<=len; i++)
  465.     {
  466.         // turn capitol i into lowercase L.
  467.         // if its a capitol i and the word isn't all caps...
  468.         if(str[i] == 'I' && !allCaps) 
  469.         {
  470.             
  471.             // .. and if its NOT the first letter, or if its followed by a vowel...
  472.             if(i > 1 || letter2IsVowel)
  473.             {
  474.                 str[i] = 'l'; // then turn it into a lowercase L.
  475.             }
  476.         }
  477.         
  478.         // turn lowercase L into capitol i.
  479.         if(str[i] == 'l')
  480.         {
  481.             if(allCaps || (i==1 && !letter2IsVowel))
  482.                 str[i] = 'I';
  483.         }
  484.         
  485.     }
  486.     
  487.     return;
  488. }
  489.  
  490.  
  491. void DoWorkOnImageData (GWorldPtr    inGWorld, Point *origin)
  492. {
  493.     WordData bestWord;
  494.     Str255    spokenString;
  495.     
  496.     CheckMouse();
  497.     
  498.     
  499.     MyFindWord(&bestWord, inGWorld);
  500.     
  501.     CopyGWorldToWindow(gScreenHDiff, gWin);
  502.  
  503.     DrawChosenString(gWin, &bestWord);
  504.     
  505.     CopyWordToPascalString(spokenString, &bestWord);
  506.     SetWTitle(gWin, spokenString);
  507.     
  508.     
  509.     // special case for illegal 1-letter strings which seem to pop
  510.     // up when the recognizer doesn't have anything better to say.
  511.     if(spokenString[0] == 1 && spokenString[1] != 'I' && spokenString[1] != 'a'
  512.         && spokenString[1] != 'A' && 
  513.         (spokenString[1] < '0'|| spokenString[1] > '9'))
  514.     {
  515.         return;
  516.     }
  517.     
  518.     PostProcessWord(spokenString);
  519.     
  520.     // abort if we moved the mouse.
  521.     if( CheckMouse() ) return;
  522.     
  523.     // set up the word rect so we don't say it over & over again.
  524.     gLastWordRect = bestWord.wordBounds;
  525.     gLastWordRect.top += origin->v;
  526.     gLastWordRect.bottom += origin->v;
  527.     gLastWordRect.left += origin->h;
  528.     gLastWordRect.right += origin->h;
  529.     
  530.     SpeakString(spokenString);
  531.     
  532.     return;
  533. }
  534.  
  535.