2.4.5 - Обработка вводимой информации из клавиатуры

Следующий пример показывает, как использовать каретку в обычном редакторе текста. Пример модифицирует позицию каретки, поскольку пользователь вводит с клавиатуры печатные символы и использует различные клавиши, чтобы двигаться по рабочей области.

#define TEXTMATRIX(x, y) *(pTextMatrix + (y * nWindowCharsX) + x)  
// Глобальные переменные
HINSTANCE hinst;		// текущий экземпляр программы 
HBITMAP hCaret;		// точечный рисунок каретки 
HDC hdc;			// контекст устройства  
PAINTSTRUCT ps;		// информация о прорисовке рабочей области 
static char *pTextMatrix = NULL;	// указатель на текстовую матрицу 
static int
	nCharX,		// ширина символа в логических единицах 
	nCharY,		// высота символа в логических единицах 
	nWindowX,		// ширина рабочей области 
	nWindowY,		// высота рабочей области 
	nWindowCharsX,	// ширина рабочей области для символа 
	nWindowCharsY,	// высота рабочей области для символа 
	nCaretPosX,	// x-координата каретки
	nCaretPosY;	// y-координата каретки 
static UINT uOldBlink;	// предыдущая частота мерцания 
int x, y;			// x и y координаты, используемые в текстовой матрице 
TEXTMETRIC tm;		// информация о фонте 
 
LONG APIENTRY MainWndProc( 
	HWND hwnd,	// дескриптор окна 
	UINT message,	// тип сообщения 
	UINT wParam,	// дополнительная информация 
	LONG lParam)	// дополнительная информация 
{ 
	switch (message) 
	{ 
		case WM_CREATE: 
// Выбор фиксированной ширины системного фонта и получение его текстовой матрицы.
			hdc = GetDC(hwnd); 
			SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); 
			GetTextMetrics(hdc, &tm); 
			ReleaseDC(hwnd, hdc); 
// Сохранение средней высоты и ширины символов. 
			nCharX = tm.tmAveCharWidth; 
			nCharY = tm.tmHeight; 
			return 0; 
		case WM_SIZE: 
// Определение ширины рабочей области, в пикселях и в количестве символов. 
			nWindowX = LOWORD(lParam); 
			nWindowCharsX = max(1, nWindowX/nCharX); 
// Определение высоты рабочей области, в пикселях и в количестве символов. 
			nWindowY = HIWORD(lParam); 
			nWindowCharsY = max(1, nWindowY/nCharY); 
// Очистка буфера, который содержит введенный текст. 
			if (pTextMatrix != NULL) 
				free(pTextMatrix); 
// Если имеется достаточно памяти, распределите пространство для буфера ввода текста.
			pTextMatrix = malloc(nWindowCharsX * nWindowCharsY); 
			if (pTextMatrix == NULL) 
				ErrorHandler("Not enough memory."); 
			else 
				for (y = 0; y < nWindowCharsY; y++) 
					for (x = 0; x < nWindowCharsX; x++) 
						TEXTMATRIX(x, y) = ' '; 
// Переместим каретку в начало координат
			SetCaretPos(0, 0); 
			return 0; 
		case WM_KEYDOWN: 
			switch (wParam) 
			{ 
				case VK_HOME:	// в начало 
					nCaretPosX = 0; 
					break; 
				case VK_END:	// в конец 
					nCaretPosX = nWindowCharsX - 1; 
					break; 
				case VK_PRIOR:	// предыдущая страница 
					nCaretPosY = 0; 
					break; 
				case VK_NEXT:	// следующая страница 
					nCaretPosY = nWindowCharsY -1; 
					break; 
				case VK_LEFT:	// перемещение стрелкой влево 
					nCaretPosX = max(nCaretPosX - 1, 0); 
					break; 
				case VK_RIGHT:	// перемещение стрелкой вправо
					nCaretPosX = min(nCaretPosX + 1, 
					nWindowCharsX - 1); 
					break; 
				case VK_UP:	// перемещение стрелкой вверх 
					nCaretPosY = max(nCaretPosY - 1, 0); 
					break; 
				case VK_DOWN:	// перемещение стрелкой вниз
					nCaretPosY = min(nCaretPosY + 1, 
					nWindowCharsY - 1); 
					break; 
				case VK_DELETE:	// удалить 
// Переместите все символы, которые следовали за удаленным символом (на той же самой строке) на один
// пробел обратно (влево) в матрице
					for (x = nCaretPosX; x < nWindowCharsX; x++) 
						TEXTMATRIX(x, nCaretPosY) = TEXTMATRIX(x + 1, nCaretPosY);
// Замена последнего символа в строке с пробелом. 
					TEXTMATRIX(nWindowCharsX - 1, 
					nCaretPosY) = ' '; 
// Прикладная программа будет рисовать вне обработки сообщения
// WM_PAINT, так скрывают каретку. 
					HideCaret(hwnd); 
// Перерисовка строки для удаленного символа. 
					hdc = GetDC(hwnd); 
					SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); 
					TextOut(hdc, nCaretPosX * nCharX, 
						nCaretPosY * nCharY, 
						&TEXTMATRIX(nCaretPosX, nCaretPosY), 
						nWindowCharsX - nCaretPosX); 
					ReleaseDC(hwnd, hdc); 
// Показать каретку. 
					ShowCaret(hwnd); 
					break; 
			} 
