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

📄 terminal.c

📁 使用xmodem进行串口通讯的程序
💻 C
字号:
////////////////////////////////////////////////////////////////////////////
//
//	TERMINAL.C	- Written by Mike Sax for Dr. Dobb's Journal
//
//	This file implements a terminal window class "TERMINAL" which you can
//	use to emulate a small tty terminal in a window.  If your application
//	has windows of class "TERMINAL", you should call the InitTerminal
//	function at the beginning of your program (not just for the first
//	instance).
//
//	This file contains one public function:
//
//	BOOL InitTerminal(HANDLE hInstance);  // Return TRUE if success
//
//	To send characters to the terminal window, you can send a TW_SENDCHAR
//	and TW_SENDSTRING messages.  For TW_SENDCHAR, the loword of lParam should
//	contain the character you want to send to the terminal window.	For
//	TW_SENDSTRING lParam should be a long pointer to a null-terminated
//	character-string.
////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <string.h>
#include "terminal.h"

// Exported functions:
LONG FAR PASCAL _export TerminalWndProc(HANDLE hWnd, WORD wMessage,
										WORD wParam, DWORD lParam);

// Static functions:
void static InitFont(void);
void static PositionCaret(HWND hWnd);
void static SendChar(HWND hWnd, int nChar);
int static Handle(WORD wParam, int nOldValue, int maxValue,
						int nTrackPosition);

// Global variables:
static char *gszClass = "TERMINAL";
static HFONT ghFont;	// Handle of terminal font
static int gcxFont; 	// Width of terminal font
static int gcyFont; 	// Height of terminal font

// Set "OEM-font" global variables: ghFont, gxFont, gyFont
void static InitFont(void)
	{

	HDC hDC;
	TEXTMETRIC tm;

	ghFont = GetStockObject(OEM_FIXED_FONT);
	hDC = GetDC(NULL);
	SelectObject(hDC, ghFont);
	GetTextMetrics(hDC, &tm);
	ReleaseDC(NULL, hDC);
	gcxFont = tm.tmMaxCharWidth;
	gcyFont = tm.tmHeight;
	}

// This function should be called once for every instance in your program
// Return TRUE if success
BOOL InitTerminal(HANDLE hInstance)
	{
	WNDCLASS wc;

	InitFont();
	// If the terminal class was registered by a previous instance, we can
	// return success
	if (GetClassInfo(hInstance, gszClass, &wc))
		return TRUE;
	wc.style = 0;
	wc.lpfnWndProc = TerminalWndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = sizeof(HTERMINAL);
	wc.hInstance = hInstance;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = gszClass;
	return RegisterClass(&wc);
	}

// Position the caret in the window IMPORTANT: This function should only be
// called when the window has the input focus!
void static PositionCaret(HWND hWnd)
	{
	HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
	NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);

	if (NULL == npTerminal)
		return; 	// Abort function
	SetCaretPos(gcxFont * (npTerminal->xCursor - npTerminal->xOffset),
				gcyFont * (npTerminal->yCursor - npTerminal->yOffset + 1) - 1);
	LocalUnlock(hTerminal);
	}

