home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1992
/
09
/
demo8.c
< prev
next >
Wrap
Text File
|
1992-02-29
|
40KB
|
934 lines
// DEMO8.C --- Pen-centric Windows application that accepts
// handwritten input, then displays various
// information from the RCRESULT structure.
// Copyright (C) 1992 Ray Duncan
#define WIN31
#define dim(x) (sizeof(x) / sizeof(x[0])) // returns no. of elements
#define BUFMAX 80 // size of scratch buffers
#include "windows.h"
#include "penwin.h"
#include "demo8.h"
HANDLE hInst; // instance handle
HWND hWndFrame = 0; // frame window handle
HWND hWndText = 0; // child text window handle
HWND hWndWrite = 0; // child writing window handle
HANDLE hPenWin = 0; // Pen Windows module handle
HDC hdc; // device context
int CharX = 0; // average char width
int CharY = 0; // char height
int CurLine = 0; // current line number
int MaxLine = 0; // lines per window
int EnumCount = 0; // translation counter
int DisplayMode = IDM_RCRESULT; // current display format
char szFrameClass[] = "DemoFrameClass"; // name of frame window class
char szTextClass[] = "DemoTextClass"; // child text window class
char szWriteClass[] = "DemoWriteClass"; // child writing window class
HANDLE hSye = 0; // handle for copy of SYE array
HANDLE hSyc = 0; // handle for copy of SYC array
RCRESULT rcresult; // local copy of RCRESULT
REC recResult = -1; // status from Recognize()
RC rc; // recognition context
struct decodeInt { // simple structure to
int Code; // associate integer values
char * Name; }; // with character strings
struct decodeLong { // simple structure to
long Code; // associate long values
char * Name; }; // with character strings
struct decodeSYV { // simple structure to
SYV Code; // associate SYV values
char * Name; }; // with character strings
struct decodeInt recogResults[] = { // values returned by
REC_OK, "REC_OK", // Recognize() function
REC_ABORT, "REC_ABORT",
REC_ALC, "REC_ALC",
REC_BADEVENTREF, "REC_BADEVENTREF",
REC_BADHPENDATA, "REC_BADHPENDATA",
REC_BUFFERTOOSMALL, "REC_BUFFERTOOSMALL",
REC_BUSY, "REC_BUSY",
REC_CLVERIFY, "REC_CLVERIFY",
REC_DICT, "REC_DICT",
REC_DONE, "REC_DONE",
REC_ERRORLEVEL, "REC_ERRORLEVEL",
REC_GUIDE, "REC_GUIDE",
REC_HREC, "REC_HREC",
REC_HWND, "REC_HWND",
REC_INVALIDREF, "REC_INVALIDREF",
REC_LANGUAGE, "REC_LANGUAGE",
REC_NOCOLLECTION, "REC_NOCOLLECTION",
REC_NOINPUT, "REC_NOINPUT",
REC_NOTABLET, "REC_NOTABLET",
REC_OEM, "REC_OEM",
REC_OOM, "REC_OOM",
REC_OVERFLOW, "REC_OVERFLOW",
REC_PARAMERROR, "REC_PARAMERROR",
REC_PCM, "REC_PCM",
REC_POINTEREVENT, "REC_POINTEREVENT",
REC_RECTEXCLUDE, "REC_RECTEXCLUDE",
REC_RECTBOUND, "REC_RECTBOUND",
REC_RESULTMODE, "REC_RESULTMODE",
REC_TERMBOUND, "REC_TERMBOUND",
REC_TERMEX, "REC_TERMEX",
REC_TERMOEM, "REC_TERMOEM",
REC_TERMPENUP, "REC_TERMPENUP",
REC_TERMRANGE, "REC_TERMRANGE",
REC_TERMTIMEOUT, "REC_TERMTIMEOUT", } ;
struct decodeInt rctypeResults[] = { // RCRESULT data types
RCRT_UNIDENTIFIED, "RCRT_UNIDENTIFIED",
RCRT_GESTURE, "RCRT_GESTURE",
RCRT_NOSYMBOLMATCH, "RCRT_NOSYMBOLMATCH",
RCRT_PRIVATE, "RCRT_PRIVATE",
RCRT_NORECOG, "RCRT_NORECOG",
RCRT_ALREADYPROCESSED, "RCRT_ALREADYPROCESSED",
RCRT_GESTURETRANSLATED, "RCRT_GESTURETRANSLATED",
RCRT_GESTURETOKEYS, "RCRT_GESTURETOKEYS", } ;
struct decodeInt pdtsScale[] = { // PENDATAHEADER structure
PDTS_ARBITRARY, "PDTS_ARBITRARY", // PDTS_XXXX scale field
PDTS_DISPLAY, "PDTS_DISPLAY",
PDTS_HIENGLISH, "PDTS_HIENGLISH",
PDTS_HIMETRIC, "PDTS_HIMETRIC",
PDTS_LOMETRIC, "PDTS_LOMETRIC",
PDTS_SCALEMAX, "PDTS_SCALEMAX", } ;
struct decodeInt pdtsBits[] = { // PENDATAHEADER structure
PDTS_COMPRESSED, "PDTS_COMPRESSED", // other PDTS_xxx bits
PDTS_COMPRESSMETHOD, "PDTS_COMPRESSMETHOD",
PDTS_COMPRESS2NDDERIV, "PDTS_COMPRESS2NDDERIV",
PDTS_NOCOLINEAR, "PDTS_NOCOLINEAR",
PDTS_NOOEMDATA, "PDTS_NOOEMDATA",
PDTS_NOPENINFO, "PDTS_NOPENINFO",
PDTS_NOUPPOINTS, "PDTS_NOUPPOINTS", } ;
struct decodeLong pdcBits[] = { // PENINFO structure
PDC_BARREL1, "PDC_BARREL1", // PDC_xxx bits
PDC_BARREL2, "PDC_BARREL2",
PDC_BARREL3, "PDC_BARREL3",
PDC_INTEGRATED, "PDC_INTEGRATED",
PDC_INVERT, "PDC_INVERT",
PDC_PROXIMITY, "PDC_PROXIMITY",
PDC_RANGE, "PDC_RANGE",
PDC_RELATIVE, "PDC_RELATIVE", } ;
struct decodeSYV syvSystemValue[] = { // system values for SYVs
SYV_BEGINOR, "SYV_BEGINOR",
SYV_EMPTY, "SYV_EMPTY",
SYV_ENDOR, "SYV_ENDOR",
SYV_NULL, "SYV_NULL",
SYV_OR, "SYV_OR",
SYV_SOFTNEWLINE, "SYV_SOFTNEWLINE",
SYV_UNKNOWN, "SYV_UNKNOWN", } ;
struct decodeSYV syvGestureValue[] = { // gesture values for SYVs
SYV_BACKSPACE, "SYV_BACKSPACE",
SYV_CLEAR, "SYV_CLEAR",
SYV_CLEARWORD, "SYV_CLEARWORD",
SYV_COPY, "SYV_COPY",
SYV_CORRECT, "SYV_CORRECT",
SYV_CUT, "SYV_CUT",
SYV_EXTENDSELECT, "SYV_EXTENDSELECT",
SYV_PASTE, "SYV_PASTE",
SYV_RETURN, "SYV_RETURN",
SYV_SPACE, "SYV_SPACE",
SYV_TAB, "SYV_TAB",
SYV_UNDO, "SYV_UNDO",
SYV_USER, "SYV_USER", } ;
//
// WinMain --- entry point from Windows. Registers window classes,
// creates windows, registers pen app, and processes messages until
// WM_QUIT received.
//
int PASCAL WinMain(HANDLE hInstance,
HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
hInst = hInstance; // save this instance handle
if(!hPrevInstance) // if first instance,
if(!InitApplication(hInstance)) // register window class
return(FALSE); // exit if couldn't register
if(!InitInstance(hInstance, nCmdShow)) // create this instance's window
{
MessageBox(0, "Initialization failed!", "DEMO8", MB_OK|MB_ICONSTOP);
return(FALSE);
}
RegisterPenApp(RPA_DEFAULT, TRUE); // enable HEDIT/BEDIT controls
while(GetMessage(&msg, NULL, 0, 0)) // while message != WM_QUIT
{
TranslateMessage(&msg); // translate virtual key codes
DispatchMessage(&msg); // dispatch message to window
}
return(msg.wParam); // return code = WM_QUIT value
}
//
// InitApplication --- registers window classes for this application
//
BOOL InitApplication(HANDLE hInstance)
{
WNDCLASS wc;
BOOL bParent;
BOOL bText;
BOOL bWrite;
// set parameters for frame window class
wc.style = CS_HREDRAW | CS_VREDRAW; // class style
wc.lpfnWndProc = FrameWndProc; // class callback function
wc.cbClsExtra = 0; // extra per-class data
wc.cbWndExtra = 0; // extra per-window data
wc.hInstance = hInstance; // handle of class owner
wc.hIcon = LoadIcon(hInst, "penicon"); // pendemo.ico icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // default cursor
wc.hbrBackground = GetStockObject(WHITE_BRUSH); // background color
wc.lpszMenuName = "DemoMenu"; // name of menu resource
wc.lpszClassName = szFrameClass; // name of window class
bParent = RegisterClass(&wc); // register frame window class
// set parameters for text output child window class
wc.lpfnWndProc = TextWndProc; // class callback function
wc.hIcon = NULL; // default icon
wc.lpszMenuName = NULL; // name of menu resource
wc.lpszClassName = szTextClass; // name of window class
bText = RegisterClass(&wc); // register text child class
// set parameters for writing input child window class
wc.lpfnWndProc = WriteWndProc; // class callback function
wc.lpszClassName = szWriteClass; // name of window class
bWrite = RegisterClass(&wc); // register writing child class
return(bParent && bText && bWrite); // return success/failure flag
}
//
// InitInstance --- creates frame window for this application instance
//
BOOL InitInstance(HANDLE hInstance, int nCmdShow)
{
hWndFrame = CreateWindow( // create frame window
szFrameClass, // window class name
"Pen Windows Demo #8", // text for title bar
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, CW_USEDEFAULT, // default position
CW_USEDEFAULT, CW_USEDEFAULT, // default size
NULL, // no parent window
NULL, // use class default menu
hInstance, // window owner
NULL // unused pointer
);
if(!hWndFrame) return(FALSE); // error, can't create window
ShowWindow(hWndFrame, nCmdShow); // make frame window visible
UpdateWindow(hWndFrame); // force WM_PAINT message
return(TRUE); // return success flag
}
//
// FrameWndProc --- callback function for application frame window
//
long FAR PASCAL FrameWndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
{
switch (wMsg)
{
case WM_CREATE: // creating frame window
hWndText = CreateWindow( // create child text window
szTextClass, // window class name
NULL, // text for title bar
WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER, // style
0, 0, 0, 0, // position and size
hWnd, // frame window is parent
0, // child window identifier
hInst, // window owner
NULL); // unused pointer
hWndWrite = CreateWindow( // create child writing window
szWriteClass, // window class name
NULL, // text for title bar
WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER, // style
0, 0, 0, 0, // position and size
hWnd, // frame window is parent
0, // child window identifier
hInst, // window owner
NULL); // unused pointer
break;
case WM_SIZE: // resize & position children:
MoveWindow(hWndWrite, // writing input window
0, 0, LOWORD(lParam)/2, HIWORD(lParam), TRUE);
MoveWindow(hWndText, // text output window
LOWORD(lParam)/2, 0, LOWORD(lParam)/2, HIWORD(lParam), TRUE);
return(0);
case WM_COMMAND: // menu command received,
DoCommand(hWnd, wParam); // decode it
break;
case WM_DESTROY: // window being destroyed
PostQuitMessage(0); // force WM_QUIT message
break;
default: // let Windows handle it
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
return(0);
}
//
// TextWndProc --- callback function for child text window
//
long FAR PASCAL TextWndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
{
TEXTMETRIC tm; // receives font characteristics
PAINTSTRUCT ps; // painting info structure
char buff1[BUFMAX]; // scratch buffer
int i; // scratch variable
switch(wMsg)
{
case WM_CREATE: // creating text child window
hdc = GetDC(hWnd); // get device context
GetTextMetrics(hdc, &tm); // get text metrics
CharX = tm.tmAveCharWidth; // save character size
CharY = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hWnd, hdc); // release device context
return(0);
case WM_SIZE: // resize/position in progress
CurLine = 0; // reset current line number
MaxLine = HIWORD(lParam)/CharY; // no. of lines in window
return(0);
case WM_PAINT: // time to repaint window
if(recResult == -1) // bail out if no result
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
hdc = BeginPaint(hWnd, &ps); // get device context
switch(DisplayMode) // display results
{
case IDM_RCRESULT: // RCRESULT data structure
ShowRCResult(&rcresult);
break;
case IDM_SYMGRAPH: // symbol graph
ShowSymbolGraph(&rcresult);
break;
case IDM_SYMSTRINGS: // candidate symbol strings
ShowSymbolStrings(&rcresult);
break;
case IDM_PENDATAHEADER: // PENDATAHEADER structure
ShowPenDataHeader(&rcresult);
break;
case IDM_PENINFO: // PENINFO structure
ShowPenInfo(&rcresult);
break;
case IDM_PENSTROKES: // individual pen strokes
ShowPenStrokes(&rcresult);
break;
case IDM_PENINK: // scale and redraw ink
ShowPenInk(&rcresult);
break;
}
EndPaint(hWnd, &ps); // release device context
break;
default:
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
}
//
// WriteWndProc --- callback function for child writing window
//
long FAR PASCAL WriteWndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
{
PAINTSTRUCT ps; // painting info structure
RECT rect; // receives client rectangle
switch(wMsg)
{
case WM_PAINT: // window needs repainting
hdc = BeginPaint(hWnd, &ps); // get device context
GetClientRect(hWnd, &rect); // get client rectangle
DrawText(hdc, // put legend in writing area
"Writing Area", -1, &rect,
DT_CENTER | DT_TOP | DT_SINGLELINE);
EndPaint(hWnd, &ps); // release device context
break;
case WM_LBUTTONDOWN: // "pen-down" in writing area
if(IsPenEvent(wMsg, GetMessageExtraInfo()))
{
InvalidateRect(hWnd, NULL, TRUE); // erase input window
UpdateWindow(hWnd);
InitRC(hWndWrite, &rc); // set default RC values
rc.hwnd = hWnd; // this window gets the results
rc.rglpdf[0] = NULL; // assume no dictionary
recResult = Recognize(&rc); // request pen input
CurLine = 0; // reset line number for output
InvalidateRect(hWndText, NULL, TRUE);
UpdateWindow(hWndText); // force repaint of output window
};
return(0);
case WM_RCRESULT: // recognition results arriving
SaveResults(lParam); // save copy of results
return(0);
default:
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
}
//
// ShowRCResult -- displays contents of RCRESULT data structure
//
void ShowRCResult(LPRCRESULT rcresult)
{
char buff1[BUFMAX], buff2[BUFMAX]; // scratch buffers
int i; // scratch variable
strcpy(buff1, "Recognize result: unknown.");
for(i = 0; i < dim(recogResults); i++)
{ // decode Recognize() value
if(recogResults[i].Code == recResult)
wsprintf(buff1, "Recognize result: %s.",
(LPSTR) recogResults[i].Name);
}
DisplayLine(buff1); // display Recognize() status
wsprintf(buff1, "rcresult.syg.cHotSpot = %0d", rcresult->syg.cHotSpot);
DisplayLine(buff1); // number of valid hot spots
wsprintf(buff1, "rcresult.syg.nFirstBox = %0d", rcresult->syg.nFirstBox);
DisplayLine(buff1); // box index, first result char
wsprintf(buff1, "rcresult.syg.lpsye = %04X:%04Xh",
HIWORD(rcresult->syg.lpsye), LOWORD(rcresult->syg.lpsye));
DisplayLine(buff1); // pointer to SYE nodes
wsprintf(buff1, "rcresult.syg.cSye = %0d", rcresult->syg.cSye);
DisplayLine(buff1); // no. of SYEs in symbol graph
wsprintf(buff1, "rcresult.syg.lpsyc = %04X:%04Xh",
HIWORD(rcresult->syg.lpsyc), LOWORD(rcresult->syg.lpsyc));
DisplayLine(buff1); // pointer to SYC nodes
wsprintf(buff1, "rcresult.syg.cSyc = %0d", rcresult->syg.cSyc);
DisplayLine(buff1); // number of SYCs
if(rcresult->wResultsType == RCRT_DEFAULT) // decode result type
DisplayLine("rcresult.wResultsType = RCRT_DEFAULT");
else // if not RCRT_DEFAULT,
{ // check each possible flag
for(i = 0; i < dim(rctypeResults); i++)
{
if(rctypeResults[i].Code & rcresult->wResultsType)
{
wsprintf(buff1, "rcresult.wResultsType = %s",
(LPSTR) rctypeResults[i].Name);
DisplayLine(buff1);
}
}
}
wsprintf(buff1, "rcresult.cSyv = %d", rcresult->cSyv);
DisplayLine(buff1); // number of symbols
FirstSymbolFromGraph(&rcresult->syg, (LPSYV) buff1, BUFMAX, &i);
SymbolToCharacter((LPSYV) buff1, BUFMAX, buff2, NULL);
wsprintf(buff1, "rcresult.lpsyv -> %s", (LPSTR) buff2);
DisplayLine(buff1); // best bet translated string
wsprintf(buff1, "rcresult.nBaseLine = %0d", rcresult->nBaseLine);
DisplayLine(buff1); // baseline of written input
wsprintf(buff1, "rcresult.nMidLine = %0d", rcresult->nMidLine);
DisplayLine(buff1); // midline of written input
wsprintf(buff1, "rcresult.hpendata = %04Xh", rcresult->hpendata);
DisplayLine(buff1); // pen data memory block handle
wsprintf(buff1, "rcresult.rectBoundInk = (%d,%d)-(%d,%d)",
rcresult->rectBoundInk.left, rcresult->rectBoundInk.top,
rcresult->rectBoundInk.right, rcresult->rectBoundInk.bottom);
DisplayLine(buff1); // bounding rectangle for ink
wsprintf(buff1, "rcresult.pntEnd = (%d,%d)",
rcresult->pntEnd.x, rcresult->pntEnd.y);
DisplayLine(buff1); // recognition termination point
wsprintf(buff1, "rcresult.lprc = %04X:%04Xh",
HIWORD(rcresult->lprc), LOWORD(rcresult->lprc));
DisplayLine(buff1); // address of RC structure
}
//
// ShowSymbolStrings -- enumerates and displays candidate symbol strings
//
void ShowSymbolStrings(LPRCRESULT rcresult)
{
FARPROC lpProc; // far pointer for callback
char buff1[BUFMAX]; // scratch buffer
wsprintf(buff1, "Symbol graph has %d possible translations.",
GetSymbolCount(&(rcresult->syg)));
DisplayLine(buff1); // display no. of candidates
EnumCount = 0; // then display each candidate
lpProc = MakeProcInstance(EnumFunc, hInst);
EnumSymbols(&(rcresult->syg), 1000, lpProc, NULL);
FreeProcInstance(lpProc);
}
//
// ShowSymbolGraph -- displays contents of symbol graph
//
void ShowSymbolGraph(LPRCRESULT rcresult)
{
LPSYE lpSye = rcresult->syg.lpsye; // first symbol element
int cSye = rcresult->syg.cSye; // no. of symbol elements
int Level = 0; // SYV_BEGINOR nesting level
SYV syv; // current symbol value
char syvChar; // current character
int syvCl; // current confidence level
int syvType; // current symbol type
char buff1[BUFMAX], buff2[BUFMAX]; // scratch buffers
int i, j; // scratch variable
char * p; // scratch pointer
FirstSymbolFromGraph(&rcresult->syg, (LPSYV) buff1, BUFMAX, &i);
SymbolToCharacter((LPSYV) buff1, BUFMAX, buff2, NULL);
wsprintf(buff1, "Preferred translation: %s", (LPSTR) buff2);
DisplayLine(buff1); // best bet translated string
DisplayLine("Start of symbol graph:"); // now dump the symbol graph
for(i = 0; i < cSye; i++)
{
syv = lpSye[i].syv; // get current symbol value
syvType = HIWORD(syv); // extract symbol type
syvChar = ChSyvToAnsi(syv); // extract character if any
syvCl = lpSye[i].cl; // get confidence level
switch(syvType) // format according to type
{
case(SYVHI_SPECIAL): // SYV system values
if(syv == SYV_BEGINOR) // start of char. choice list
{
if(Level) // if stuff already waiting
DisplayLine(buff1); // in buffer, display it
p = buff1 + wsprintf(buff1, "{ ");
Level++; // count nesting levels
}
else if(syv == SYV_OR) // choice list separator
{
p += wsprintf(p, " | ");
}
else if(syv == SYV_ENDOR) // end of char. choice list
{
wsprintf(p, " }");
DisplayLine(buff1); // display choice list
p = buff1;
Level--; // count nesting levels
}
else // decode & display all
{ // other system SYV values
for(j = 0; j < dim(syvSystemValue); j++)
{
if(syvSystemValue[j].Code == syv)
DisplayLine(syvSystemValue[j].Name);
}
}
break;
case(SYVHI_ANSI): // SYV ASCII characters
if(syv == SYV_SPACENULL) // format char. & conf. level
wsprintf(buff2, "NO SPACE [%d%%]", syvCl);
else if(syvChar == ' ')
wsprintf(buff2, "SPACE [%d%%]", syvCl);
else if(syvChar < ' ')
wsprintf(buff2, "%02Xh [%d%%]", syvChar, syvCl);
else
wsprintf(buff2, "%c [%d%%]", syvChar, syvCl);
if(Level) // within char. choice list?
p += wsprintf(p, "%s", (LPSTR) buff2); // yes, append
else // no, display text now
DisplayLine(buff2);
break;
case(SYVHI_GESTURE): // SYV gestures
for(j = 0; j < dim(syvGestureValue); j++)
{ // decode gesture value
if(syvGestureValue[j].Code == syv)
{ // found match, display it
DisplayLine(syvGestureValue[j].Name);
break;
}
if(j == dim(syvGestureValue))
{ // no match, show hex value
wsprintf(buff1, "gesture: %08lXh", syv);
DisplayLine(buff1);
}
}
break;
case(SYVHI_KANJI): // Kanji
case(SYVHI_SHAPE): // shapes
case(SYVHI_UNICODE): // Unicode
case(SYVHI_VKEY): // virtual keys
default: // whatever else
wsprintf(buff1, "type %d: %08lXh", syvType, syv);
DisplayLine(buff1);
}
}
DisplayLine("End of symbol graph.");
}
//
// ShowPenDataHeader -- displays PENDATAHEADER structure
//
void ShowPenDataHeader(LPRCRESULT rcresult)
{
PENDATAHEADER pdh; // pen data header
char buff1[BUFMAX]; // scratch buffer
int i; // scratch variable
GetPenDataInfo(rcresult->hpendata, &pdh, NULL, 0L);
wsprintf(buff1, "pendataheader.wVersion = %d", pdh.wVersion);
DisplayLine(buff1); // pen data format version
wsprintf(buff1, "pendataheader.cbSizeUsed = %u", pdh.cbSizeUsed);
DisplayLine(buff1); // size of pen data in bytes
wsprintf(buff1, "pendataheader.cStrokes = %u", pdh.cStrokes);
DisplayLine(buff1); // number of pen strokes
wsprintf(buff1, "pendataheader.cPnt = %u", pdh.cPnt);
DisplayLine(buff1); // number of points
wsprintf(buff1, "pendataheader.cPntStrokeMax = %u", pdh.cPntStrokeMax);
DisplayLine(buff1); // points in longest stroke
wsprintf(buff1, "pendataheader.rectBound = (%d,%d)-(%d,%d)",
pdh.rectBound.left, pdh.rectBound.top,
pdh.rectBound.right, pdh.rectBound.bottom);
DisplayLine(buff1); // bounding rect down points
wsprintf(buff1, "pendataheader.wPndts = %Xh", pdh.wPndts);
DisplayLine(buff1); // state of PDTS_xxx bits
for(i = 0; i < dim(pdtsScale); i++) // decode PDTS_ scaling field
{
if(pdtsScale[i].Code == (PDTS_SCALEMASK & pdh.wPndts))
{
wsprintf(buff1, "pendataheader.wPndts = %s",
(LPSTR) pdtsScale[i].Name);
DisplayLine(buff1);
}
}
for(i = 0; i < dim(pdtsBits); i++) // decode PDTS_xxx bits
{
if(pdtsBits[i].Code & pdh.wPndts)
{
wsprintf(buff1, "pendataheader.wPndts = %s",
(LPSTR) pdtsBits[i].Name);
DisplayLine(buff1);
}
}
wsprintf(buff1, "pendataheader.nInkWidth = %d", pdh.nInkWidth);
DisplayLine(buff1); // ink width
wsprintf(buff1, "pendataheader.rgbInk = %08lXh", pdh.rgbInk);
DisplayLine(buff1); // ink color
}
//
// ShowPenInfo -- displays PENINFO structure
//
void ShowPenInfo(LPRCRESULT rcresult)
{
PENDATAHEADER pdh; // pen data header
PENINFO peninfo; // pen info structure
char buff1[BUFMAX]; // scratch buffer
int i; // scratch variable
GetPenDataInfo(rcresult->hpendata, &pdh, &peninfo, 0L);
wsprintf(buff1, "peninfo.cxRawWidth = %u", peninfo.cxRawWidth);
DisplayLine(buff1); // width in 0.001 inches
wsprintf(buff1, "peninfo.cyRawHeight = %u", peninfo.cyRawHeight);
DisplayLine(buff1); // height in 0.001 inches
wsprintf(buff1, "peninfo.wDistinctWidth = %u", peninfo.wDistinctWidth);
DisplayLine(buff1); // width in distinct X values
wsprintf(buff1, "peninfo.wDistinctHeight = %u", peninfo.wDistinctHeight);
DisplayLine(buff1); // height in distinct Y values
wsprintf(buff1, "peninfo.nSamplingRate = %d", peninfo.nSamplingRate);
DisplayLine(buff1); // samples per second
wsprintf(buff1, "peninfo.nSamplingDist = %d", peninfo.nSamplingDist);
DisplayLine(buff1); // minimum distance per event
wsprintf(buff1, "peninfo.lPdc = %08lXh", peninfo.lPdc);
DisplayLine(buff1); // pen device capabilities
for(i = 0; i < dim(pdcBits); i++) // decode PDC_xxxx bits
{
if(pdcBits[i].Code & peninfo.lPdc)
{
wsprintf(buff1, "peninfo.lPdc = %s",
(LPSTR) pdcBits[i].Name);
DisplayLine(buff1);
}
}
wsprintf(buff1, "peninfo.cPens = %d", peninfo.cPens);
DisplayLine(buff1); // number of pens supported
wsprintf(buff1, "peninfo.cbOemData = %d", peninfo.cbOemData);
DisplayLine(buff1); // width of OEM data packet
}
//
// ShowPenStrokes -- displays STROKEINFO structures
//
void ShowPenStrokes(LPRCRESULT rcresult)
{
PENDATAHEADER pdh; // pen data header
STROKEINFO strokeinfo; // stroke information
LPPENDATA lpPenData; // far pointer to pen data
LPPOINT lpPoint; // far pointer to POINT list
char buff1[BUFMAX]; // scratch buffer
int i; // scratch variable
GetPenDataInfo(rcresult->hpendata, &pdh, NULL, 0L); // get PENDATAHEADER
lpPenData = BeginEnumStrokes(rcresult->hpendata); // lock pen data
DisplayLine("Stroke Points State TimeStamp");
for(i = 0; i < pdh.cStrokes; i++)
{ // get info for this stroke
GetPenDataStroke(lpPenData, i, &lpPoint, NULL, &strokeinfo);
wsprintf(buff1, " %03d %05u %04Xh %09ld",
i, // stroke number
strokeinfo.cPnt, // points in stroke
strokeinfo.wPdk, // state of stroke
strokeinfo.dwTick); // timestamp of stroke
DisplayLine(buff1);
}
EndEnumStrokes(rcresult->hpendata); // unlock pen data
}
//
// ShowPenInk -- redraws original ink in right-hand window
//
void ShowPenInk(LPRCRESULT rcresult)
{
PENDATAHEADER pdh; // pen data header
HPENDATA hpendata; // duplicate ink handle
LPPENDATA lpPenData; // far pointer to pen data
char buff1[BUFMAX]; // scratch buffer for output
RECT rect; // client rect for output win
GetClientRect(hWndText, &rect); // get client rectangle
rect.left += 10; // calculate bounding
rect.right += -10; // rectangle for redrawn ink
rect.top += ((rect.bottom-rect.top)/2) + 10;
rect.bottom += -10;
// duplicate original ink in a new PENDATA memory block
hpendata = DuplicatePenData(rcresult->hpendata, GMEM_MOVEABLE);
// get PENDATAHEADER for duplicated ink memory block
GetPenDataInfo(hpendata, &pdh, NULL, 0L);
// display total strokes and points from PENDATAHEADER
wsprintf(buff1, "Strokes = %u", pdh.cStrokes);
DisplayLine(buff1);
wsprintf(buff1, "Points = %u", pdh.cPnt);
DisplayLine(buff1);
// display original bounding rectangle from PENDATAHEADER
DisplayLine("Bounding rectangles:");
wsprintf(buff1, "Original = (%d,%d)-(%d,%d)",
pdh.rectBound.left, pdh.rectBound.top,
pdh.rectBound.right, pdh.rectBound.bottom);
DisplayLine(buff1);
// rescale pen data points for display
MetricScalePenData(hpendata, PDTS_DISPLAY);
// display rescaled bounding rectangle from PENDATAHEADER
GetPenDataInfo(hpendata, &pdh, NULL, 0L);
wsprintf(buff1, "Rescaled = (%d,%d)-(%d,%d)",
pdh.rectBound.left, pdh.rectBound.top,
pdh.rectBound.right, pdh.rectBound.bottom);
DisplayLine(buff1);
// resize pen data to fit in lower half of output window
ResizePenData(hpendata, &rect);
// display resized bounding rectangle from PENDATAHEADER
GetPenDataInfo(hpendata, &pdh, NULL, 0L);
wsprintf(buff1, "Resized = (%d,%d)-(%d,%d)",
pdh.rectBound.left, pdh.rectBound.top,
pdh.rectBound.right, pdh.rectBound.bottom);
DisplayLine(buff1);
// draw a frame for the ink in lower half of output window
Rectangle(hdc, rect.left-2, rect.top-2, rect.right+2,rect.bottom+2);
// redraw ink within the frame
DrawPenData(hdc, NULL, hpendata);
DestroyPenData(hpendata); // release duplicate ink block
}
//
// DisplayLine --- displays a string in the text output child window
//
void DisplayLine(char * szOut)
{
RECT rect;
if(CurLine == MaxLine) // at bottom of window?
return; // yes, bail out
GetClientRect(hWndText, &rect); // get client rectangle
TextOut(hdc, 0, CurLine * CharY, // display text in window
szOut, strlen(szOut));
CurLine++; // move to next line
return;
}
//
// DoCommand --- handles menu command messages for the frame window
//
void DoCommand(HWND hWnd, WORD wParam)
{
FARPROC lpProc; // far pointer to callback
HMENU hMenu;
switch(wParam) // decode it
{
case IDM_EXIT: // user picked File-Quit
SendMessage (hWnd, WM_CLOSE, 0, 0L);
break;
case IDM_RCRESULT: // user picked a display
case IDM_SYMGRAPH: // format, save it and
case IDM_SYMSTRINGS: // check/uncheck menu items,
case IDM_PENDATAHEADER: // then reset line number
case IDM_PENINFO: // for output window and
case IDM_PENSTROKES: // force repaint of window
case IDM_PENINK:
hMenu = GetMenu(hWnd);
CheckMenuItem(hMenu, DisplayMode, MF_UNCHECKED);
DisplayMode = wParam;
CheckMenuItem(hMenu, DisplayMode, MF_CHECKED);
CurLine = 0;
InvalidateRect(hWndText, NULL, TRUE);
UpdateWindow(hWndText);
break;
default: // unknown command, ignore it
break;
}
}
//
// EnumFunc --- the callback function for EnumSymbols(). During
// evaluation of a symbol graph, this function is entered
// repetitively with a pointer to each candidate symbol array.
// The symbol array is translated to a character string and displayed.
//
int FAR PASCAL EnumFunc(LPSYV lpSyv, int cSyv, VOID FAR * lpData)
{
char buff1[BUFMAX], buff2[BUFMAX]; // scratch buffers
SymbolToCharacter(lpSyv, BUFMAX, // convert symbol string to
buff2, NULL); // char string and display it
wsprintf(buff1, "Translation #%d is: %s.", ++EnumCount, (LPSTR) buff2);
DisplayLine(buff1);
return(TRUE); // TRUE to continue enumeration
}
//
// SaveResults -- copies the RCRESULT structure to local storage,
// creates copies of the SYE and SYC arrays in global memory blocks,
// and creates a duplicate pen data header block. This allows all of
// the pen result data to be accessed outside the WM_RCRESULT processing.
//
void SaveResults(LONG lParam)
{
LPSYE lpSye; // temp ptr to SYE array
LPSYC lpSyc; // temp ptr to SYC array
int i; // scratch variable
if(hSye) // free old data if necessary
{
GlobalUnlock(hSye); // unlock SYE and SYC blocks
GlobalUnlock(hSyc);
GlobalFree(hSye); // release SYE and SYC blocks
GlobalFree(hSyc);
DestroyPenData(rcresult.hpendata); // release ink data block
}
rcresult = *(LPRCRESULT) lParam; // make local copy of RCRESULT
hSye = GlobalAlloc(GMEM_MOVEABLE, // allocate memory block for
(rcresult.syg.cSye * sizeof(SYE))); // copy of SYE array
hSyc = GlobalAlloc(GMEM_MOVEABLE, // allocate memory block for
(rcresult.syg.cSyc * sizeof(SYC))); // copy of SYC array
lpSye = (LPSYE) GlobalLock(hSye); // lock down the blocks
lpSyc = (LPSYC) GlobalLock(hSyc); // and get far pointers
for(i = 0; i < rcresult.syg.cSye; i++) // copy SYE array to our
lpSye[i] = rcresult.syg.lpsye[i]; // own memory block
for(i = 0; i < rcresult.syg.cSyc; i++) // copy SYC array to our
lpSyc[i] = rcresult.syg.lpsyc[i]; // own memory block
rcresult.syg.lpsye = lpSye; // update pointers in
rcresult.syg.lpsyc = lpSyc; // local RCRESULT structure
rcresult.hpendata = // make copy of ink data
DuplicatePenData(rcresult.hpendata, GMEM_MOVEABLE);
}