home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 17.ddi / SAMPLES / SREC / PENAPP.C_ / PENAPP.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  30.5 KB  |  1,069 lines

  1. /************************************************************
  2.  
  3.    PROGRAM: PENAPP.C
  4.  
  5.    PURPOSE: A generic template for a pen-aware app.
  6.  
  7.    COMMENTS:
  8.  
  9.       This code is a skeleton program containing all necessary
  10.       functionality to recognize pen input using three separate
  11.       recognizers: a custom, a shape, and the system recognizer.
  12.  
  13.       PENAPP accepts pen input through the Input Window.
  14.       Depending on the menu option, PENAPP sends the input
  15.       to either the system default recognizer, the sample custom
  16.       recognizer (SREC), or the shape recognizer (SHAPEREC).
  17.  
  18.       The output from the recognizers are displayed through the
  19.       Raw Data and Info windows.  The Raw Data window displays
  20.       the actual ink the user wrote or drew.  The Info window
  21.       displays one of three things:
  22.  
  23.          1) For the system recognizer -- the Info window outputs
  24.             the recognized ANSI text.
  25.  
  26.          2) For the sample custom recognizer -- the Info window
  27.             outputs an arrow indicating the compass direction of
  28.             the input stroke (up, down, left, or right).
  29.  
  30.          3) For the shape recognizer -- the Info window displays
  31.             a "clean" image of the shape.  Recognized shapes may
  32.             be rectangles, ellipses, or lines.
  33.  
  34. ************************************************************/
  35.  
  36. #define NOCOMM
  37. #include <windows.h>
  38. #include <string.h>
  39. #include <penwin.h>
  40. #include <penwoem.h>
  41. #include "main.h"
  42. #include "penapp.h"
  43. #include "penres.h"
  44.  
  45.  
  46. /******** Module Variables *********/
  47.  
  48. char     szResult[cchMax]  = {0};   /* Recognized string */
  49. SYV      syvGlobal   = SYV_NULL;    /* Recognized symbol value */
  50. WORD     wLineStyle;                /* Line style of the shape */
  51. RECT     shapeRect;                 /* Bounding rectangle of the shape */
  52. int      miRecMode   = miSample;    /* Menu ID of current recognizer */
  53. BOOL     fSaveData   = TRUE;        /* Save data flag    */
  54. HREC     hrecCur     = (HREC)RC_WDEFAULT; /* Current recognizer handle */
  55. HPENDATA hpendata;                  /* Most recent raw data saved */
  56. HWND     hwndMain;                  /* Window handles */
  57. HWND     hwndInput;
  58. HWND     hwndRaw;
  59. HWND     hwndInfo;
  60.  
  61.  
  62.  
  63. /******** Code *********/
  64.  
  65.  
  66. /*----------------------------------------------------------
  67. Purpose: Main Windows function
  68. Returns: Exit code
  69. */
  70. int PASCAL WinMain(
  71.    HANDLE hInstance,       /* Instance handle  */
  72.    HANDLE hPrevInstance,   /* Previous instance handle */
  73.    LPSTR lpszCommandLine,  /* Command line string */
  74.    int cmdShow)            /* ShowWindow flag */
  75.    {
  76.    MSG   msg;
  77.  
  78.    Unused(lpszCommandLine);
  79.  
  80.    if (!hPrevInstance)
  81.       {
  82.       if (!FInitApp(hInstance))
  83.          {
  84.          return 1;
  85.          }
  86.       }
  87.  
  88.    if (FInitInstance(hInstance, hPrevInstance, cmdShow))
  89.       {
  90.       while (GetMessage((LPMSG)&msg,NULL,0,0) )
  91.          {
  92.          TranslateMessage((LPMSG)&msg);
  93.          DispatchMessage((LPMSG)&msg);
  94.          }
  95.       }
  96.    else
  97.       msg.wParam = 0;
  98.  
  99.    return msg.wParam;
  100.    }
  101.  
  102.  
  103. /*----------------------------------------------------------
  104. Purpose: Window procedure for main sample window.
  105. Returns: Varies
  106. */
  107. LRESULT CALLBACK __export MainWndProc(
  108.    HWND hwnd,        /* Window handle */
  109.    UINT message,     /* Message */
  110.    WPARAM wParam,    /* Varies */
  111.    LPARAM lParam)    /* Varies */
  112.    {
  113.    LONG  lRet  = 0L;
  114.    RC    rc;
  115.    BOOL (FAR PASCAL *lpfnConfig) (WORD, WORD, LONG);
  116.  
  117.    switch (message)
  118.       {
  119.       case WM_COMMAND:
  120.          switch (wParam)
  121.             {
  122.             case miExit:
  123.                DestroyWindow(hwndMain);
  124.                break;
  125.  
  126.             case miSample:
  127.             case miShape:
  128.             case miSystem:
  129.                SetGraphWindow(wParam);
  130.                break;
  131.  
  132.             case miSaveData:
  133.                {
  134.                HMENU hmenu = GetMenu(hwnd);
  135.  
  136.                CheckMenuItem(hmenu, miSaveData,
  137.                   (fSaveData = !fSaveData) ? MF_CHECKED : MF_UNCHECKED);
  138.                break;
  139.                }
  140.  
  141.             default:
  142.                break;
  143.             }
  144.          break;
  145.  
  146.       case WM_SIZE:
  147.          {
  148.          int x;
  149.          int y;
  150.          int dx;
  151.          int dy;
  152.  
  153.          x = XInputWnd(LOWORD(lParam));
  154.          y = YInputWnd(0);
  155.          dx = DxInputWnd(LOWORD(lParam));
  156.          dy = DyInputWnd(HIWORD(lParam));
  157.          MoveWindow(hwndInput, x, y, dx, dy, TRUE);
  158.  
  159.          x = XRawWnd(0);
  160.          y = YRawWnd(HIWORD(lParam));
  161.          dx = DxRawWnd(LOWORD(lParam));
  162.          dy = DyRawWnd(HIWORD(lParam));
  163.          MoveWindow(hwndRaw, x, y, dx, dy, TRUE);
  164.  
  165.          x = XInfoWnd(0);
  166.          y = YInfoWnd(0);
  167.          dx = DxInfoWnd(LOWORD(lParam));
  168.          dy = DyInfoWnd(HIWORD(lParam));
  169.          MoveWindow(hwndInfo, x, y, dx, dy, TRUE);
  170.          break;
  171.          }
  172.  
  173.       case WM_DESTROY:
  174.          if (hpendata)
  175.             DestroyPenData(hpendata);
  176.  
  177.          /* Unload current recognizer if not System recognizer
  178.          */
  179.          if (hrecCur != RC_WDEFAULT)
  180.             UninstallRecognizer(hrecCur);
  181.  
  182.          PostQuitMessage(0);
  183.          break;
  184.  
  185.       case WM_GLOBALRCCHANGE:
  186.          /* There is really no reason to pass the WM_GLOBALRCCHANGE on to
  187.          ** the Sample Recognizer since it is a private recognizer and
  188.          ** this application knows that the sample recognizer will not
  189.          ** process the message.  But we'll pass it anyway.
  190.          */
  191.          GetGlobalRC ((LPRC)&rc, (LPSTR)NULL, (LPSTR)NULL, NULL);
  192.          if (hrecCur != RC_WDEFAULT &&
  193.         ((FARPROC)lpfnConfig = GetProcAddress(hrecCur, "ConfigRecognizer")) != NULL)
  194.             {
  195.             lRet = (*lpfnConfig) (WCR_RCCHANGE, 0, (LONG) (LPRC) &rc);
  196.             }
  197.          break;
  198.  
  199.       default:
  200.          lRet = DefWindowProc(hwnd, message, wParam, lParam);
  201.          break;
  202.       }
  203.  
  204.    return lRet;
  205.    }
  206.  
  207.  
  208.  
  209. /*----------------------------------------------------------
  210. Purpose: Window procedure for the input child window
  211. Returns: Varies
  212. Comment: This is a template of a typical pen-aware window procedure.
  213.  
  214.          The general interaction with recognition API is:
  215.  
  216.             1) Install specific recognizer using InstallRecognizer
  217.                (this is done in FLoadRec in this sample)
  218.             2) Initialize the RC data structure
  219.             3) At pen input (WM_LBUTTONDOWN), call the recognizer
  220.             3) Retrieve recognized data on WM_RCRESULT message
  221.             4) Unload recognizer using UninstallRecognizer
  222. */
  223. LRESULT CALLBACK __export InputWndProc(
  224.    HWND hwnd,        /* Window handle */
  225.    UINT message,     /* Message */
  226.    WPARAM wParam,    /* Varies */
  227.    LPARAM lParam)    /* Varies */
  228.    {
  229.    LONG  lRet  = 0L;
  230.    RC    rc;
  231.  
  232.    switch (message)
  233.       {
  234.       case WM_LBUTTONDOWN:
  235.  
  236.          /* Two possibilities exist: user is using mouse or the pen.
  237.          ** If it is the pen, the user is starting to write.
  238.          ** Initialize recognition-context for recognizer
  239.          */
  240.          if (IsPenEvent(message, GetMessageExtraInfo()))
  241.             {
  242.             InitRC(hwndInput, &rc);
  243.  
  244.             rc.rglpdf[0] = NULL; /* No dictionary search */
  245.  
  246.             rc.lRcOptions |= RCO_NOPOINTEREVENT;   /* Ignore Tap-n-Hold feature */
  247.             rc.lRcOptions |= fSaveData ? RCO_SAVEALLDATA : 0;
  248.  
  249.             rc.hrec = hrecCur;   /* Set hrec since it might not be the system recognizer */
  250.             if(miRecMode == miSample)
  251.                {
  252.                rc.lPcm |= PCM_PENUP;   /* Set this flag for single strokes */
  253.                }
  254.             else
  255.                rc.lPcm |= PCM_TIMEOUT;
  256.  
  257.             if (Recognize(&rc) == REC_BUSY)
  258.                MessageBox(hwndMain, "Recognizer is busy", szPenAppWnd, MB_OK|MB_ICONEXCLAMATION);
  259.             }
  260.          break;
  261.  
  262.       case WM_RCRESULT:
  263.          {
  264.          LPRECT   lprect;
  265.          LPRCRESULT  lprcresult = (LPRCRESULT)lParam;
  266.  
  267.          /* The recognizer has recognized input and piped it through
  268.          ** lParam (as an LPRCRESULT).
  269.          **
  270.          ** The sample recognizer returns a symbol graph containing codes
  271.          ** indicating the general direction the input stroke is written,
  272.          ** according to the four compass directions.
  273.          **
  274.          ** The shape recognizer returns a symbol graph indicating
  275.          ** the geometric shape of the input (either line, rectangle,
  276.          ** or ellipse).
  277.          **
  278.          ** The standard recognizer returns the recognized string.
  279.          */
  280.          lprect = &lprcresult->rectBoundInk;
  281.  
  282.          if ((int)wParam < 0)       /* Did an error occur? */
  283.             {
  284.             syvGlobal = SYV_NULL;   /* Reset */
  285.             *szResult = NULL;
  286.  
  287.             /* We set the lprect to NULL to invalidate entire input window,
  288.             ** since the error could be overflow, in which case ink could
  289.             ** be outside the given lprect.
  290.             */
  291.  
  292.             lprect = NULL;
  293.             }
  294.          else if (!(lprcresult->wResultsType & rcrtNoResults))
  295.             {
  296.             switch (miRecMode)
  297.                {
  298.                case miSample:
  299.                   syvGlobal = *(lprcresult->lpsyv);   /* Copy symbol value */
  300.                   break;
  301.                case miShape:
  302.                   syvGlobal = *(lprcresult->lpsyv);   /* Copy symbol value */
  303.                   shapeRect = *(LPRECT)(lprcresult->syg.rgpntHotSpots);
  304.                   wLineStyle = (WORD)(lprcresult->syg.lRecogVal);
  305.                   break;
  306.                default:
  307.                   *szResult = NULL;
  308.  
  309.                   /* Set syvGlobal simply to pass test condition in InfoWndProc
  310.                   */
  311.                   syvGlobal = *(lprcresult->lpsyv);
  312.                   SymbolToCharacter(lprcresult->lpsyv, cchMax, szResult, NULL);
  313.                   break;
  314.                }
  315.             CopyRawData(lprcresult);
  316.             }
  317.          else  /* Nothing Recognized */
  318.             {
  319.             syvGlobal = SYV_NULL;
  320.             *szResult = NULL;
  321.             CopyRawData(lprcresult);
  322.             }
  323.  
  324.          InvalidateRect(hwndInfo, NULL, TRUE);
  325.          InvalidateRect(hwndInput, lprect, TRUE);
  326.          InvalidateRect(hwndRaw, NULL, TRUE);
  327.  
  328.          /* Invalidate any topmost windows overlapping our inking rect.
  329.          ** Note we wouldn't have to do this if we used ProcessWriting
  330.          ** (it handles it for us).
  331.          */
  332.          if (lprect != NULL)     /* Recopy if necessary */
  333.             lprect = &lprcresult->rectBoundInk;
  334.          MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)lprect, 2);
  335.          RedrawWindow(GetDesktopWindow(), lprect, NULL,
  336.             RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
  337.          break;
  338.          }
  339.  
  340.       case WM_SYSCOMMAND:
  341.          switch (wParam & 0xFFF0)
  342.             {
  343.             case SC_MOVE:     /* Don't allow window to be moved */
  344.                break;
  345.  
  346.             default:
  347.                DefWindowProc(hwnd, message, wParam, lParam);
  348.                break;
  349.             }
  350.          break;
  351.  
  352.       case WM_PAINT:
  353.          {
  354.          HDC         hdc;
  355.          PAINTSTRUCT ps;
  356.  
  357.          hdc = BeginPaint(hwnd, &ps);
  358.          EndPaint(hwnd, &ps);
  359.          break;
  360.          }
  361.  
  362.       default:
  363.          lRet = DefWindowProc(hwnd, message, wParam, lParam);
  364.          break;
  365.       }
  366.  
  367.    return lRet;
  368.    }
  369.  
  370.  
  371.  
  372. /*----------------------------------------------------------
  373. Purpose: Window procedure for the info child window
  374. Returns: Varies
  375. */
  376. LRESULT CALLBACK __export InfoWndProc(
  377.    HWND hwnd,        /* Window handle */
  378.    UINT message,     /* Message */
  379.    WPARAM wParam,    /* Varies */
  380.    LPARAM lParam)    /* Varies */
  381.    {
  382.    LONG        lRet  = 0L;
  383.  
  384.    switch (message)
  385.       {
  386.       case WM_PAINT:
  387.          {
  388.          HPEN     hpen;
  389.          HPEN     hpenSav;
  390.          HBRUSH   hbrushSav;
  391.          HDC      hdc;
  392.          PAINTSTRUCT ps;
  393.          int      iSavBkMode;
  394.  
  395.          hdc = BeginPaint(hwnd, &ps);
  396.          if(syvGlobal != SYV_NULL)
  397.             {
  398.             switch(miRecMode)
  399.                {
  400.                case miSample:
  401.                   hpen = CreatePen(PS_SOLID, 2, GetSysColor(COLOR_WINDOWTEXT));
  402.                   hpenSav = SelectObject(hdc, hpen);
  403.  
  404.                   DrawArrow(hwnd, hdc);
  405.  
  406.                   SelectObject(hdc, hpenSav);
  407.                   DeleteObject(hpen);
  408.                   break;
  409.  
  410.                case miShape:
  411.                   hpen = CreatePen(wLineStyle, 1, GetSysColor(COLOR_WINDOWTEXT));
  412.                   hpenSav = SelectObject(hdc, hpen);
  413.  
  414.                   hbrushSav = SelectObject(hdc, GetStockObject(NULL_BRUSH));
  415.                   iSavBkMode = SetBkMode(hdc, TRANSPARENT);
  416.  
  417.                   DrawShape(hwnd, hdc);
  418.  
  419.                   SetBkMode(hdc, iSavBkMode);
  420.                   SelectObject(hdc, hbrushSav);
  421.                   SelectObject(hdc, hpenSav);
  422.                   DeleteObject(hpen);
  423.                   break;
  424.  
  425.                default:
  426.                   SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  427.                   SetBkMode(hdc, TRANSPARENT);
  428.  
  429.                   TextOut(hdc, 1, 1, szResult, strlen(szResult));
  430.                   break;
  431.                }
  432.             }
  433.          EndPaint(hwnd, &ps);
  434.          break;
  435.          }
  436.  
  437.       case WM_SYSCOMMAND:
  438.          switch (wParam & 0xFFF0)
  439.             {
  440.             case SC_MOVE:        /* Don't allow window to be moved */
  441.                break;
  442.  
  443.             default:
  444.                DefWindowProc(hwnd, message, wParam, lParam);
  445.                break;
  446.             }
  447.          break;
  448.  
  449.       default:
  450.          lRet = DefWindowProc(hwnd, message, wParam, lParam);
  451.          break;
  452.       }
  453.  
  454.    return lRet;
  455.    }
  456.  
  457.  
  458. /*----------------------------------------------------------
  459. Purpose: Window procedure for the raw child window
  460. Returns: Varies
  461. */
  462. LRESULT CALLBACK __export RawWndProc(
  463.    HWND hwnd,        /* Window handle */
  464.    UINT message,     /* Message */
  465.    WPARAM wParam,    /* Varies */
  466.    LPARAM lParam)    /* Varies */
  467.    {
  468.    LONG        lRet  = 0L;
  469.  
  470.    switch (message)
  471.       {
  472.       case WM_PAINT:
  473.          {
  474.          HDC         hdc;
  475.          PAINTSTRUCT ps;
  476.  
  477.          hdc = BeginPaint(hwnd, &ps);
  478.          DrawRawData(hdc);
  479.          EndPaint(hwnd, &ps);
  480.          break;
  481.          }
  482.  
  483.       case WM_SYSCOMMAND:
  484.          switch (wParam & 0xFFF0)
  485.             {
  486.             case SC_MOVE:        /* Don't allow window to be moved */
  487.                break;
  488.  
  489.             default:
  490.                DefWindowProc(hwnd, message, wParam, lParam);
  491.                break;
  492.             }
  493.          break;
  494.  
  495.       default:
  496.          lRet = DefWindowProc(hwnd, message, wParam, lParam);
  497.          break;
  498.       }
  499.  
  500.    return lRet;
  501.    }
  502.  
  503.  
  504. /*----------------------------------------------------------
  505. Purpose: Initialize application data and register window classes
  506. Returns: TRUE if all successful
  507. Comment: There are four window classes: the main application window,
  508.          and three child windows for: input, information display, and
  509.          raw data display.
  510.  
  511.          The input window is the area in which handwriting is received.
  512.          The raw data window outputs the raw input data.  The info window
  513.          outputs the data of the recognized input.
  514. */
  515. BOOL FInitApp(HANDLE hInstance)     /* Instance handle */
  516.    {
  517.    WNDCLASS wc;
  518.    HCURSOR  hcursor;
  519.  
  520.    hcursor = LoadCursor(NULL, IDC_ARROW);
  521.  
  522.    /* Register Pen App window class
  523.    */
  524.    wc.hCursor = hcursor;
  525.    wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(iconPenApp));
  526.    wc.lpszMenuName = MAKEINTRESOURCE(menuPenApp);
  527.    wc.lpszClassName = (LPSTR)szPenAppClass ;
  528.    wc.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE+1;
  529.    wc.hInstance = hInstance;
  530.    wc.style = CS_VREDRAW | CS_HREDRAW ;
  531.    wc.lpfnWndProc = MainWndProc;
  532.    wc.cbClsExtra = 0;
  533.    wc.cbWndExtra = 0;
  534.  
  535.    if (!RegisterClass((LPWNDCLASS) &wc))
  536.       return FALSE;
  537.  
  538.  
  539.    /* Register Pen App child window classes
  540.    */
  541.    wc.hCursor = LoadCursor(NULL, IDC_PEN);
  542.    wc.hIcon = NULL;
  543.    wc.lpszMenuName = NULL;
  544.    wc.lpszClassName = (LPSTR)szPenAppInputClass;
  545.    wc.hbrBackground = (HBRUSH)COLOR_WINDOW+1;
  546.    wc.style = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS;
  547.    wc.lpfnWndProc = InputWndProc;
  548.    if (!RegisterClass((LPWNDCLASS) &wc))
  549.       return FALSE;
  550.  
  551.    wc.hCursor = hcursor;
  552.    wc.lpszClassName = (LPSTR)szPenAppInfoClass;
  553.    wc.lpfnWndProc = InfoWndProc;
  554.    if (!RegisterClass((LPWNDCLASS) &wc))
  555.       return FALSE;
  556.  
  557.    wc.lpszClassName = (LPSTR)szPenAppRawClass;
  558.    wc.lpfnWndProc = RawWndProc;
  559.    wc.hbrBackground = (HBRUSH)COLOR_WINDOW+1;
  560.    if (!RegisterClass((LPWNDCLASS) &wc))
  561.       return FALSE;
  562.    }
  563.  
  564.  
  565. /*----------------------------------------------------------
  566. Purpose: Initialize data structures; create windows; load recognizer.
  567. Returns: TRUE if all successful
  568. */
  569. BOOL FInitInstance(
  570.    HANDLE hInstance,       /* Instance handle */
  571.    HANDLE hPrevInstance,   /* Previous instance handle */
  572.    int cmdShow)            /* ShowWindow flag */
  573.    {
  574.    int      cxScreen = GetSystemMetrics(SM_CXSCREEN);
  575.    int      cyScreen = GetSystemMetrics(SM_CYSCREEN);
  576.    RECT  rect;
  577.  
  578.    Unused(hPrevInstance);
  579.  
  580.    /* Create Main window
  581.    */
  582.    hwndMain = CreateWindow((LPSTR)szPenAppClass,
  583.          (LPSTR)szPenAppWnd,
  584.          WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
  585.          0, 0, cxScreen, cyScreen,
  586.          (HWND)NULL,
  587.          (HWND)NULL,
  588.          (HANDLE)hInstance,
  589.          (LPSTR)NULL
  590.          );
  591.  
  592.    if (!hwndMain)
  593.       {
  594.       return FALSE;
  595.       }
  596.  
  597.  
  598.    /* Create Input window
  599.    */
  600.    GetClientRect(hwndMain, &rect);
  601.  
  602.    hwndInput = CreateWindow((LPSTR)szPenAppInputClass,
  603.          (LPSTR)szInputWnd,
  604.          WS_CHILD | WS_BORDER | WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS,
  605.          XInputWnd(rect.right), YInputWnd(0), DxInputWnd(rect.right), DyInputWnd(rect.bottom),
  606.          hwndMain,
  607.          NULL,
  608.          (HANDLE)hInstance,
  609.          (LPSTR)NULL
  610.          );
  611.  
  612.    if (!hwndInput)
  613.       {
  614.       return FALSE;
  615.       }
  616.  
  617.  
  618.    /* Create Raw Data window
  619.    */
  620.    hwndRaw = CreateWindow((LPSTR)szPenAppRawClass,
  621.          (LPSTR)szRawWnd,
  622.          WS_CHILD | WS_BORDER | WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS,
  623.          XRawWnd(0), YRawWnd(rect.bottom),
  624.          DxRawWnd(rect.right), DyRawWnd(rect.bottom),
  625.          hwndMain,
  626.          NULL,
  627.          (HANDLE)hInstance,
  628.          (LPSTR)NULL
  629.          );
  630.  
  631.    if (!hwndRaw)
  632.       {
  633.       return FALSE;
  634.       }
  635.  
  636.  
  637.    /* Create Info window
  638.    */
  639.    hwndInfo = CreateWindow((LPSTR)szPenAppInfoClass,
  640.          (LPSTR)szInfoWnd,
  641.          WS_CHILD | WS_BORDER | WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS,
  642.          XInfoWnd(0), YInfoWnd(0),
  643.          DxInfoWnd(rect.right), DyInfoWnd(rect.bottom),
  644.          hwndMain,
  645.          NULL,
  646.          (HANDLE)hInstance,
  647.          (LPSTR)NULL
  648.          );
  649.  
  650.    if (!hwndInfo)
  651.       {
  652.       return FALSE;
  653.       }
  654.  
  655.    ShowWindow(hwndMain, cmdShow);
  656.    UpdateWindow(hwndMain);
  657.  
  658.    return FLoadRec();      /* Load the recognizer  */
  659.    }
  660.  
  661.  
  662. /*----------------------------------------------------------
  663. Purpose: Install a recognizer, based upon the value of miRecMode
  664. Returns: TRUE if successful
  665. */
  666. BOOL FLoadRec(VOID)
  667.    {
  668.    LPSTR lpRecogName;
  669.    HCURSOR hsave;
  670.  
  671.    /* Note that hrecCur == RC_WDEFAULT at start of program
  672.    */
  673.    if (hrecCur != RC_WDEFAULT)
  674.       {
  675.       UninstallRecognizer(hrecCur); /* Unload any current recognizer */
  676.       }
  677.  
  678.    /* Install appropriate recognizer DLL
  679.    */
  680.    switch(miRecMode)
  681.       {
  682.       case miSample:       /* Sample recognizer */
  683.          lpRecogName = (LPSTR)szSampleRec;
  684.          break;
  685.       case miShape:        /* Shape recognizer */
  686.          lpRecogName = (LPSTR)szShapeRec;
  687.          break;
  688.       default:             /* System recognizer */
  689.          /* The system recognizer is always loaded, so we just set
  690.          ** our internal variables and return.
  691.          */
  692.          lpRecogName = NULL;
  693.          hrecCur = RC_WDEFAULT;
  694.          return TRUE;      /* Don't need to load the System recognizer */
  695.       }
  696.    hsave = SetCursor(LoadCursor(NULL, IDC_WAIT));
  697.    hrecCur = InstallRecognizer(lpRecogName);
  698.    SetCursor(hsave);
  699.  
  700.    if (!hrecCur)
  701.       {
  702.       MessageBox(hwndMain, "Could not install recognizer", szPenAppWnd, MB_OK);
  703.       return FALSE;
  704.       }
  705.  
  706.    return TRUE;
  707.    }
  708.  
  709.  
  710. /*----------------------------------------------------------
  711. Purpose: Duplicate the pen data buffer
  712. Returns: --
  713. */
  714. VOID CopyRawData(LPRCRESULT lprcresult)   /* Ptr to RCRESULT struct */
  715.    {
  716.    if (hpendata != NULL)         /* Destroy old buffer */
  717.       DestroyPenData(hpendata);
  718.  
  719.    /* Allocate new buffer for data points
  720.    */
  721.    if ((hpendata = DuplicatePenData(lprcresult->hpendata, 0)) == NULL)
  722.       {
  723.       MessageBox(hwndMain, "Insufficient memory", szPenAppWnd, MB_ICONEXCLAMATION | MB_OK);
  724.       *szResult = NULL;
  725.       }
  726.    }
  727.  
  728.  
  729. /*----------------------------------------------------------
  730. Purpose: Draw an arrow in the direction of the endpoint line
  731. Returns: --
  732. Comment: Direction is specified in szResult, and are one of the four
  733.          compass directions.
  734. */
  735. VOID DrawArrow(
  736.    HWND hwnd,     /* Window handle */
  737.    HDC hdc)       /* DC handle */
  738.    {
  739.    RECT  rect;
  740.    int      xEnd;
  741.    int      yEnd;
  742.    int      xArrow[2];
  743.    int      yArrow[2];
  744.  
  745.    GetClientRect(hwnd, &rect);
  746.    SetMapMode(hdc, MM_ISOTROPIC);
  747.  
  748.    SetWindowExt(hdc, 100, 100);
  749.    SetViewportExt(hdc, rect.right/2, rect.bottom/2);
  750.    SetViewportOrg(hdc, rect.right/2, rect.bottom/2);
  751.  
  752.    /* Draw arrow
  753.    */
  754.    switch ((int)syvGlobal)
  755.       {
  756.       case (int)syvEast:
  757.          xEnd = dwLength;
  758.          yEnd = 0;
  759.          xArrow[0] = xEnd-dxArrow;
  760.          yArrow[0] = -dyArrow;
  761.          xArrow[1] = xEnd-dxArrow;
  762.          yArrow[1] = dyArrow;
  763.          break;
  764.       case (int)syvSouth:
  765.          xEnd = 0;
  766.          yEnd = dwLength;
  767.          xArrow[0] = dyArrow;
  768.          yArrow[0] = yEnd-dxArrow;
  769.          xArrow[1] = -dyArrow;
  770.          yArrow[1] = yEnd-dxArrow;
  771.          break;
  772.       case (int)syvWest:
  773.          xEnd = -dwLength;
  774.          yEnd = 0;
  775.          xArrow[0] = xEnd+dxArrow;
  776.          yArrow[0] = -dyArrow;
  777.          xArrow[1] = xEnd+dxArrow;
  778.          yArrow[1] = dyArrow;
  779.          break;
  780.       case (int)syvNorth:
  781.          xEnd = 0;
  782.          yEnd = -dwLength;
  783.          xArrow[0] = dyArrow;
  784.          yArrow[0] = yEnd+dxArrow;
  785.          xArrow[1] = -dyArrow;
  786.          yArrow[1] = yEnd+dxArrow;
  787.          break;
  788.       case (int)syvDot:
  789.          Ellipse(hdc, -dwLength/10, -dwLength/10, dwLength/10, dwLength/10);
  790.          return;
  791.       default:
  792.          return;
  793.       }
  794.    MoveTo(hdc, 0, 0);
  795.    LineTo(hdc, xEnd, yEnd);
  796.    LineTo(hdc, xArrow[0], yArrow[0]);
  797.    MoveTo(hdc, xEnd, yEnd);
  798.    LineTo(hdc, xArrow[1], yArrow[1]);
  799.    }
  800.  
  801.  
  802. /*----------------------------------------------------------
  803. Purpose: Draw a "clean" version of a shape
  804. Returns: --
  805. Comment: Shape is specified in syvGlobal
  806. */
  807. VOID DrawShape(
  808.    HWND hwnd,     /* Window handle */
  809.    HDC hdc)       /* DC handle */
  810.    {
  811.    RECT rect;
  812.    RECT rectWnd;
  813.    RECT rectT;
  814.  
  815.    rectT = shapeRect;
  816.  
  817.    /* Determine mapping region
  818.    */
  819.    TPtoDP((LPPOINT)&rectT, 2);
  820.    MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&rectT, 2);
  821.    GetClientRect(hwnd, &rectWnd);
  822.  
  823.    /* Set Mapping to fit shape into window
  824.    */
  825.    rect = rectT;
  826.    if (rect.top > rect.bottom)
  827.       {
  828.       rect.top = rectT.bottom;
  829.       rect.bottom = rectT.top;
  830.       }
  831.  
  832.    if (rect.right-rect.left > rectWnd.right-2*cBorder ||
  833.        rect.bottom-rect.top > rectWnd.bottom-2*cBorder)
  834.       {
  835.       SetMapMode(hdc, MM_ISOTROPIC);
  836.       SetWindowExt(hdc, rect.right-rect.left, rect.bottom-rect.top);
  837.       SetViewportExt(hdc, rectWnd.right-2*cBorder, rectWnd.bottom-2*cBorder);
  838.       SetWindowOrg(hdc, rect.left, rect.top);
  839.       SetViewportOrg(hdc, cBorder, cBorder);
  840.       }
  841.    else
  842.       OffsetRect(&rectT
  843.                , -(rectT.left+rectT.right)/2+(rectWnd.right - rectWnd.left)/2
  844.                , -(rectT.top+rectT.bottom)/2+(rectWnd.bottom - rectWnd.top)/2);
  845.  
  846.    /* Draw "clean" shape
  847.    */
  848.    switch((int)syvGlobal)
  849.       {
  850.       case (int)SYV_SHAPELINE:
  851.          MoveTo(hdc, rectT.left, rectT.top);
  852.          LineTo(hdc, rectT.right, rectT.bottom);
  853.          break;
  854.       case (int)SYV_SHAPERECT:
  855.          Rectangle(hdc  , rectT.left
  856.                         , rectT.top
  857.                         , rectT.right
  858.                         , rectT.bottom);
  859.          break;
  860.       case (int)SYV_SHAPEELLIPSE:
  861.          Ellipse(hdc , rectT.left
  862.                      , rectT.top
  863.                      , rectT.right
  864.                      , rectT.bottom);
  865.          break;
  866.       }
  867.    }
  868.  
  869.  
  870. /*----------------------------------------------------------
  871. Purpose: Draw the actual ink taken by the recognizer
  872. Returns:
  873. Comment: We demonstrate two techniques.  One uses the DrawPenData
  874.          API and the other enumerates through the penstrokes to
  875.          draw the image.
  876.  
  877.          We use DrawPenData for straight-forward writing/drawing
  878.          (when the Save All Data menuitem is not checked).
  879.  
  880.          We enumerate so we can also ink the upstrokes (pen
  881.          movements when pen is NOT in contact with the tablet).
  882.          We do this when the Save All Data menuitem is checked.
  883. */
  884. VOID DrawRawData(HDC hdc)     /* DC handle */
  885.    {
  886.    PENDATAHEADER pendataheader;
  887.    RECT     rectWnd;
  888.    int      nWidth;
  889.  
  890.    GetClientRect(hwndRaw, &rectWnd);
  891.    if (hpendata == NULL || rectWnd.right <= 3*cBorder ||
  892.       rectWnd.bottom <= 3*cBorder)
  893.       {
  894.       return;     /* Bad handle or window is too small */
  895.       }
  896.    if ( !GetPenDataInfo(hpendata, &pendataheader, NULL, 0) )
  897.       {
  898.       return;
  899.       }
  900.    nWidth = NSetRawExtents(hdc, &pendataheader, &rectWnd);
  901.  
  902.    /* Draw the pen strokes
  903.    */
  904.    if (fSaveData)
  905.       {
  906.       EnumerateStrokes(hdc, &rectWnd, nWidth);
  907.       }
  908.    else
  909.       {
  910.       HPEN  hpenOld;
  911.  
  912.       hpenOld = SelectObject(hdc, CreatePen(PS_SOLID, nWidth, pendataheader.rgbInk));
  913.  
  914.       DrawPenData(hdc, NULL, hpendata);
  915.  
  916.       DeleteObject(SelectObject(hdc, hpenOld));
  917.       }
  918.    }
  919.  
  920.  
  921.  
  922. /*----------------------------------------------------------
  923. Purpose: Set the window extents for the given DC handle
  924. Returns: Width of ink to use when redrawing
  925. */
  926. int NSetRawExtents(
  927.    HDC hdc,                /* DC handle */
  928.    LPPENDATAHEADER lppndt, /* Ptr to PENDATAHEADER struct */
  929.    LPRECT lprectWnd)       /* Ptr to rectangle of window */
  930.    {
  931.    RECT     rectDP;
  932.    LPRECT   lprect = &lppndt->rectBound;     /* In tablet coordinates */
  933.    int      nWidth;
  934.  
  935.    /* Set mapping to fit raw data into window
  936.    */
  937.    SetMapMode(hdc, MM_ISOTROPIC);
  938.  
  939.    /* Window extents are the tablet-coord dimensions of drawing
  940.    */
  941.    SetWindowExt(hdc, lprect->right-lprect->left, lprect->bottom-lprect->top);
  942.  
  943.    rectDP = *lprect;
  944.    TPtoDP((LPPOINT)&rectDP,2);
  945.  
  946.    /* Now set viewport extents.  Check for special case when rectDP
  947.    ** is empty (otherwise GDI won't display anything)
  948.    */
  949.    if (IsRectEmpty(&rectDP))
  950.       {
  951.       SetViewportExt(hdc, lprect->right-lprect->left, lprect->bottom-lprect->top);
  952.       nWidth = lppndt->nInkWidth;
  953.       }
  954.    else
  955.       {
  956.       if (rectDP.right-rectDP.left > lprectWnd->right-2*cBorder ||
  957.          rectDP.bottom-rectDP.top > lprectWnd->bottom-2*cBorder)
  958.          {
  959.          SetViewportExt(hdc, lprectWnd->right-2*cBorder, lprectWnd->bottom - 2*cBorder);
  960.          }
  961.       else     /* Drawing is smaller than raw window */
  962.          {
  963.          SetViewportExt(hdc, rectDP.right-rectDP.left, rectDP.bottom-rectDP.top);
  964.          }
  965.  
  966.       /* Convert ink width to logical coordinates (tablet coordinates)
  967.       */
  968.       GetLPWidth(hdc, lppndt->nInkWidth, &nWidth);
  969.       }
  970.  
  971.    SetWindowOrg(hdc, lprect->left, lprect->top);
  972.    SetViewportOrg(hdc, cBorder, cBorder);
  973.    return nWidth;
  974.    }
  975.  
  976.  
  977. /*----------------------------------------------------------
  978. Purpose: Enumerate and draw each stroke
  979. Returns: --
  980. Comment: We enumerate and draw separate strokes so we can ink
  981.          the upstrokes (the pen movements when pen is NOT in contact
  982.          with the tablet).  We do this when the Save All Data
  983.          menu-item is checked.
  984. */
  985. VOID EnumerateStrokes(
  986.    HDC hdc,             /* DC handle */
  987.    LPRECT lprectWnd,    /* Ptr to rectangle of window */
  988.    int nWidth)          /* Ink width */
  989.    {
  990.    LPPENDATA   lppndt;
  991.    LPPOINT  lppoint;
  992.    WORD     iStroke;
  993.    STROKEINFO  si;
  994.    HPEN     hpenDown;
  995.    HPEN     hpenUp;
  996.    HPEN     hpenSav;
  997.  
  998.    /* If the RCO_SAVEALLDATA bit is set in the lRcOptions field in the
  999.    ** RC structure the recognizer saves all the pen data. If the bit is
  1000.    ** masked out, only data used by the recognizer is saved; this could
  1001.    ** include upstrokes.  Upstrokes are strokes made while the pen is
  1002.    ** not in contact with the tablet.
  1003.    **
  1004.    ** We ink the downstrokes in the ink color and the upstrokes in red.
  1005.    ** (Note that a red window background will make these invisible).
  1006.    */
  1007.  
  1008.    if ((lppndt = BeginEnumStrokes(hpendata)) == NULL)
  1009.       return;
  1010.  
  1011.    hpenUp = CreatePen(PS_SOLID, nWidth, rgbRed);
  1012.    hpenDown = CreatePen(PS_SOLID, nWidth, lppndt->rgbInk);
  1013.    hpenSav = SelectObject(hdc, hpenDown);
  1014.  
  1015.    for (iStroke = 0; iStroke < (WORD)lppndt->cStrokes; iStroke++)
  1016.       {
  1017.       GetPenDataStroke(lppndt, iStroke, &lppoint, NULL, &si);
  1018.  
  1019.       SelectObject(hdc, si.wPdk & PDK_DOWN ? hpenDown : hpenUp);
  1020.  
  1021.       /* Polyline requires 2 or more points. If the stroke consists
  1022.       ** of only one point use MoveTo and LineTo to draw the point.
  1023.       */
  1024.       if (si.cPnt < 2)
  1025.          {
  1026.          MoveTo(hdc, (*lppoint).x, (*lppoint).y);
  1027.          LineTo(hdc, (*lppoint).x+1, (*lppoint).y+1);
  1028.          }
  1029.       else
  1030.          Polyline(hdc, lppoint, si.cPnt);
  1031.       }
  1032.  
  1033.    SelectObject(hdc, hpenSav);
  1034.    DeleteObject(hpenUp);
  1035.    DeleteObject(hpenDown);
  1036.  
  1037.    EndEnumStrokes(hpendata);
  1038.    }
  1039.  
  1040.  
  1041. /*----------------------------------------------------------
  1042. Purpose: Set the graph window and (re)install appropriate
  1043.          recognizer
  1044. Returns: --
  1045. */
  1046. VOID SetGraphWindow(int mi)      /* Menu ID of recognizer to switch to */
  1047.    {
  1048.    HMENU hmenu;
  1049.  
  1050.    if (mi == miRecMode)    /* Stay the same? */
  1051.       return;
  1052.  
  1053.    hmenu = GetMenu(hwndMain);
  1054.  
  1055.    CheckMenuItem(hmenu, miRecMode, MF_UNCHECKED);
  1056.    miRecMode = mi;
  1057.    CheckMenuItem(hmenu, mi, MF_CHECKED);
  1058.  
  1059.    FLoadRec();
  1060.    syvGlobal = SYV_NULL;   /* Reset window globals */
  1061.    if (hpendata)
  1062.       DestroyPenData(hpendata);
  1063.    hpendata = NULL;
  1064.  
  1065.    InvalidateRect(hwndInput, NULL, TRUE);
  1066.    InvalidateRect(hwndRaw, NULL, TRUE);
  1067.    InvalidateRect(hwndInfo, NULL, TRUE);
  1068.    }
  1069.