// Send a character to a terminal window (internal function)
void static SendChar(HWND hWnd, int nChar)
	{
	HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
	NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);

	if (NULL == npTerminal)
		return;				// Abort function
	switch(nChar)
		{
		case '\t':			// Tab
			npTerminal->xCursor += TABSIZE - (npTerminal->xCursor % TABSIZE);
			break;
		case '\r':			// Return
			npTerminal->xCursor = 0;
			break;
		case '\n':			// New line
			npTerminal->yCursor++;
			break;
		case '\a':			// Beep
			MessageBeep(0);
			break;
		case '\xC': 		// Clear screen
			memset(npTerminal->achBuffer[0], ' ', ROWS * COLUMNS);
			npTerminal->xCursor = npTerminal->yCursor = 0;
			InvalidateRect(hWnd, NULL, TRUE);
			break;
		case '\b':			// Backspace
			if (npTerminal->xCursor)
				npTerminal->xCursor--;
			break;
		default:
			{
			HDC hDC;
			npTerminal->achBuffer[npTerminal->yCursor]
								[npTerminal->xCursor] = (char)nChar;

			if (hDC = GetDC(hWnd))
				{
				SelectObject(hDC, ghFont);
				SetBkColor(hDC, 0l);
				SetTextColor(hDC, RGB(255, 128, 128));
				HideCaret(hWnd);	// Don't paint over the caret
				TextOut(hDC,
						gcxFont * (npTerminal->xCursor - npTerminal->xOffset),
						gcyFont * (npTerminal->yCursor - npTerminal->yOffset),
						(LPSTR)&nChar, 1);
				ShowCaret(hWnd);
				ReleaseDC(hWnd, hDC);
				}

			npTerminal->xCursor++;
			}
		}
	if (npTerminal->xCursor >= COLUMNS)
		{
		npTerminal->xCursor = 0;
		npTerminal->yCursor++;
		}
	if (npTerminal->yCursor >= ROWS)
		{
		npTerminal->yCursor = ROWS - 1;
		memmove(npTerminal->achBuffer[0], npTerminal->achBuffer[1],
				(ROWS - 1) * COLUMNS);
		memset(npTerminal->achBuffer[ROWS - 1], ' ', COLUMNS);
		ScrollWindow(hWnd, 0, -gcyFont, NULL, NULL);
		UpdateWindow(hWnd); 				// Send WM_PAINT message now
		}
	if (hWnd == GetFocus())
		PositionCaret(hWnd);
	LocalUnlock(hTerminal);
	}

// Handle WM_VSCROLL or WM_HSCROLL message.
// Returns the new scrollbar position
int static HandleScroll(WORD wParam, int nOldValue, int maxValue,
						int nTrackPosition)
	{
	int nNewValue = nOldValue;

	switch(wParam)
		{
		case SB_BOTTOM:
			nNewValue = maxValue - 1;
			break;
		case SB_LINEUP:
			--nNewValue;
			break;
		case SB_LINEDOWN:
			++nNewValue;
			break;
		case SB_PAGEUP:
			nNewValue -= maxValue / 5;
			break;
		case SB_PAGEDOWN:
			nNewValue += maxValue / 5;
			break;
		case SB_TOP:
			nNewValue = 0;
		case SB_THUMBPOSITION:
			nNewValue = nTrackPosition;
			break;
		}
	if (nNewValue < 0)
		nNewValue = 0;
	if (nNewValue > maxValue)
		nNewValue = maxValue;
	return nNewValue;
	}

