home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1992 / 09 / demo8.c < prev    next >
Text File  |  1992-02-29  |  40KB  |  934 lines

  1. // DEMO8.C --- Pen-centric Windows application that accepts 
  2. //             handwritten input, then displays various 
  3. //             information from the RCRESULT structure.
  4. // Copyright (C) 1992 Ray Duncan
  5.  
  6. #define WIN31
  7. #define dim(x) (sizeof(x) / sizeof(x[0]))   // returns no. of elements
  8. #define BUFMAX 80                           // size of scratch buffers
  9.  
  10. #include "windows.h"
  11. #include "penwin.h"
  12. #include "demo8.h"
  13.  
  14. HANDLE hInst;                               // instance handle
  15. HWND hWndFrame = 0;                         // frame window handle
  16. HWND hWndText = 0;                          // child text window handle
  17. HWND hWndWrite = 0;                         // child writing window handle
  18. HANDLE hPenWin = 0;                         // Pen Windows module handle
  19. HDC hdc;                                    // device context
  20.  
  21. int CharX = 0;                              // average char width
  22. int CharY = 0;                              // char height
  23. int CurLine = 0;                            // current line number
  24. int MaxLine = 0;                            // lines per window
  25. int EnumCount = 0;                          // translation counter
  26. int DisplayMode = IDM_RCRESULT;             // current display format
  27.  
  28. char szFrameClass[] = "DemoFrameClass";     // name of frame window class
  29. char szTextClass[]  = "DemoTextClass";      // child text window class
  30. char szWriteClass[] = "DemoWriteClass";     // child writing window class
  31.  
  32. HANDLE hSye = 0;                            // handle for copy of SYE array
  33. HANDLE hSyc = 0;                            // handle for copy of SYC array
  34. RCRESULT rcresult;                          // local copy of RCRESULT 
  35. REC recResult = -1;                         // status from Recognize()
  36. RC rc;                                      // recognition context
  37.  
  38. struct decodeInt {                          // simple structure to
  39.     int Code;                               // associate integer values
  40.     char * Name; };                         // with character strings
  41.  
  42. struct decodeLong {                         // simple structure to
  43.     long Code;                              // associate long values
  44.     char * Name; };                         // with character strings
  45.  
  46. struct decodeSYV {                          // simple structure to
  47.     SYV Code;                               // associate SYV values
  48.     char * Name; };                         // with character strings
  49.  
  50. struct decodeInt recogResults[] = {         // values returned by
  51.     REC_OK, "REC_OK",                       // Recognize() function
  52.     REC_ABORT, "REC_ABORT",
  53.     REC_ALC, "REC_ALC",
  54.     REC_BADEVENTREF, "REC_BADEVENTREF",
  55.     REC_BADHPENDATA, "REC_BADHPENDATA",
  56.     REC_BUFFERTOOSMALL, "REC_BUFFERTOOSMALL",
  57.     REC_BUSY, "REC_BUSY",
  58.     REC_CLVERIFY, "REC_CLVERIFY",
  59.     REC_DICT, "REC_DICT",
  60.     REC_DONE, "REC_DONE",
  61.     REC_ERRORLEVEL, "REC_ERRORLEVEL",
  62.     REC_GUIDE, "REC_GUIDE",
  63.     REC_HREC, "REC_HREC",
  64.     REC_HWND, "REC_HWND",
  65.     REC_INVALIDREF, "REC_INVALIDREF",
  66.     REC_LANGUAGE, "REC_LANGUAGE",
  67.     REC_NOCOLLECTION, "REC_NOCOLLECTION",
  68.     REC_NOINPUT, "REC_NOINPUT",
  69.     REC_NOTABLET, "REC_NOTABLET",
  70.     REC_OEM, "REC_OEM",
  71.     REC_OOM, "REC_OOM",
  72.     REC_OVERFLOW, "REC_OVERFLOW",
  73.     REC_PARAMERROR, "REC_PARAMERROR",
  74.     REC_PCM, "REC_PCM",
  75.     REC_POINTEREVENT, "REC_POINTEREVENT",
  76.     REC_RECTEXCLUDE, "REC_RECTEXCLUDE",
  77.     REC_RECTBOUND, "REC_RECTBOUND",
  78.     REC_RESULTMODE, "REC_RESULTMODE",
  79.     REC_TERMBOUND, "REC_TERMBOUND",
  80.     REC_TERMEX, "REC_TERMEX",
  81.     REC_TERMOEM, "REC_TERMOEM",
  82.     REC_TERMPENUP, "REC_TERMPENUP",
  83.     REC_TERMRANGE, "REC_TERMRANGE",
  84.     REC_TERMTIMEOUT, "REC_TERMTIMEOUT", } ;
  85.  
  86. struct decodeInt rctypeResults[] = {        // RCRESULT data types  
  87.     RCRT_UNIDENTIFIED, "RCRT_UNIDENTIFIED",
  88.     RCRT_GESTURE, "RCRT_GESTURE",   
  89.     RCRT_NOSYMBOLMATCH, "RCRT_NOSYMBOLMATCH",    
  90.     RCRT_PRIVATE, "RCRT_PRIVATE",
  91.     RCRT_NORECOG, "RCRT_NORECOG",
  92.     RCRT_ALREADYPROCESSED, "RCRT_ALREADYPROCESSED",
  93.     RCRT_GESTURETRANSLATED, "RCRT_GESTURETRANSLATED",
  94.     RCRT_GESTURETOKEYS, "RCRT_GESTURETOKEYS", } ;
  95.  
  96. struct decodeInt pdtsScale[] = {            // PENDATAHEADER structure
  97.     PDTS_ARBITRARY, "PDTS_ARBITRARY",       // PDTS_XXXX scale field
  98.     PDTS_DISPLAY, "PDTS_DISPLAY",
  99.     PDTS_HIENGLISH, "PDTS_HIENGLISH",
  100.     PDTS_HIMETRIC, "PDTS_HIMETRIC",
  101.     PDTS_LOMETRIC, "PDTS_LOMETRIC",
  102.     PDTS_SCALEMAX, "PDTS_SCALEMAX", } ;
  103.  
  104. struct decodeInt pdtsBits[] = {             // PENDATAHEADER structure
  105.     PDTS_COMPRESSED, "PDTS_COMPRESSED",     // other PDTS_xxx bits
  106.     PDTS_COMPRESSMETHOD, "PDTS_COMPRESSMETHOD",
  107.     PDTS_COMPRESS2NDDERIV, "PDTS_COMPRESS2NDDERIV",
  108.     PDTS_NOCOLINEAR, "PDTS_NOCOLINEAR",
  109.     PDTS_NOOEMDATA, "PDTS_NOOEMDATA",
  110.     PDTS_NOPENINFO, "PDTS_NOPENINFO",
  111.     PDTS_NOUPPOINTS, "PDTS_NOUPPOINTS", } ;
  112.  
  113. struct decodeLong pdcBits[] = {             // PENINFO structure
  114.     PDC_BARREL1, "PDC_BARREL1",             // PDC_xxx bits
  115.     PDC_BARREL2, "PDC_BARREL2",
  116.     PDC_BARREL3, "PDC_BARREL3",
  117.     PDC_INTEGRATED, "PDC_INTEGRATED",
  118.     PDC_INVERT, "PDC_INVERT",
  119.     PDC_PROXIMITY, "PDC_PROXIMITY",
  120.     PDC_RANGE, "PDC_RANGE",
  121.     PDC_RELATIVE, "PDC_RELATIVE", } ;
  122.  
  123. struct decodeSYV syvSystemValue[] = {       // system values for SYVs
  124.     SYV_BEGINOR, "SYV_BEGINOR",
  125.     SYV_EMPTY, "SYV_EMPTY",                 
  126.     SYV_ENDOR, "SYV_ENDOR",
  127.     SYV_NULL, "SYV_NULL",                   
  128.     SYV_OR, "SYV_OR",
  129.     SYV_SOFTNEWLINE, "SYV_SOFTNEWLINE",
  130.     SYV_UNKNOWN, "SYV_UNKNOWN", } ;
  131.  
  132. struct decodeSYV syvGestureValue[] = {      // gesture values for SYVs
  133.     SYV_BACKSPACE, "SYV_BACKSPACE",
  134.     SYV_CLEAR, "SYV_CLEAR",
  135.     SYV_CLEARWORD, "SYV_CLEARWORD",
  136.     SYV_COPY, "SYV_COPY",
  137.     SYV_CORRECT, "SYV_CORRECT",
  138.     SYV_CUT, "SYV_CUT",
  139.     SYV_EXTENDSELECT, "SYV_EXTENDSELECT",
  140.     SYV_PASTE, "SYV_PASTE",
  141.     SYV_RETURN, "SYV_RETURN",
  142.     SYV_SPACE, "SYV_SPACE",
  143.     SYV_TAB, "SYV_TAB",
  144.     SYV_UNDO, "SYV_UNDO",
  145.     SYV_USER, "SYV_USER", } ;
  146.  
  147. //
  148. // WinMain --- entry point from Windows.  Registers window classes,
  149. // creates windows, registers pen app, and processes messages until 
  150. // WM_QUIT received.
  151. //
  152. int PASCAL WinMain(HANDLE hInstance, 
  153.     HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  154. {
  155.     MSG msg;                     
  156.  
  157.     hInst = hInstance;                      // save this instance handle
  158.  
  159.     if(!hPrevInstance)                      // if first instance,
  160.         if(!InitApplication(hInstance))     // register window class
  161.             return(FALSE);                  // exit if couldn't register
  162.  
  163.     if(!InitInstance(hInstance, nCmdShow))  // create this instance's window
  164.     {
  165.         MessageBox(0, "Initialization failed!", "DEMO8", MB_OK|MB_ICONSTOP);
  166.         return(FALSE);
  167.     }
  168.  
  169.     RegisterPenApp(RPA_DEFAULT, TRUE);      // enable HEDIT/BEDIT controls
  170.  
  171.     while(GetMessage(&msg, NULL, 0, 0))     // while message != WM_QUIT
  172.     {
  173.         TranslateMessage(&msg);             // translate virtual key codes
  174.         DispatchMessage(&msg);              // dispatch message to window
  175.     }
  176.     return(msg.wParam);                     // return code = WM_QUIT value
  177. }
  178.  
  179. //
  180. // InitApplication --- registers window classes for this application
  181. //
  182. BOOL InitApplication(HANDLE hInstance)
  183. {
  184.     WNDCLASS  wc;
  185.     BOOL bParent;
  186.     BOOL bText;
  187.     BOOL bWrite;
  188.  
  189.     // set parameters for frame window class
  190.     wc.style = CS_HREDRAW | CS_VREDRAW;     // class style
  191.     wc.lpfnWndProc = FrameWndProc;           // class callback function
  192.     wc.cbClsExtra = 0;                      // extra per-class data
  193.     wc.cbWndExtra = 0;                      // extra per-window data
  194.     wc.hInstance = hInstance;               // handle of class owner
  195.     wc.hIcon = LoadIcon(hInst, "penicon");  // pendemo.ico icon
  196.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);       // default cursor
  197.     wc.hbrBackground = GetStockObject(WHITE_BRUSH); // background color 
  198.     wc.lpszMenuName =  "DemoMenu";          // name of menu resource
  199.     wc.lpszClassName = szFrameClass;        // name of window class
  200.  
  201.     bParent = RegisterClass(&wc);           // register frame window class
  202.  
  203.     // set parameters for text output child window class
  204.     wc.lpfnWndProc = TextWndProc;           // class callback function
  205.     wc.hIcon = NULL;                        // default icon
  206.     wc.lpszMenuName =  NULL;                // name of menu resource
  207.     wc.lpszClassName = szTextClass;         // name of window class
  208.  
  209.     bText = RegisterClass(&wc);             // register text child class
  210.  
  211.     // set parameters for writing input child window class
  212.     wc.lpfnWndProc = WriteWndProc;          // class callback function
  213.     wc.lpszClassName = szWriteClass;        // name of window class
  214.  
  215.     bWrite = RegisterClass(&wc);            // register writing child class
  216.  
  217.     return(bParent && bText && bWrite);     // return success/failure flag
  218. }
  219.  
  220. //
  221. // InitInstance --- creates frame window for this application instance
  222. //
  223. BOOL InitInstance(HANDLE hInstance, int nCmdShow)
  224. {
  225.     hWndFrame = CreateWindow(               // create frame window
  226.         szFrameClass,                       // window class name
  227.         "Pen Windows Demo #8",              // text for title bar
  228.         WS_OVERLAPPEDWINDOW,                // window style
  229.         CW_USEDEFAULT, CW_USEDEFAULT,       // default position
  230.         CW_USEDEFAULT, CW_USEDEFAULT,       // default size
  231.         NULL,                               // no parent window
  232.         NULL,                               // use class default menu
  233.         hInstance,                          // window owner
  234.         NULL                                // unused pointer
  235.     );
  236.  
  237.     if(!hWndFrame) return(FALSE);           // error, can't create window
  238.  
  239.     ShowWindow(hWndFrame, nCmdShow);        // make frame window visible
  240.     UpdateWindow(hWndFrame);                // force WM_PAINT message
  241.     return(TRUE);                           // return success flag
  242. }
  243.  
  244. //
  245. // FrameWndProc --- callback function for application frame window
  246. //
  247. long FAR PASCAL FrameWndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  248. {
  249.     switch (wMsg) 
  250.     {
  251.         case WM_CREATE:                     // creating frame window
  252.             hWndText = CreateWindow(        // create child text window
  253.                 szTextClass,                // window class name
  254.                 NULL,                       // text for title bar
  255.                 WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER,    // style
  256.                 0, 0, 0, 0,                 // position and size
  257.                 hWnd,                       // frame window is parent 
  258.                 0,                          // child window identifier
  259.                 hInst,                      // window owner
  260.                 NULL);                      // unused pointer
  261.             hWndWrite = CreateWindow(       // create child writing window
  262.                 szWriteClass,               // window class name
  263.                 NULL,                       // text for title bar
  264.                 WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER,    // style
  265.                 0, 0, 0, 0,                 // position and size
  266.                 hWnd,                       // frame window is parent 
  267.                 0,                          // child window identifier
  268.                 hInst,                      // window owner
  269.                 NULL);                      // unused pointer
  270.             break;
  271.  
  272.         case WM_SIZE:                       // resize & position children:
  273.             MoveWindow(hWndWrite,           // writing input window 
  274.                 0, 0, LOWORD(lParam)/2, HIWORD(lParam), TRUE);
  275.             MoveWindow(hWndText,            // text output window
  276.                 LOWORD(lParam)/2, 0, LOWORD(lParam)/2, HIWORD(lParam), TRUE);
  277.             return(0);
  278.  
  279.         case WM_COMMAND:                    // menu command received,
  280.             DoCommand(hWnd, wParam);        // decode it
  281.             break;
  282.  
  283.         case WM_DESTROY:                    // window being destroyed
  284.             PostQuitMessage(0);             // force WM_QUIT message
  285.             break;
  286.  
  287.         default:                            // let Windows handle it
  288.             return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  289.     }
  290.  
  291.     return(0);
  292. }
  293.  
  294. //
  295. // TextWndProc --- callback function for child text window
  296. //
  297. long FAR PASCAL TextWndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  298. {
  299.     TEXTMETRIC tm;                          // receives font characteristics
  300.     PAINTSTRUCT ps;                         // painting info structure
  301.     char buff1[BUFMAX];                     // scratch buffer
  302.     int i;                                  // scratch variable
  303.  
  304.     switch(wMsg)
  305.     {
  306.         case WM_CREATE:                     // creating text child window
  307.             hdc = GetDC(hWnd);              // get device context
  308.             GetTextMetrics(hdc, &tm);       // get text metrics
  309.             CharX = tm.tmAveCharWidth;      // save character size
  310.             CharY = tm.tmHeight + tm.tmExternalLeading;
  311.             ReleaseDC(hWnd, hdc);           // release device context
  312.             return(0);
  313.  
  314.         case WM_SIZE:                       // resize/position in progress
  315.             CurLine = 0;                    // reset current line number
  316.             MaxLine = HIWORD(lParam)/CharY; // no. of lines in window
  317.             return(0);
  318.  
  319.         case WM_PAINT:                      // time to repaint window
  320.             if(recResult == -1)             // bail out if no result
  321.                 return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  322.  
  323.             hdc = BeginPaint(hWnd, &ps);    // get device context
  324.  
  325.             switch(DisplayMode)             // display results 
  326.             {                               
  327.                 case IDM_RCRESULT:          // RCRESULT data structure  
  328.                     ShowRCResult(&rcresult); 
  329.                     break;
  330.  
  331.                 case IDM_SYMGRAPH:          // symbol graph
  332.                     ShowSymbolGraph(&rcresult);
  333.                     break;
  334.  
  335.                 case IDM_SYMSTRINGS:        // candidate symbol strings
  336.                     ShowSymbolStrings(&rcresult);
  337.                     break;
  338.  
  339.                 case IDM_PENDATAHEADER:     // PENDATAHEADER structure
  340.                     ShowPenDataHeader(&rcresult);
  341.                     break;
  342.  
  343.                 case IDM_PENINFO:           // PENINFO structure
  344.                     ShowPenInfo(&rcresult);
  345.                     break;
  346.  
  347.                 case IDM_PENSTROKES:        // individual pen strokes
  348.                     ShowPenStrokes(&rcresult);
  349.                     break;
  350.  
  351.                 case IDM_PENINK:            // scale and redraw ink
  352.                     ShowPenInk(&rcresult);
  353.                     break;
  354.             }
  355.             EndPaint(hWnd, &ps);            // release device context
  356.             break;
  357.  
  358.         default:
  359.             return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  360.     }
  361. }
  362.  
  363. //
  364. // WriteWndProc --- callback function for child writing window
  365. //
  366. long FAR PASCAL WriteWndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  367. {
  368.     PAINTSTRUCT ps;                         // painting info structure
  369.     RECT rect;                              // receives client rectangle
  370.  
  371.     switch(wMsg)
  372.     {
  373.         case WM_PAINT:                      // window needs repainting
  374.             hdc = BeginPaint(hWnd, &ps);    // get device context
  375.             GetClientRect(hWnd, &rect);     // get client rectangle
  376.             DrawText(hdc,                   // put legend in writing area
  377.                 "Writing Area", -1, &rect, 
  378.                 DT_CENTER | DT_TOP | DT_SINGLELINE);
  379.             EndPaint(hWnd, &ps);            // release device context
  380.             break;
  381.  
  382.         case WM_LBUTTONDOWN:                // "pen-down" in writing area
  383.             if(IsPenEvent(wMsg, GetMessageExtraInfo()))
  384.             {
  385.                 InvalidateRect(hWnd, NULL, TRUE);   // erase input window
  386.                 UpdateWindow(hWnd);                 
  387.                 InitRC(hWndWrite, &rc);     // set default RC values
  388.                 rc.hwnd = hWnd;             // this window gets the results
  389.                 rc.rglpdf[0] = NULL;        // assume no dictionary
  390.                 recResult = Recognize(&rc); // request pen input
  391.                 CurLine = 0;                // reset line number for output
  392.                 InvalidateRect(hWndText, NULL, TRUE);   
  393.                 UpdateWindow(hWndText);     // force repaint of output window       
  394.             };
  395.             return(0);
  396.  
  397.         case WM_RCRESULT:                   // recognition results arriving
  398.             SaveResults(lParam);            // save copy of results
  399.             return(0);                      
  400.  
  401.         default:
  402.             return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  403.     }
  404. }
  405.  
  406. //
  407. // ShowRCResult -- displays contents of RCRESULT data structure
  408. //
  409. void ShowRCResult(LPRCRESULT rcresult)
  410. {
  411.     char buff1[BUFMAX], buff2[BUFMAX];      // scratch buffers
  412.     int i;                                  // scratch variable
  413.  
  414.     strcpy(buff1, "Recognize result: unknown.");
  415.     for(i = 0; i < dim(recogResults); i++)
  416.     {                                       // decode Recognize() value
  417.         if(recogResults[i].Code == recResult)
  418.             wsprintf(buff1, "Recognize result: %s.", 
  419.                 (LPSTR) recogResults[i].Name);
  420.     }
  421.     DisplayLine(buff1);                     // display Recognize() status   
  422.  
  423.     wsprintf(buff1, "rcresult.syg.cHotSpot = %0d", rcresult->syg.cHotSpot);
  424.     DisplayLine(buff1);                     // number of valid hot spots
  425.  
  426.     wsprintf(buff1, "rcresult.syg.nFirstBox = %0d", rcresult->syg.nFirstBox);
  427.     DisplayLine(buff1);                     // box index, first result char
  428.  
  429.     wsprintf(buff1, "rcresult.syg.lpsye = %04X:%04Xh", 
  430.         HIWORD(rcresult->syg.lpsye), LOWORD(rcresult->syg.lpsye));
  431.     DisplayLine(buff1);                     // pointer to SYE nodes
  432.  
  433.     wsprintf(buff1, "rcresult.syg.cSye = %0d", rcresult->syg.cSye);
  434.     DisplayLine(buff1);                     // no. of SYEs in symbol graph
  435.  
  436.     wsprintf(buff1, "rcresult.syg.lpsyc = %04X:%04Xh", 
  437.         HIWORD(rcresult->syg.lpsyc), LOWORD(rcresult->syg.lpsyc));
  438.     DisplayLine(buff1);                     // pointer to SYC nodes
  439.  
  440.     wsprintf(buff1, "rcresult.syg.cSyc = %0d", rcresult->syg.cSyc);
  441.     DisplayLine(buff1);                     // number of SYCs 
  442.  
  443.     if(rcresult->wResultsType == RCRT_DEFAULT)  // decode result type
  444.         DisplayLine("rcresult.wResultsType = RCRT_DEFAULT");
  445.     else                                    // if not RCRT_DEFAULT,
  446.     {                                       // check each possible flag
  447.         for(i = 0; i < dim(rctypeResults); i++) 
  448.         {                                       
  449.             if(rctypeResults[i].Code & rcresult->wResultsType)
  450.             {
  451.                 wsprintf(buff1, "rcresult.wResultsType = %s", 
  452.                     (LPSTR) rctypeResults[i].Name);
  453.                 DisplayLine(buff1);             
  454.             }
  455.         }
  456.     }
  457.  
  458.     wsprintf(buff1, "rcresult.cSyv = %d", rcresult->cSyv);
  459.     DisplayLine(buff1);                     // number of symbols
  460.  
  461.     FirstSymbolFromGraph(&rcresult->syg, (LPSYV) buff1, BUFMAX, &i);
  462.     SymbolToCharacter((LPSYV) buff1, BUFMAX, buff2, NULL);
  463.     wsprintf(buff1, "rcresult.lpsyv -> %s", (LPSTR) buff2);
  464.     DisplayLine(buff1);                     // best bet translated string
  465.  
  466.     wsprintf(buff1, "rcresult.nBaseLine = %0d", rcresult->nBaseLine);
  467.     DisplayLine(buff1);                     // baseline of written input
  468.  
  469.     wsprintf(buff1, "rcresult.nMidLine = %0d", rcresult->nMidLine);
  470.     DisplayLine(buff1);                     // midline of written input
  471.  
  472.     wsprintf(buff1, "rcresult.hpendata = %04Xh", rcresult->hpendata);
  473.     DisplayLine(buff1);                     // pen data memory block handle
  474.  
  475.     wsprintf(buff1, "rcresult.rectBoundInk = (%d,%d)-(%d,%d)",
  476.         rcresult->rectBoundInk.left, rcresult->rectBoundInk.top,
  477.         rcresult->rectBoundInk.right, rcresult->rectBoundInk.bottom);
  478.     DisplayLine(buff1);                     // bounding rectangle for ink
  479.  
  480.     wsprintf(buff1, "rcresult.pntEnd = (%d,%d)",
  481.         rcresult->pntEnd.x, rcresult->pntEnd.y);
  482.     DisplayLine(buff1);                     // recognition termination point
  483.  
  484.     wsprintf(buff1, "rcresult.lprc = %04X:%04Xh", 
  485.         HIWORD(rcresult->lprc), LOWORD(rcresult->lprc));
  486.     DisplayLine(buff1);                     // address of RC structure
  487. }
  488.  
  489. //
  490. // ShowSymbolStrings -- enumerates and displays candidate symbol strings
  491. //
  492. void ShowSymbolStrings(LPRCRESULT rcresult)
  493. {
  494.     FARPROC lpProc;                         // far pointer for callback 
  495.     char buff1[BUFMAX];                     // scratch buffer
  496.  
  497.     wsprintf(buff1, "Symbol graph has %d possible translations.",
  498.         GetSymbolCount(&(rcresult->syg)));   
  499.     DisplayLine(buff1);                     // display no. of candidates
  500.     EnumCount = 0;                          // then display each candidate
  501.     lpProc = MakeProcInstance(EnumFunc, hInst);
  502.     EnumSymbols(&(rcresult->syg), 1000, lpProc, NULL);
  503.     FreeProcInstance(lpProc);
  504. }
  505.  
  506. //
  507. // ShowSymbolGraph -- displays contents of symbol graph
  508. //
  509. void ShowSymbolGraph(LPRCRESULT rcresult)
  510. {
  511.     LPSYE lpSye = rcresult->syg.lpsye;      // first symbol element
  512.     int cSye = rcresult->syg.cSye;          // no. of symbol elements
  513.     int Level = 0;                          // SYV_BEGINOR nesting level
  514.     SYV syv;                                // current symbol value
  515.     char syvChar;                           // current character
  516.     int syvCl;                              // current confidence level
  517.     int syvType;                            // current symbol type
  518.     char buff1[BUFMAX], buff2[BUFMAX];      // scratch buffers
  519.     int i, j;                               // scratch variable
  520.     char * p;                               // scratch pointer
  521.  
  522.     FirstSymbolFromGraph(&rcresult->syg, (LPSYV) buff1, BUFMAX, &i);
  523.     SymbolToCharacter((LPSYV) buff1, BUFMAX, buff2, NULL);
  524.     wsprintf(buff1, "Preferred translation: %s", (LPSTR) buff2);
  525.     DisplayLine(buff1);                     // best bet translated string
  526.  
  527.     DisplayLine("Start of symbol graph:");  // now dump the symbol graph
  528.  
  529.     for(i = 0; i < cSye; i++)
  530.     {                                       
  531.         syv = lpSye[i].syv;                 // get current symbol value
  532.         syvType = HIWORD(syv);              // extract symbol type
  533.         syvChar = ChSyvToAnsi(syv);         // extract character if any
  534.         syvCl = lpSye[i].cl;                // get confidence level
  535.  
  536.         switch(syvType)                     // format according to type
  537.         {
  538.             case(SYVHI_SPECIAL):            // SYV system values
  539.                 if(syv == SYV_BEGINOR)      // start of char. choice list
  540.                 {                           
  541.                     if(Level)               // if stuff already waiting 
  542.                         DisplayLine(buff1); // in buffer, display it
  543.                     p = buff1 + wsprintf(buff1, "{ ");
  544.                     Level++;                // count nesting levels
  545.                 }
  546.                 else if(syv == SYV_OR)      // choice list separator
  547.                 {
  548.                     p += wsprintf(p, " | ");
  549.                 }
  550.                 else if(syv == SYV_ENDOR)   // end of char. choice list
  551.                 {                           
  552.                     wsprintf(p, " }");
  553.                     DisplayLine(buff1);     // display choice list
  554.                     p = buff1;
  555.                     Level--;                // count nesting levels
  556.                 }
  557.                 else                        // decode & display all 
  558.                 {                           // other system SYV values
  559.                     for(j = 0; j < dim(syvSystemValue); j++)
  560.                     {                       
  561.                         if(syvSystemValue[j].Code == syv)
  562.                             DisplayLine(syvSystemValue[j].Name);
  563.                     }
  564.                 }
  565.                 break;
  566.  
  567.             case(SYVHI_ANSI):               // SYV ASCII characters
  568.                 if(syv == SYV_SPACENULL)    // format char. & conf. level
  569.                     wsprintf(buff2, "NO SPACE [%d%%]", syvCl);
  570.                 else if(syvChar == ' ')
  571.                     wsprintf(buff2, "SPACE [%d%%]", syvCl);
  572.                 else if(syvChar < ' ')
  573.                     wsprintf(buff2, "%02Xh [%d%%]", syvChar, syvCl);
  574.                 else
  575.                     wsprintf(buff2, "%c [%d%%]", syvChar, syvCl);
  576.  
  577.                 if(Level)                   // within char. choice list?
  578.                     p += wsprintf(p, "%s", (LPSTR) buff2);  // yes, append 
  579.                 else                        // no, display text now
  580.                     DisplayLine(buff2);                     
  581.                 break;
  582.  
  583.             case(SYVHI_GESTURE):            // SYV gestures
  584.                 for(j = 0; j < dim(syvGestureValue); j++)
  585.                 {                           // decode gesture value
  586.                     if(syvGestureValue[j].Code == syv)
  587.                     {                       // found match, display it
  588.                         DisplayLine(syvGestureValue[j].Name);
  589.                         break;
  590.                     }
  591.                     if(j == dim(syvGestureValue))
  592.                     {                       // no match, show hex value
  593.                         wsprintf(buff1, "gesture: %08lXh", syv);
  594.                         DisplayLine(buff1);                     
  595.                     }
  596.                 }
  597.                 break;
  598.  
  599.             case(SYVHI_KANJI):              // Kanji
  600.             case(SYVHI_SHAPE):              // shapes
  601.             case(SYVHI_UNICODE):            // Unicode
  602.             case(SYVHI_VKEY):               // virtual keys
  603.             default:                        // whatever else
  604.                 wsprintf(buff1, "type %d: %08lXh", syvType, syv);
  605.                 DisplayLine(buff1);                     
  606.         }
  607.     }
  608.     DisplayLine("End of symbol graph.");  
  609. }
  610.  
  611. //
  612. // ShowPenDataHeader -- displays PENDATAHEADER structure
  613. //
  614. void ShowPenDataHeader(LPRCRESULT rcresult)
  615. {
  616.     PENDATAHEADER pdh;                      // pen data header
  617.     char buff1[BUFMAX];                     // scratch buffer
  618.     int i;                                  // scratch variable
  619.  
  620.     GetPenDataInfo(rcresult->hpendata, &pdh, NULL, 0L);
  621.  
  622.     wsprintf(buff1, "pendataheader.wVersion = %d", pdh.wVersion);
  623.     DisplayLine(buff1);                     // pen data format version
  624.  
  625.     wsprintf(buff1, "pendataheader.cbSizeUsed = %u", pdh.cbSizeUsed);
  626.     DisplayLine(buff1);                     // size of pen data in bytes
  627.  
  628.     wsprintf(buff1, "pendataheader.cStrokes = %u", pdh.cStrokes);
  629.     DisplayLine(buff1);                     // number of pen strokes
  630.  
  631.     wsprintf(buff1, "pendataheader.cPnt = %u", pdh.cPnt);
  632.     DisplayLine(buff1);                     // number of points
  633.  
  634.     wsprintf(buff1, "pendataheader.cPntStrokeMax = %u", pdh.cPntStrokeMax);
  635.     DisplayLine(buff1);                     // points in longest stroke
  636.  
  637.     wsprintf(buff1, "pendataheader.rectBound = (%d,%d)-(%d,%d)",
  638.         pdh.rectBound.left, pdh.rectBound.top,
  639.         pdh.rectBound.right, pdh.rectBound.bottom);
  640.     DisplayLine(buff1);                     // bounding rect down points
  641.  
  642.     wsprintf(buff1, "pendataheader.wPndts = %Xh", pdh.wPndts);
  643.     DisplayLine(buff1);                     // state of PDTS_xxx bits
  644.  
  645.     for(i = 0; i < dim(pdtsScale); i++)     // decode PDTS_ scaling field
  646.     {                                       
  647.         if(pdtsScale[i].Code == (PDTS_SCALEMASK & pdh.wPndts))
  648.         {
  649.             wsprintf(buff1, "pendataheader.wPndts = %s", 
  650.                 (LPSTR) pdtsScale[i].Name);
  651.             DisplayLine(buff1);             
  652.         }
  653.     }
  654.  
  655.     for(i = 0; i < dim(pdtsBits); i++)      // decode PDTS_xxx bits
  656.     {                                       
  657.         if(pdtsBits[i].Code & pdh.wPndts)
  658.         {
  659.             wsprintf(buff1, "pendataheader.wPndts = %s", 
  660.                 (LPSTR) pdtsBits[i].Name);
  661.             DisplayLine(buff1);             
  662.         }
  663.     }
  664.  
  665.     wsprintf(buff1, "pendataheader.nInkWidth = %d", pdh.nInkWidth);
  666.     DisplayLine(buff1);                     // ink width
  667.  
  668.     wsprintf(buff1, "pendataheader.rgbInk = %08lXh", pdh.rgbInk);
  669.     DisplayLine(buff1);                     // ink color
  670. }
  671.  
  672. //
  673. // ShowPenInfo -- displays PENINFO structure
  674. //
  675. void ShowPenInfo(LPRCRESULT rcresult)
  676. {
  677.     PENDATAHEADER pdh;                      // pen data header
  678.     PENINFO peninfo;                        // pen info structure
  679.     char buff1[BUFMAX];                     // scratch buffer
  680.     int i;                                  // scratch variable
  681.  
  682.     GetPenDataInfo(rcresult->hpendata, &pdh, &peninfo, 0L);
  683.  
  684.     wsprintf(buff1, "peninfo.cxRawWidth = %u", peninfo.cxRawWidth);
  685.     DisplayLine(buff1);                     // width in 0.001 inches
  686.  
  687.     wsprintf(buff1, "peninfo.cyRawHeight = %u", peninfo.cyRawHeight);
  688.     DisplayLine(buff1);                     // height in 0.001 inches
  689.  
  690.     wsprintf(buff1, "peninfo.wDistinctWidth = %u", peninfo.wDistinctWidth);
  691.     DisplayLine(buff1);                     // width in distinct X values
  692.  
  693.     wsprintf(buff1, "peninfo.wDistinctHeight = %u", peninfo.wDistinctHeight);
  694.     DisplayLine(buff1);                     // height in distinct Y values
  695.  
  696.     wsprintf(buff1, "peninfo.nSamplingRate = %d", peninfo.nSamplingRate);
  697.     DisplayLine(buff1);                     // samples per second
  698.  
  699.     wsprintf(buff1, "peninfo.nSamplingDist = %d", peninfo.nSamplingDist);
  700.     DisplayLine(buff1);                     // minimum distance per event
  701.  
  702.     wsprintf(buff1, "peninfo.lPdc = %08lXh", peninfo.lPdc);
  703.     DisplayLine(buff1);                     // pen device capabilities
  704.  
  705.     for(i = 0; i < dim(pdcBits); i++)       // decode PDC_xxxx bits
  706.     {                                       
  707.         if(pdcBits[i].Code & peninfo.lPdc)
  708.         {
  709.             wsprintf(buff1, "peninfo.lPdc = %s", 
  710.                 (LPSTR) pdcBits[i].Name);
  711.             DisplayLine(buff1);             
  712.         }
  713.     }
  714.  
  715.     wsprintf(buff1, "peninfo.cPens = %d", peninfo.cPens);
  716.     DisplayLine(buff1);                     // number of pens supported
  717.  
  718.     wsprintf(buff1, "peninfo.cbOemData = %d", peninfo.cbOemData);
  719.     DisplayLine(buff1);                     // width of OEM data packet
  720. }
  721.  
  722. //
  723. // ShowPenStrokes -- displays STROKEINFO structures
  724. //
  725. void ShowPenStrokes(LPRCRESULT rcresult)
  726. {
  727.     PENDATAHEADER pdh;                      // pen data header
  728.     STROKEINFO strokeinfo;                  // stroke information
  729.     LPPENDATA lpPenData;                    // far pointer to pen data
  730.     LPPOINT lpPoint;                        // far pointer to POINT list
  731.     char buff1[BUFMAX];                     // scratch buffer
  732.     int i;                                  // scratch variable
  733.  
  734.     GetPenDataInfo(rcresult->hpendata, &pdh, NULL, 0L); // get PENDATAHEADER
  735.     lpPenData = BeginEnumStrokes(rcresult->hpendata);   // lock pen data
  736.  
  737.     DisplayLine("Stroke  Points  State   TimeStamp");       
  738.  
  739.     for(i = 0; i < pdh.cStrokes; i++)
  740.     {                                       // get info for this stroke
  741.         GetPenDataStroke(lpPenData, i, &lpPoint, NULL, &strokeinfo);
  742.  
  743.         wsprintf(buff1, " %03d     %05u  %04Xh  %09ld",     
  744.             i,                              // stroke number
  745.             strokeinfo.cPnt,                // points in stroke
  746.             strokeinfo.wPdk,                // state of stroke
  747.             strokeinfo.dwTick);             // timestamp of stroke
  748.         DisplayLine(buff1);                     
  749.     }
  750.  
  751.     EndEnumStrokes(rcresult->hpendata);     // unlock pen data
  752. }
  753.  
  754. //
  755. // ShowPenInk -- redraws original ink in right-hand window
  756. //
  757. void ShowPenInk(LPRCRESULT rcresult)
  758. {
  759.     PENDATAHEADER pdh;                      // pen data header
  760.     HPENDATA hpendata;                      // duplicate ink handle 
  761.     LPPENDATA lpPenData;                    // far pointer to pen data
  762.     char buff1[BUFMAX];                     // scratch buffer for output
  763.     RECT rect;                              // client rect for output win
  764.  
  765.     GetClientRect(hWndText, &rect);         // get client rectangle
  766.  
  767.     rect.left += 10;                        // calculate bounding 
  768.     rect.right += -10;                      // rectangle for redrawn ink
  769.     rect.top += ((rect.bottom-rect.top)/2) + 10;    
  770.     rect.bottom += -10;                     
  771.  
  772.     // duplicate original ink in a new PENDATA memory block
  773.     hpendata = DuplicatePenData(rcresult->hpendata, GMEM_MOVEABLE);
  774.  
  775.     // get PENDATAHEADER for duplicated ink memory block
  776.     GetPenDataInfo(hpendata, &pdh, NULL, 0L);
  777.  
  778.     // display total strokes and points from PENDATAHEADER
  779.     wsprintf(buff1, "Strokes = %u", pdh.cStrokes);
  780.     DisplayLine(buff1);        
  781.     wsprintf(buff1, "Points = %u", pdh.cPnt);
  782.     DisplayLine(buff1);        
  783.  
  784.     // display original bounding rectangle from PENDATAHEADER
  785.     DisplayLine("Bounding rectangles:");                     
  786.     wsprintf(buff1, "Original = (%d,%d)-(%d,%d)",
  787.         pdh.rectBound.left, pdh.rectBound.top,
  788.         pdh.rectBound.right, pdh.rectBound.bottom);
  789.     DisplayLine(buff1);                     
  790.  
  791.     // rescale pen data points for display
  792.     MetricScalePenData(hpendata, PDTS_DISPLAY);
  793.  
  794.     // display rescaled bounding rectangle from PENDATAHEADER
  795.     GetPenDataInfo(hpendata, &pdh, NULL, 0L);
  796.     wsprintf(buff1, "Rescaled = (%d,%d)-(%d,%d)",
  797.         pdh.rectBound.left, pdh.rectBound.top,
  798.         pdh.rectBound.right, pdh.rectBound.bottom);
  799.     DisplayLine(buff1);                     
  800.  
  801.     // resize pen data to fit in lower half of output window
  802.     ResizePenData(hpendata, &rect);
  803.  
  804.     // display resized bounding rectangle from PENDATAHEADER
  805.     GetPenDataInfo(hpendata, &pdh, NULL, 0L);
  806.     wsprintf(buff1, "Resized = (%d,%d)-(%d,%d)",
  807.         pdh.rectBound.left, pdh.rectBound.top,
  808.         pdh.rectBound.right, pdh.rectBound.bottom);
  809.     DisplayLine(buff1);                     
  810.  
  811.     // draw a frame for the ink in lower half of output window
  812.     Rectangle(hdc, rect.left-2, rect.top-2, rect.right+2,rect.bottom+2);
  813.  
  814.     // redraw ink within the frame 
  815.     DrawPenData(hdc, NULL, hpendata);
  816.  
  817.     DestroyPenData(hpendata);               // release duplicate ink block  
  818. }
  819.  
  820. // 
  821. // DisplayLine --- displays a string in the text output child window
  822. //
  823. void DisplayLine(char * szOut)
  824. {
  825.     RECT rect;
  826.  
  827.     if(CurLine == MaxLine)                  // at bottom of window?
  828.         return;                             // yes, bail out
  829.  
  830.     GetClientRect(hWndText, &rect);         // get client rectangle
  831.     TextOut(hdc, 0, CurLine * CharY,        // display text in window
  832.         szOut, strlen(szOut));
  833.     CurLine++;                              // move to next line
  834.     return;
  835. }
  836.  
  837. //
  838. // DoCommand --- handles menu command messages for the frame window
  839. //
  840. void DoCommand(HWND hWnd, WORD wParam)
  841. {
  842.     FARPROC lpProc;                         // far pointer to callback 
  843.     HMENU hMenu;
  844.  
  845.     switch(wParam)                          // decode it
  846.     {
  847.         case IDM_EXIT:                      // user picked File-Quit
  848.             SendMessage (hWnd, WM_CLOSE, 0, 0L);
  849.             break;
  850.  
  851.         case IDM_RCRESULT:                  // user picked a display
  852.         case IDM_SYMGRAPH:                  // format, save it and 
  853.         case IDM_SYMSTRINGS:                // check/uncheck menu items,
  854.         case IDM_PENDATAHEADER:             // then reset line number   
  855.         case IDM_PENINFO:                   // for output window and
  856.         case IDM_PENSTROKES:                // force repaint of window
  857.         case IDM_PENINK:
  858.             hMenu = GetMenu(hWnd);
  859.             CheckMenuItem(hMenu, DisplayMode, MF_UNCHECKED);
  860.             DisplayMode = wParam;
  861.             CheckMenuItem(hMenu, DisplayMode, MF_CHECKED);
  862.             CurLine = 0;                    
  863.             InvalidateRect(hWndText, NULL, TRUE);   
  864.             UpdateWindow(hWndText);         
  865.             break;
  866.  
  867.         default:                            // unknown command, ignore it
  868.             break;
  869.     }
  870. }
  871.  
  872. //
  873. // EnumFunc --- the callback function for EnumSymbols().  During
  874. // evaluation of a symbol graph, this function is entered 
  875. // repetitively with a pointer to each candidate symbol array.
  876. // The symbol array is translated to a character string and displayed.
  877. //
  878. int FAR PASCAL EnumFunc(LPSYV lpSyv, int cSyv, VOID FAR * lpData)
  879. {
  880.     char buff1[BUFMAX], buff2[BUFMAX];      // scratch buffers
  881.  
  882.     SymbolToCharacter(lpSyv, BUFMAX,        // convert symbol string to
  883.         buff2, NULL);                       // char string and display it
  884.     wsprintf(buff1, "Translation #%d is: %s.", ++EnumCount, (LPSTR) buff2);
  885.     DisplayLine(buff1);
  886.     return(TRUE);                           // TRUE to continue enumeration
  887. }
  888.  
  889. //
  890. // SaveResults -- copies the RCRESULT structure to local storage, 
  891. // creates copies of the SYE and SYC arrays in global memory blocks,
  892. // and creates a duplicate pen data header block.  This allows all of
  893. // the pen result data to be accessed outside the WM_RCRESULT processing.
  894. //
  895. void SaveResults(LONG lParam)
  896. {
  897.     LPSYE lpSye;                            // temp ptr to SYE array
  898.     LPSYC lpSyc;                            // temp ptr to SYC array
  899.     int i;                                  // scratch variable
  900.  
  901.     if(hSye)                                // free old data if necessary
  902.     {                                       
  903.         GlobalUnlock(hSye);                 // unlock SYE and SYC blocks
  904.         GlobalUnlock(hSyc);
  905.         GlobalFree(hSye);                   // release SYE and SYC blocks
  906.         GlobalFree(hSyc);
  907.         DestroyPenData(rcresult.hpendata);  // release ink data block   
  908.     }
  909.  
  910.     rcresult = *(LPRCRESULT) lParam;        // make local copy of RCRESULT
  911.  
  912.     hSye = GlobalAlloc(GMEM_MOVEABLE,       // allocate memory block for 
  913.         (rcresult.syg.cSye * sizeof(SYE))); // copy of SYE array
  914.     hSyc = GlobalAlloc(GMEM_MOVEABLE,       // allocate memory block for 
  915.         (rcresult.syg.cSyc * sizeof(SYC))); // copy of SYC array
  916.     lpSye = (LPSYE) GlobalLock(hSye);       // lock down the blocks
  917.     lpSyc = (LPSYC) GlobalLock(hSyc);       // and get far pointers
  918.  
  919.     for(i = 0; i < rcresult.syg.cSye; i++)  // copy SYE array to our
  920.         lpSye[i] = rcresult.syg.lpsye[i];   // own memory block
  921.     
  922.     for(i = 0; i < rcresult.syg.cSyc; i++)  // copy SYC array to our
  923.         lpSyc[i] = rcresult.syg.lpsyc[i];   // own memory block
  924.  
  925.     rcresult.syg.lpsye = lpSye;             // update pointers in
  926.     rcresult.syg.lpsyc = lpSyc;             // local RCRESULT structure
  927.  
  928.     rcresult.hpendata =                     // make copy of ink data 
  929.         DuplicatePenData(rcresult.hpendata, GMEM_MOVEABLE);
  930. }
  931.  
  932.  
  933. 
  934.