// Корректировать позицию каретки, основанную при обработке виртуальной клавиши
			SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); 
			return 0; 
		case WM_CHAR: 
			switch (wParam) 
			{ 
			case 0x08:	// Обратный Пробел (Back Space) 
// Перемещение каретки на один пробел, а затем обработка этого действия подобно клавише DEL. 
				if (nCaretPosX > 0) 
				{ 
					nCaretPosX--; 
					SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1L); 
				} 
				break; 
			case 0x09:	// табуляция (Tab) 
// Табуляция останавливается, проходя каждые четыре пробела, таким образом добавляются пробелы, 
// до тех пор, пока пользователь нажимает следующий раз на клавишу табуляции. 
				do 
				{ 
					SendMessage(hwnd, WM_CHAR, ' ', 1L); 
				} while (nCaretPosX % 4 != 0); 
				break; 

			case 0x0D:	// возврат каретки 
// Переход к началу следующей строки. Нижняя строка переносится по кругу в верхнюю часть.
				nCaretPosX = 0; 
				if (++nCaretPosY == nWindowCharsY) 
					nCaretPosY = 0; 
				break; 

			case 0x1B:	// Escape 
			case 0x0A:	// перевод строки 
				MessageBeep((UINT) -1); 
				break; 
			default: 
// Добавление символа в буфер текста. 
				TEXTMATRIX(nCaretPosX, nCaretPosY) = (char) wParam; 
// Прикладная программа будет рисовать вне обработки сообщения WM_PAINT; так скрывают каретку. 
				HideCaret(hwnd); 
// Прорисовка символа на экране
				hdc = GetDC(hwnd); 
				SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); 
				TextOut(hdc, nCaretPosX * nCharX, 
					nCaretPosY * nCharY, 
					&TEXTMATRIX(nCaretPosX, nCaretPosY), 1); 
				ReleaseDC(hwnd, hdc); 
// Отобразим каретку
				ShowCaret(hwnd); 
// Подготовка переноса по словам с начала до конца, если Вы достигли конца строки
				if (++nCaretPosX == nWindowCharsX) 
				{ 
					nCaretPosX = 0; 
					if (++nCaretPosY == nWindowCharsY) 
						nCaretPosY = 0; 
				} 
				break; 
			} 
// Регулировка позиции каретки, основанной на обработке символа. 
			SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); 
			return 0; 

		case WM_PAINT: 
// Прорисовка всех символов в буфере, строка за строкой. 

			hdc = BeginPaint(hwnd, &ps); 
			SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); 
			for (y = 0; y < nWindowCharsY; y++) 
				TextOut(hdc, 0, y * nCharY, &TEXTMATRIX(0, y), nWindowCharsX); 
			EndPaint(hwnd, &ps); 
		case WM_SETFOCUS: 
// Окно имеет фокус ввода. Загрузка каретки определенной ресурсом программного приложения. 
			hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120)); 
// Создание каретки
			CreateCaret(hwnd, hCaret, 0, 0); 
// Регулировка позиции каретки
			SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); 
// Изображение каретки. 
			ShowCaret(hwnd); 
			break; 
		case WM_KILLFOCUS: 
// Окно теряет фокус ввода, так что каретка уничтожается. 
			DestroyCaret(); 
			break; 
		default: 
			return DefWindowProc(hwnd, message, wParam, lParam); 
		} 
		return NULL; 
} 

Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Владимир Соковиков - 04.01.2002