// This is the window function of the terminal class
LONG FAR PASCAL _export TerminalWndProc(HANDLE hWnd, WORD wMessage,
										WORD wParam, DWORD lParam)
	{

	switch(wMessage)
		{
		case WM_CREATE:
			{
			HTERMINAL hTerminal = LocalAlloc(LHND, sizeof(TERMINAL));
			NPTERMINAL npTerminal;

			if (!hTerminal)
				return -1;		// Fail CreateWindow
			npTerminal = (NPTERMINAL)LocalLock(hTerminal);
			if (npTerminal == NULL)
				{
				LocalFree(hTerminal);
				return -1;
				}
			memset((PSTR)npTerminal->achBuffer, ' ', ROWS * COLUMNS);
			SetWindowWord(hWnd, 0, (WORD)hTerminal);
			LocalUnlock(hTerminal);
			}
			break;
		case WM_HSCROLL:
			{
			HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
			NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
			int xNewOffset;

			if (NULL == npTerminal)
				return 0l;	// abort
			xNewOffset = HandleScroll(wParam, npTerminal->xOffset,
					max(0, COLUMNS - npTerminal->cxWindow), LOWORD(lParam));
			if (xNewOffset != npTerminal->xOffset)
				{
				ScrollWindow(hWnd, gcxFont * (npTerminal->xOffset -
							 xNewOffset), 0, NULL, NULL);
				npTerminal->xOffset = xNewOffset;
				SetScrollPos(hWnd, SB_HORZ, xNewOffset, TRUE);
				}
			LocalUnlock(hTerminal);
			}
			break;
		case WM_VSCROLL:
			{
			HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
			NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
			int yNewOffset;

			if (NULL == npTerminal)
				return 0l;	// abort
			yNewOffset = HandleScroll(wParam, npTerminal->yOffset,
				max(0, ROWS - npTerminal->cyWindow), LOWORD(lParam));
			if (yNewOffset != npTerminal->yOffset)
				{
				ScrollWindow(hWnd, 0, gcyFont * (npTerminal->yOffset -
							 yNewOffset),  NULL, NULL);
				npTerminal->yOffset = yNewOffset;
				SetScrollPos(hWnd, SB_VERT, yNewOffset, TRUE);
				}
			LocalUnlock(hTerminal);
			}
			break;
		case WM_DESTROY:
			LocalFree(GetWindowWord(hWnd, 0));
			break;
		case WM_PAINT:
			{
			int i;
			PAINTSTRUCT ps;
			HDC hDC;
			HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
			NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);

			if (NULL == npTerminal)
				return 0l;		// Can't access our parameters->abort paint
			hDC = BeginPaint(hWnd, &ps);
			SelectObject(hDC, ghFont);
			SetBkColor(hDC, 0l);
			SetTextColor(hDC, RGB(255, 128, 128));
			for(i = 0 ; i < ROWS ; ++i)
				TextOut(hDC, - (npTerminal->xOffset * gcxFont),
						gcyFont * (i - npTerminal->yOffset),
						npTerminal->achBuffer[i], COLUMNS);
			EndPaint(hWnd, &ps);
			LocalUnlock(hTerminal);
			}
			break;
		case WM_SIZE:
			{
			HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
			NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
			RECT rect;

			if (NULL == npTerminal)
				return 0l;
			// Get client dimensions without scroll bars (we have no border)
			GetWindowRect(hWnd, &rect);
			// Set max rows and columns that can be displayed
			npTerminal->cxWindow = (rect.right - rect.left) / gcxFont;
			npTerminal->cyWindow = (rect.bottom - rect.top) / gcyFont;
			SetScrollRange(hWnd, SB_HORZ, 0,
						   max(0, COLUMNS - npTerminal->cxWindow), TRUE);
			SetScrollRange(hWnd, SB_VERT, 0,
						   max(0, ROWS - npTerminal->cyWindow), TRUE);
			LocalUnlock(hTerminal);
			}
			break;
		case TW_SENDCHAR:
			SendChar(hWnd, wParam);
			break;
		case TW_SENDSTRING:
			while ((LPSTR)(lParam))
				SendChar(hWnd, *((LPSTR)(lParam++)));
			break;
		case WM_CHAR:
			// Send a notification message to our parent
			SendMessage(GetParent(hWnd), WM_COMMAND,
						GetWindowWord(hWnd, GWW_ID), MAKELONG(hWnd, wParam));
			break;
		case WM_LBUTTONDOWN:
			SetFocus(hWnd);
		case WM_SETFOCUS:
			CreateCaret(hWnd, NULL, gcxFont, 0);
			PositionCaret(hWnd);
			ShowCaret(hWnd);
			break;
		case WM_KILLFOCUS:
			DestroyCaret();
			break;
		case WM_GETDLGCODE:
			return DLGC_WANTALLKEYS;	// We also process enter, tab, ...
		default:
			return DefWindowProc(hWnd, wMessage, wParam, lParam);
		}
	return 0l;
	}

⌨️ 快捷键说明

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