⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lmidoodler.cpp

📁 SimpleLAP源码的配套设置和调用代码
💻 CPP
字号:

#include <windows.h>
#include "LmiDoodler.h"


//
// Sample password input control.  This code is not essential to implementing a replacement
// password component.
//

// Size of the grid tic marks
#define DOODLER_TICSIZE		4

// Element colors
#define DOODLER_COLORREF_TIC		RGB(0,0,0)
#define DOODLER_COLORREF_SECURE		RGB(204,204,204)
#define DOODLER_COLORREF_INPUT		RGB(0,0,255)
#define DOODLER_COLORREF_FEEDBACK	RGB(255,0,0)

//
// Various internal doodler structures
//
typedef unsigned char	DOODLEDATA[25];

typedef struct
{
	DOODLEDATA	abVectorMap;
	int			nVectors;
	POINT		apMousePoints[64+2];
	POINT		ptLastVertex;
	BOOL		fSecure;
	BOOL		fCapture;
	HPEN		hpen;
	HBRUSH		hbrush;
	int			nExtent;
	int			nHOffset;
	int			nVOffset;

} DOODLER_WINDOW_INFO;

enum DOODLER_VECTOR
{
	up = 0x01,
	northeast = 0x02,
	right = 0x04,
	southeast = 0x08,
	down = 0x10,
	southwest = 0x20,
	left = 0x40,
	northwest = 0x80

};

static const POINT	l_aVectorBias[8] = { {0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1} };



//
// Draw a blank doodle grid.
//
void LmiDoodler_Clear( 
					
	DOODLER_WINDOW_INFO*	pdwi, 
	HDC						hdc, 
	int						nWidth, 
	int						nHeight )
{
	int						nRow, nCol, nExtent;
	POINT					ptLine[2];
	int						nStep = (((nWidth>nHeight)?nHeight:nWidth)-1) >> 2;
	RECT					rc = { 0, 0, nWidth, nHeight };


	// Calculate evenly spaced vertices, then calculate the extent of the control.
	pdwi->nExtent = nExtent = nStep * 4;

	// Center the grid within the client area.
	pdwi->nHOffset = ( nWidth - nExtent ) / 2;
	pdwi->nVOffset = ( nHeight - nExtent ) / 2;

	FillRect( hdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH) );

	for ( nRow = 0; nRow <= nExtent; nRow += nStep )
		for ( nCol = 0; nCol <= nExtent; nCol += nStep )
		{
			ptLine[0].x = nCol + pdwi->nHOffset; // Drawing horizontal tic
			ptLine[0].y = nRow + pdwi->nVOffset;
			ptLine[1].x = nCol + 1 + pdwi->nHOffset;
			ptLine[1].y = nRow + pdwi->nVOffset;

			if ( nCol > 0 )
				ptLine[0].x -= DOODLER_TICSIZE;
			if ( nCol < nExtent )
				ptLine[1].x += DOODLER_TICSIZE;

			Polyline( hdc, ptLine, 2 );

			ptLine[0].x = nCol + pdwi->nHOffset; // Drawing vertical tic
			ptLine[0].y = nRow + pdwi->nVOffset;
			ptLine[1].x = nCol + pdwi->nHOffset;
			ptLine[1].y = nRow + 1 + pdwi->nVOffset;

			if ( nRow > 0 )
				ptLine[0].y -= DOODLER_TICSIZE;
			if ( nRow < nExtent )
				ptLine[1].y += DOODLER_TICSIZE;

			Polyline( hdc, ptLine, 2 );
		}
}



