Обработка ввода с клавиатуры


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

Демонстрационный пример

#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;                         // координаты матрицы текста
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:       // В начало документа (Home) 
                    nCaretPosX = 0; 
                    break; 
 
                case VK_END:        // В конец документа (End) 
                    nCaretPosX = nWindowCharsX - 1; 
                    break; 
 
                case VK_PRIOR:      // На страницу вверх (Page Up) 
                    nCaretPosY = 0; 
                    break; 
 
                case VK_NEXT:       // На страницу вниз (Page Down) 
                    nCaretPosY = nWindowCharsY -1; 
                    break; 
 
                case VK_LEFT:       // Стрелка влево (Left arrow) 
                    nCaretPosX = max(nCaretPosX - 1, 0); 
                    break; 
 
                case VK_RIGHT:      // Стрелка вправо (Right arrow) 
                    nCaretPosX = min(nCaretPosX + 1, 
                        nWindowCharsX - 1); 
                    break; 
 
                case VK_UP:         // Стрелка вверх (Up arrow) 
                    nCaretPosY = max(nCaretPosY - 1, 0); 
                    break; 
 
                case VK_DOWN:       // Стрелка вниз (Down arrow) 
                    nCaretPosY = min(nCaretPosY + 1, 
                        nWindowCharsY - 1); 
                    break; 
 
                case VK_DELETE:     // Удаление (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:          // Возврат на один знак (Backspace) 
                // Перемещаем каретку назад на один пробел, а затем
                // обрабатываем аналогично клавише DEL. 
 
                    if (nCaretPosX > 0) 
                    { 
                        nCaretPosX--; 
                        SendMessage(hwnd, WM_KEYDOWN, 
                            VK_DELETE, 1L); 
                    } 
                    break; 
 
                case 0x09:          // Табуляция (Tab) 
         // Существующий шаг табуляции равен четырем пробелам, так что
         // добавим пробелы, пока пользователь не нажал след. Tab. 
 
                    do 
                    { 
                        SendMessage(hwnd, WM_CHAR, ' ', 1L); 
                    } while (nCaretPosX % 4 != 0); 
                    break; 
 
                case 0x0D:          // Возврат каретки
                // Перейдем в начало следующей строки. 
                // Нижняя строка переносит по словам обратно вверх. 
 
                    nCaretPosX = 0; 
 
                    if (++nCaretPosY == nWindowCharsY) 
                        nCaretPosY = 0; 
                    break; 
 
                case 0x1B:        // Переход 
                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; 
} 

 

Назад в оглавление темы
На главную страницу темы
Перевод 20.02.2004 16:40 ©Copyright V. Sokovikov
Hosted by uCoz