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

  1. /************************************************************
  2.  
  3.    PROGRAM: SREC.C
  4.  
  5.    PURPOSE: Generic template for a custom recognizer DLL.
  6.  
  7.    COMMENTS:
  8.  
  9.       This code is a skeleton program containing all necessary
  10.       functionality for a simple recognizer.  The recognizer is
  11.       a DLL loaded at runtime by the pen-aware application.
  12.       This particular recognizer is used by the PENAPP sample
  13.       application.
  14.  
  15.       This sample recognizer inputs a single stroke of data points.
  16.       Taking the beginning and ending points of the stroke, SREC
  17.       calculates the nearest compass direction of the line formed
  18.       by these endpoints.
  19.  
  20.       SREC then fills out the symbol graph (passed through the
  21.       lParam structure of the application's window procedure on
  22.       the WM_RCRESULT message) using the following special codes:
  23.  
  24.          Value       Direction
  25.          -------     -----------
  26.          syvEast     right
  27.          syvSouth    down
  28.          syvWest     left
  29.          syvNorth    up
  30.          syvDot      point
  31.  
  32.       Application Requirements:
  33.  
  34.          Any application choosing to use this recognizer (SREC) must
  35.          set the following RC struct item:
  36.  
  37.          1) lPcm = PCM_PENUP | any other flags.
  38.  
  39.  
  40.    RULES FOR ALL RECOGNIZERS:
  41.  
  42.       All recognizers must take heed to the following structure
  43.       items in the RC structure:
  44.  
  45.          Required RC struct items:
  46.  
  47.             1) lRcOptions...     RCO_SAVEEXTRADATA
  48.  
  49.             2) wTimeOut
  50.  
  51.       The following struct items may be ignored:
  52.  
  53.          Optional RC struct items:
  54.  
  55.             1) lRcOptions...  RCO_SINGLE (recognizer specific)
  56.  
  57.             2) GUIDE
  58.  
  59.             3) wRcOrient (recognizer specific, only required for orientation
  60.                dependent glyphs)
  61.  
  62.             4) wRcDirect
  63.  
  64.             5) wRcPreferences
  65.  
  66. ************************************************************/
  67.  
  68. #define NOCOMM
  69. #include <windows.h>
  70. #define  DEFPENMOD      /* for PENINFO struct */
  71. #include <penwin.h>
  72. #include <penwoem.h>
  73. #include "main.h"
  74.  
  75. /******** Prototypes *********/
  76.  
  77. REC DoRecognition (LPRC lprc, HPENDATA hpendata, LPRCRESULT lprcresult);
  78. VOID CalcNearestDirection (LPPOINT lppointEnds);
  79. LPSTR lstrncpy (LPSTR lpszA, LPSTR lpszB, int cch);
  80. WORD FAR PASCAL __export WEP(int);
  81. REC WINAPI __export RecognizeInternal(LPRC, LPFUNCRESULTS);
  82. REC WINAPI RecognizeDataInternal(LPRC,HPENDATA,LPFUNCRESULTS);
  83. UINT WINAPI __export ConfigRecognizer(UINT,WPARAM,LPARAM); 
  84. BOOL WINAPI __export InitRecognizer(LPRC); 
  85. BOOL WINAPI __export InitRecognizer(LPRC); 
  86. BOOL WINAPI __export TrainInkInternal(LPRC,HPENDATA,LPSYV);
  87. BOOL WINAPI __export TrainContextInternal(LPRCRESULT,LPSYE,int,LPSYC,int);
  88.  
  89.  
  90. /******** Macros *********/
  91.  
  92. #define  ABS(n)   ((n) < 0 ? -(n) : n)
  93.  
  94. /******** Constants *********/
  95.  
  96. #define cpntMax   128      /* Max count of points for point buffer */
  97.  
  98. #define szID   "US Compass direction, single-stroke"
  99. #define szMsg1 "This application requires Standard or Enhanced Mode Windows."
  100.  
  101. /******** Module Variables *********/
  102.  
  103. static SYE  syeGlobal;
  104.  
  105.  
  106. /******** Code *********/
  107.  
  108. /*----------------------------------------------------------
  109. Purpose: Main DLL function
  110. Returns: TRUE
  111. */
  112. int FAR PASCAL LibMain(
  113.    HANDLE hinst,        // Instance handle
  114.    WORD wDataSeg,       // Data segment
  115.    WORD cbHeapSize,     // Size of heap
  116.    LPSTR lpszCmdLine)   // Command line
  117.    {
  118.    Unused(hinst);
  119.    Unused(wDataSeg);
  120.    Unused(lpszCmdLine);
  121.  
  122.    if (cbHeapSize != 0)
  123.       {
  124.       UnlockData(0);
  125.       }
  126.  
  127.    return TRUE;
  128.    }
  129.  
  130.  
  131. /*----------------------------------------------------------
  132. Purpose: DLL termination function
  133. Returns: 1
  134. */
  135. WORD FAR PASCAL __export WEP(int nParam)
  136.    {
  137.    Unused(nParam);
  138.  
  139.    return 1;
  140.    }
  141.  
  142.  
  143. /*----------------------------------------------------------
  144. Purpose: Initializes recognizer
  145. Returns: TRUE on success, FAIL on failure
  146. Comment: DLL receives this call when an application calls
  147.          InstallRecognizer.
  148. */
  149. BOOL WINAPI __export InitRecognizer(LPRC lprc)     /* Ptr to RC struct */
  150.    {
  151.    Unused(lprc);
  152.  
  153.    /* We don't do any initializing for this recognizer.  But if we
  154.    ** wanted to, we would do it here.
  155.    */
  156.    return TRUE;
  157.    }
  158.  
  159.  
  160. /*----------------------------------------------------------
  161. Purpose: Perform final unloading of recognizer
  162. Returns: --
  163. Cond:    DLL receives this call when an application calls
  164.          UninstallRecognizer.
  165. */
  166. VOID WINAPI __export CloseRecognizer(VOID)
  167.    {
  168.    /* We don't do anything for this recognizer.  But if we
  169.    ** wanted to, we would do it here.
  170.    */
  171.    return;
  172.    }
  173.  
  174.  
  175. /*----------------------------------------------------------
  176. Purpose: Configure recognizer for special options.
  177. Returns:
  178. Cond:    DLL receives this call when the Control Panel or
  179.          application makes a change to the recognizer
  180.          configuration.
  181.  
  182.          This recognizer provides no custom configuration
  183.          other than returning the identification string.
  184. */
  185. UINT WINAPI __export ConfigRecognizer(
  186.    UINT wConfig,     /* Configuration subfunction */
  187.    WPARAM wParam,    /* Varies */
  188.    LPARAM lParam)    /* Varies */
  189.    {
  190.    WORD  wRet = TRUE;
  191.  
  192.    Unused(wParam);
  193.  
  194.    switch (wConfig)
  195.       {
  196.       case WCR_CONFIGDIALOG:
  197.          break;
  198.  
  199.       case WCR_RCCHANGE:
  200.          break;
  201.  
  202.       case WCR_RECOGNAME:
  203.          lstrncpy((LPSTR)lParam, szID, wParam);
  204.          break;
  205.  
  206.       case WCR_TRAIN:
  207.          wRet = TRAIN_NONE;      /* Does not support training */
  208.          break;
  209.  
  210.       case WCR_DEFAULT:          /* Incapable of being system default */
  211.       case WCR_QUERY:            /* Does not support configuration dialog */
  212.       case WCR_QUERYLANGUAGE:    /* Does not support any language */
  213.       case WCR_TRAINMAX:
  214.       case WCR_TRAINDIRTY:
  215.       case WCR_TRAINCUSTOM:
  216.       case WCR_TRAINSAVE:
  217.          wRet = FALSE;
  218.          break;
  219.  
  220.       case WCR_VERSION:
  221.          wRet = 0x0103;    /* Recognizer version 3.1 */
  222.          break;
  223.       }
  224.    return wRet;
  225.    }
  226.  
  227.  
  228. /*----------------------------------------------------------
  229. Purpose: Perform context-independent training
  230. Returns: TRUE if ink in hpendata can be trained
  231. Cond:    --
  232. */
  233. BOOL WINAPI __export TrainInkInternal(
  234.    LPRC lprc,           /* Ptr to RC struct */
  235.    HPENDATA hpendata,   /* Pendata handle */
  236.    LPSYV lpsyv)         /* Ptr to symbol value buffer */
  237.    {
  238.    Unused(lprc);
  239.    Unused(hpendata);
  240.    Unused(lpsyv);
  241.  
  242.    return FALSE;   /* This recognizer does not support training */
  243.    }
  244.  
  245.  
  246. /*----------------------------------------------------------
  247. Purpose: Perform contextual training
  248. Returns: TRUE if ink can be trained
  249. Cond:    --
  250. */
  251. BOOL WINAPI __export TrainContextInternal(
  252.    LPRCRESULT lprcresult,     /* Ptr to RCRESULT struct */
  253.    LPSYE lpsye,               /* Ptr to symbol elements */
  254.    int csye,                  /* Count of symbol elements */
  255.    LPSYC lpsyc,               /* Ptr to symbol correspondence buffer */
  256.    int csyc)                  /* Count of SYCs */
  257.    {
  258.    Unused(lprcresult);
  259.    Unused(lpsye);
  260.    Unused(csye);
  261.    Unused(lpsyc);
  262.    Unused(csyc);
  263.  
  264.    return FALSE;  /* This recognizer does not support training */
  265.    }
  266.  
  267.  
  268. /*----------------------------------------------------------
  269. Purpose: OEM recognizer function.
  270. Returns: Various
  271. Comment: This function receives pen stroke input through
  272.          RecGetPenData and performs recognition.  Recognition
  273.          results are passed in an RCRESULT struct through
  274.          the lpFuncResults function.
  275.  
  276.          Returns one of several values available for this
  277.          function.  See documentation for more details.
  278.  
  279.          A recognizer has the following general form:
  280.  
  281.          {
  282.          Allocate memory to buffer results and raw data;
  283.  
  284.          while (GetPenHwData(..) == REC_OK)
  285.             {
  286.             Yield sometimes;
  287.             Add points to pendata buffer
  288.             if (overflow)
  289.                {
  290.                EndPenCollection(REC_OOM);
  291.                break;
  292.                }
  293.             if (enough data to recognize)
  294.                {
  295.                Do recognition;
  296.  
  297.                Fill RCRESULT struct;
  298.                Call lpFuncResults(..rcresult..);
  299.                if (lpFuncResults == 0)
  300.                   return (valid value for RecRecognize);
  301.                }
  302.             }
  303.  
  304.          if (still some raw data left)
  305.             {
  306.             Do recognition;
  307.             Fill RCRESULT struct;
  308.             Call lpFuncResults(..rcresult..);
  309.             }
  310.          Free buffer memory;
  311.  
  312.          return (valid value for RecRecognize);
  313.          }
  314.  
  315.          For SREC, this function receives input of data
  316.          points of one stroke and calculates the closest
  317.          compass direction of the stroke.
  318.  
  319.          Note that, unlike a typical recognizer, this
  320.          recognizer collects all data points first before
  321.          calculating nearest compass direction.
  322.  
  323.          Also this recognizer assumes the PCM_PENUP is set.
  324.          Thus no timeout checking is done.
  325. */
  326. REC WINAPI __export RecognizeInternal(
  327.    LPRC lprc,                    /* Ptr to RC struct */
  328.    LPFUNCRESULTS lpFuncResults)  /* Ptr to results function */
  329.    {
  330.    WORD  rgpntOem[cpntMax*MAXOEMDATAWORDS];     /* temporary buffer */
  331.    POINT rgpnt[cpntMax];      /* actual data buffer */
  332.    WORD  cYield   = 0;        /* yield count */
  333.    BOOL  fSaveAll= (lprc->lRcOptions & RCO_SAVEALLDATA) != 0;
  334.    LPVOID  lpvOem = (fSaveAll ? (LPVOID)rgpntOem : (LPVOID)NULL);
  335.    REC      rec = REC_OK;
  336.    HPENDATA hpendata;
  337.    HPENDATA hpendataT = NULL;
  338.    RCRESULT rcresult;
  339.    STROKEINFO si;
  340.  
  341.    if ((lprc->lPcm & PCM_PENUP) == 0)
  342.       {
  343.       /* Did application set the PCM_PENUP as method for
  344.       ** ending recognition?
  345.       */
  346.       return REC_NOPENUP;      /* Recognizer specific error */
  347.       }
  348.  
  349.    /* Allocate OEM data buffer
  350.    */
  351.    if ( (hpendata = CreatePenData(NULL, (fSaveAll ? -1 : 0), PDTS_STANDARDSCALE, GMEM_SHARE)) == NULL)
  352.       return REC_OOM;
  353.  
  354.    /* Data input loop
  355.    */
  356.    while ((rec = GetPenHwData(rgpnt, lpvOem, cpntMax, 0, &si)) == REC_OK)
  357.       {
  358.       if (si.cPnt != 0)
  359.          {
  360.          if ( (hpendataT = AddPointsPenData(hpendata, rgpnt, lpvOem, &si)) == NULL)
  361.             {
  362.             rec = REC_OOM;
  363.             EndPenCollection(REC_OOM);
  364.             break;
  365.             }
  366.          hpendata = hpendataT;
  367.          }
  368.  
  369.       if ((cYield++ % 5) && (lprc->lpfnYield))   /* lpfnYield can be NULL */
  370.          {
  371.          (*lprc->lpfnYield)();       /* Yield */
  372.          }
  373.       }
  374.  
  375.    /* Copy last point.  Note that last point only really counts
  376.    ** if rec == REC_TERMPENUP
  377.    */
  378.    if (hpendataT != NULL && rec == REC_TERMPENUP)
  379.       {
  380.       /* Normal ending of loop above.  Add the pen up stroke
  381.       */
  382.       if ( (hpendata = AddPointsPenData(hpendata, rgpnt, lpvOem, &si)) == NULL)
  383.          rec = REC_OOM;
  384.       }
  385.  
  386.  
  387.    if (rec == REC_TERMPENUP)
  388.       {
  389.       /* Send results back to app
  390.       */
  391.       DoRecognition(lprc, hpendata, &rcresult);
  392.       (*lpFuncResults)((LPRCRESULT) &rcresult, rec);
  393.       }
  394.  
  395.    /* Free up memory used to save data.  If app wanted to save it, they
  396.    ** need to make a copy or set the RCO_SAVEHPENDATA flag.
  397.    */
  398.    if (hpendata != NULL && (lprc->lRcOptions&RCO_SAVEHPENDATA)==0)
  399.       DestroyPenData(hpendata);
  400.  
  401.    return rec;
  402.    }
  403.  
  404.  
  405.  
  406. /*----------------------------------------------------------
  407. Purpose: OEM recognizer function.  This function takes the
  408.          given data points (lppntIn) and performs recognition.
  409.          Also passed is any custom OEM data (lpvOEM).
  410.          Recognition results are passed in an RCRESULT struct
  411.          through the lpFuncResults function.
  412. Returns: REC_NOINPUT if no data or REC_DONE if finished
  413. Comment: For SREC, this function takes the list of data points
  414.          of the single stroke and calculates the closest
  415.          compass direction of the stroke.
  416. */
  417. REC WINAPI RecognizeDataInternal(
  418.    LPRC lprc,                    /* Ptr to RC struct */
  419.    HPENDATA hpendata,            /* Pendata handle */
  420.    LPFUNCRESULTS lpFuncResults)  /* Ptr to results function */
  421.    {
  422.    RCRESULT rcresult;
  423.    REC rec;
  424.  
  425.    /* Check for empty buffer
  426.    */
  427.    rec =  DoRecognition(lprc, hpendata, &rcresult);
  428.  
  429.    if (rec == REC_OK)
  430.       (*lpFuncResults)((LPRCRESULT) &rcresult, rec = REC_DONE);
  431.  
  432.    return rec;
  433.    }
  434.  
  435.  
  436. /*----------------------------------------------------------
  437. Purpose: Private function sharing common code between
  438.          RecognizeInternal and RecognizeDataInternal.  This
  439.          fills in the RCRESULT structure.
  440. Returns: lprcresult struct is updated
  441. Cond:    --
  442. */
  443. REC DoRecognition(
  444.    LPRC lprc,              /* Ptr to RC struct */
  445.    HPENDATA hpendata,      /* Pendata handle */
  446.    LPRCRESULT lprcresult)  /* Ptr to RCRESULT */
  447.    {
  448.    LPPENDATA   lppendata;
  449.    LPPOINT     lppoint;
  450.    POINT    rgpntEnds[2];
  451.    STROKEINFO  si;
  452.  
  453.    /* Check for empty buffer
  454.    */
  455.    if (hpendata == 0 || (lppendata = BeginEnumStrokes(hpendata)) == NULL)
  456.       return REC_NOINPUT;
  457.  
  458.    /* Grab endpoints from first stroke
  459.    */
  460.    GetPenDataStroke(lppendata, 0, &lppoint, NULL, &si);
  461.    rgpntEnds[0] = lppoint[0];
  462.    rgpntEnds[1] = lppoint[si.cPnt-1];
  463.    EndEnumStrokes(hpendata);
  464.  
  465.    /* Build symbol graph
  466.    */
  467.    lprcresult->syg.rgpntHotSpots[0] = rgpntEnds[0];   /* Set hotspots to endpoints */
  468.    lprcresult->syg.rgpntHotSpots[1] = rgpntEnds[1];
  469.    lprcresult->syg.cHotSpot = 2;
  470.  
  471.    lprcresult->syg.lRecogVal = 0L;                    /* Not used */
  472.  
  473.    CalcNearestDirection(&rgpntEnds[0]);
  474.    lprcresult->syg.lpsye = &syeGlobal;
  475.    lprcresult->syg.cSye = 1;
  476.  
  477.    /* Fill data struct
  478.    */
  479.    lprcresult->wResultsType   = RCRT_PRIVATE;      /* Recognizer-specific result */
  480.    lprcresult->nBaseLine      = 0;
  481.    lprcresult->nMidLine       = 0;
  482.    lprcresult->hSyv        = 0;
  483.  
  484.    lprcresult->hpendata    = hpendata;
  485.    lprcresult->lprc        = lprc;
  486.    return REC_OK;
  487.    }
  488.  
  489.  
  490. /*----------------------------------------------------------
  491. Purpose: Private function to calculate the closest compass
  492.          direction of the line defined by pntFirst and pntLast.
  493. Returns:
  494. Comment: The created symbol element is composed of a
  495.          recognizer-specific symbol value (SYV), confidence level,
  496.          and recognizer value.
  497.  
  498.          This algorithm takes no tablet aspect ratio into account.
  499. */
  500. VOID CalcNearestDirection(LPPOINT lppointEnds)  /* Ptr to buffer of 2 POINT structs */
  501.    {
  502.    int    dx;
  503.    int    dy;
  504.    BOOL fIsEastward;
  505.    BOOL fIsSouthward;
  506.    BOOL fIsHoriz;
  507.  
  508.    dx = (lppointEnds+1)->x - lppointEnds->x;
  509.    dy = (lppointEnds+1)->y - lppointEnds->y;
  510.  
  511.    fIsEastward = dx > 0 ? TRUE : FALSE;
  512.    fIsSouthward = dy > 0 ? TRUE : FALSE;
  513.    fIsHoriz = ABS(dx) > ABS(dy) ? TRUE : FALSE;
  514.  
  515.    if (fIsHoriz)
  516.       {
  517.       syeGlobal.syv = fIsEastward ? syvEast : syvWest;
  518.       }
  519.    else
  520.       {
  521.       syeGlobal.syv = fIsSouthward ? syvSouth : syvNorth;
  522.       }
  523.    if (dx == 0 && dy == 0)
  524.       {
  525.       syeGlobal.syv = syvDot;
  526.       }
  527.  
  528.    syeGlobal.cl = 100;        /* Set confidence level */
  529.    syeGlobal.lRecogVal = 0L;  /* Not used */
  530.    }
  531.  
  532.  
  533. /*----------------------------------------------------------
  534. Purpose: Far pointer version of strncpy
  535. Returns: Ptr to copied string
  536. */
  537. LPSTR lstrncpy(
  538.    LPSTR lpszA,   /* Dest string */
  539.    LPSTR lpszB,   /* Source string */
  540.    int cch)       /* Max count of characters to copy */
  541.    {
  542.    LPSTR lpszSav = lpszA;
  543.  
  544.    while (cch-- > 0 && (*lpszA++ = *lpszB++))
  545.       ;
  546.    *(--lpszA) = NULL;
  547.    return lpszSav;
  548.    }
  549.