//
// Handle a doodle input point
//
void LmiDoodler_HandlePoint( 
					   
	DOODLER_WINDOW_INFO*	pdwi, 
	POINT					pt )
{
	int						x, y, nStep;
	BYTE					bDirection;


	// Map point to nearest vertex

	nStep = pdwi->nExtent / 4;

	x = ( pt.x - pdwi->nHOffset + ( nStep / 2 ) ) / nStep;
	y = ( pt.y - pdwi->nVOffset + ( nStep / 2 ) ) / nStep;

	// To assist in handling diagonal lines, create a dead spot in the 
	// center area betwixt tics

	if (	abs( x * nStep - ( pt.x - pdwi->nHOffset ) ) > ( nStep / 4 ) &&
			abs( y * nStep - ( pt.y - pdwi->nVOffset ) ) > ( nStep / 4 ) )
		return;

	// First vector point case

	if ( -1 == pdwi->ptLastVertex.x )
	{
		pdwi->ptLastVertex.x = x;
		pdwi->ptLastVertex.y = y;
		return;
	}

	// Record resulting vector

	if ( y == pdwi->ptLastVertex.y ) // maybe horizontal
	{
		if ( x == pdwi->ptLastVertex.x )  // no vector yet
			return;
		else if ( x < pdwi->ptLastVertex.x )
			bDirection = left;
		else // ( x > pdwi->ptLastVertex.x )
			bDirection = right;
	}
	else if ( x == pdwi->ptLastVertex.x ) // maybe vertical
	{
		if ( y == pdwi->ptLastVertex.y ) // no vector yet
			return;
		else if ( y < pdwi->ptLastVertex.y )
			bDirection = up;
		else // ( y > pdwi->ptLastVertex.y )
			bDirection = down;
	}
	else if ( x < pdwi->ptLastVertex.x ) // leftward
	{
		if ( y < pdwi->ptLastVertex.y )
			bDirection = northwest;
		else // ( y > pdwi->ptLastVertex.y )
			bDirection = southwest;
	}
	else // ( x > pdwi->ptLastVertex.x ) // rightward
	{
		if ( y < pdwi->ptLastVertex.y )
			bDirection = northeast;
		else // ( y > pdwi->ptLastVertex.y )
			bDirection = southeast;
	}

	pdwi->abVectorMap[ pdwi->ptLastVertex.y * 5 + pdwi->ptLastVertex.x ] |= bDirection;
	pdwi->ptLastVertex.y = y;
	pdwi->ptLastVertex.x = x;
	pdwi->nVectors++;

}



//
// Render vectors for feedback
//
void LmiDoodler_Render( 
				  
	DOODLER_WINDOW_INFO*	pdwi, 
	HDC						hdc )
{
	int						x, y, d, nStep;
	POINT					pt[2];
	HPEN					hpen = CreatePen( PS_SOLID, 3, DOODLER_COLORREF_FEEDBACK );


	hpen = (HPEN)SelectObject( hdc, hpen );

	nStep = pdwi->nExtent / 4;

	for ( y=0; y<5; y++ )
		for ( x=0; x<5; x++ )
			for ( d=0; d<8; d++ )
			{
				if ( !(pdwi->abVectorMap[y*5+x] & (1<<d)) )
					continue;

				pt[0].x = pt[1].x = x * nStep + pdwi->nHOffset;
				pt[0].y = pt[1].y = y * nStep + pdwi->nVOffset;
				pt[1].x += nStep * l_aVectorBias[d].x;
				pt[1].y += nStep * l_aVectorBias[d].y;

				Polyline( hdc, pt, 2 );
			}

	hpen = (HPEN)SelectObject( hdc, hpen );
	DeleteObject( hpen );
}



//
// Adjust the data to the upper left corner.  This is so the path
// can be doodled for verification independent of where the user
// cares to put the pen down.  Do nothing here and the user will
// have to know exactly which vertex to start on.
//
void LmiDoodler_Normalize( DOODLEDATA* pData )
{
	int		i;

	for ( i=0; (i<25) && (!(*pData)[i]); i++ );

	if ( ( i>=25 ) || ( !i ) )
		return;

	memmove( (*pData), (*pData) + i, 25 - i );
	memset( (*pData) + 25 - i, 0, i );
}


//
// Prevent point from going outside useful area.
//
void LmiDoodler_Constrain( 
						  
	DOODLER_WINDOW_INFO*	pdwi, 
	POINT*					pt )
{

	if ( pt->x < pdwi->nHOffset ) 
		pt->x = pdwi->nHOffset;
	else if ( pt->x > pdwi->nHOffset + pdwi->nExtent )
		pt->x = pdwi->nHOffset + pdwi->nExtent;

	if ( pt->y < pdwi->nVOffset ) 
		pt->y = pdwi->nVOffset;
	else if ( pt->y > pdwi->nVOffset + pdwi->nExtent )
		pt->y = pdwi->nVOffset + pdwi->nExtent;
}



//
// Draw the window and handle doodling
//
LRESULT WINAPI LmiDoodler_WndProc( 
							 
	HWND					hwnd, 
	UINT					uMsg, 
	WPARAM					wParam, 
	LPARAM					lParam )
{
	DOODLER_WINDOW_INFO*	pdwi = (DOODLER_WINDOW_INFO*)GetWindowLong( hwnd, 0 );


	switch( uMsg )
	{
		case WM_CREATE:

			pdwi = (DOODLER_WINDOW_INFO*)LocalAlloc( 0, sizeof(DOODLER_WINDOW_INFO) );
			SetWindowLong( hwnd, 0, (LONG)pdwi );

			pdwi->fSecure = TRUE;
			pdwi->fCapture = FALSE;
			pdwi->hpen = (HPEN)0;
			pdwi->hbrush = (HBRUSH)0;
			pdwi->apMousePoints[0].x = pdwi->apMousePoints[1].x = -1; // Reset input array
			pdwi->ptLastVertex.x = -1;


		case WM_DESTROY:

			if (pdwi->hpen )
				DeleteObject( pdwi->hpen );

			if (pdwi->hbrush)
				DeleteObject( pdwi->hbrush );

			return 0;


		case WM_PAINT:
		{
			PAINTSTRUCT ps;

			//if ( GetUpdateRect( hwnd, 0, FALSE ) )
			{	
				RECT rc;
				HDC hdcPaint = BeginPaint( hwnd, &ps );

				GetClientRect( hwnd, &rc );
				LmiDoodler_Clear( pdwi, hdcPaint, rc.right - rc.left, rc.bottom - rc.top );
				EndPaint( hwnd, &ps );
			}
			return 0;
		}


		case WM_LBUTTONDOWN:
		{
			SetCapture( hwnd );
			pdwi->fCapture = TRUE;
			pdwi->nVectors = 0;

			COLORREF color = pdwi->fSecure ? DOODLER_COLORREF_SECURE : DOODLER_COLORREF_INPUT;
			pdwi->hpen = CreatePen( PS_SOLID, 3, color );
			pdwi->hbrush = CreateSolidBrush( color );

			HDC hdc = GetDC( hwnd );
			HPEN hpenSave = (HPEN)SelectObject( hdc, pdwi->hpen );
			HBRUSH hbrushSave = (HBRUSH)SelectObject( hdc, pdwi->hbrush );
			POINT point = { LOWORD(lParam), HIWORD(lParam) };

			LmiDoodler_Constrain( pdwi, &point );
			pdwi->apMousePoints[1] = point;

			memset( pdwi->abVectorMap, 0, sizeof(DOODLEDATA) );

			Ellipse( hdc, point.x-1, point.y-1, point.x+1, point.y+1 );

			LmiDoodler_HandlePoint( pdwi, point );

			SelectObject( hdc, hpenSave );
			SelectObject( hdc, hbrushSave );
			ReleaseDC( hwnd, hdc );

			return 0;
		}


		case WM_MOUSEMOVE:
		{
			if ( !pdwi->fCapture )
				return 0;

			HDC		hdc = GetDC( hwnd );
			UINT	n, cp;
			HPEN	hpenSave = (HPEN)SelectObject( hdc, pdwi->hpen );


			cp = 0;
			GetMouseMovePoints( &pdwi->apMousePoints[2], 64, &cp );

			for ( n=0; n<cp; n++ )
			{
				pdwi->apMousePoints[2+n].x >>= 2;
				pdwi->apMousePoints[2+n].y >>= 2;
				ScreenToClient( hwnd, &pdwi->apMousePoints[2+n] );

				LmiDoodler_Constrain( pdwi, &pdwi->apMousePoints[2+n] );
				LmiDoodler_HandlePoint( pdwi, pdwi->apMousePoints[2+n] );

			}

			n = 2;

			if ( pdwi->apMousePoints[1].x != -1 )
				cp++, n--;

			if ( pdwi->apMousePoints[0].x != -1 )
				cp++, n--;

			if ( cp > 1 )
				Polyline( hdc, &pdwi->apMousePoints[n], cp );

			pdwi->apMousePoints[0] = pdwi->apMousePoints[n+cp-2];
			pdwi->apMousePoints[1] = pdwi->apMousePoints[n+cp-1];

			SelectObject( hdc, hpenSave );
			ReleaseDC( hwnd, hdc );
			return 0;
		}


		case WM_LBUTTONUP:
		{
			if ( !pdwi->fCapture )
				return 0;

			DeleteObject( pdwi->hpen ); pdwi->hpen = (HPEN)0;
			DeleteObject( pdwi->hbrush ); pdwi->hbrush = (HBRUSH)0;

			pdwi->apMousePoints[0].x = pdwi->apMousePoints[1].x = -1; // Reset input array
			pdwi->ptLastVertex.x = -1;

			SetCapture( (HWND)0 );
			pdwi->fCapture = FALSE;

			HDC hdc = GetDC( hwnd );

			if ( !pdwi->fSecure )
				LmiDoodler_Render( pdwi, hdc );

			ReleaseDC( hwnd, hdc );

			// Let parent know that input is ready.
			SendMessage( GetParent(hwnd), WM_COMMAND, MAKELONG(GetWindowLong(hwnd,GWL_ID),DIN_READY), (LPARAM)hwnd );

			return 0;
		}


		case DIM_CLEAR:

			InvalidateRect( hwnd, 0, FALSE );
			return 0;


		case DIM_GETDATA:
		{
			if ( !pdwi->nVectors )
				return 0;

			DOODLEDATA* pData = (DOODLEDATA*)LocalAlloc( 0, sizeof(DOODLEDATA) );
			memcpy( pData, pdwi->abVectorMap, sizeof(DOODLEDATA) );
			LmiDoodler_Normalize( pData );

			return (LRESULT)pData;
		}


		case DIM_GETDATALEN:

			return sizeof(DOODLEDATA);


		case DIM_SECURE:

			pdwi->fSecure = (BOOL)wParam;
			return 0;


		case DIM_COMPARE:

			if ( !wParam || !lParam )
				return ( (DWORD)wParam == (DWORD)lParam );
			return memcmp( (void*)wParam, (void*)lParam, sizeof(DOODLEDATA) );
	}

	return DefWindowProc( hwnd, uMsg, wParam, lParam );
}



//
// Intialize the control class
//
BOOL LmiDoodler_Init( HINSTANCE hInstance )
{
	WNDCLASS	wc;

	if ( GetClassInfo( GetModuleHandle(0), DOODLER_CLASS, &wc ) )
		return TRUE;

	memset( &wc, 0, sizeof(wc) );
	wc.cbWndExtra = sizeof(DOODLER_WINDOW_INFO*);
	wc.hInstance = GetModuleHandle(0);
	wc.lpfnWndProc = LmiDoodler_WndProc;
	wc.lpszClassName = DOODLER_CLASS;

	return (ATOM)0 != RegisterClass( &wc );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -