Поделиться через


Ввод клавиатуры (начало работы с Win32 и C++)

Клавиатура используется для нескольких различных типов входных данных, в том числе:

  • Ввод символов. Текст, который пользователь вводит в документ или поле редактирования.
  • Сочетания клавиш. Штрихи ключей, вызывающие функции приложения; например, CTRL+O для открытия файла.
  • Системные команды. Штрихи ключей, вызывающие системные функции; например, ALT +TAB для переключения окон.

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

  • a
  • A
  • á (если клавиатура поддерживает объединение диакритических элементов)

Кроме того, если клавиша ALT удерживается вниз, нажатие клавиши A создает ALT+A, которое система не обрабатывает как символ вообще, а как системную команду.

Ключевые коды

При нажатии клавиши оборудование создает скан-код . Коды сканирования зависят от клавиатуры, и существуют отдельные коды сканирования для событий нажатия и отпускания клавиш. Вам почти никогда не будут важны коды сканирования. Драйвер клавиатуры преобразует коды сканирования в коды виртуальных клавиш. Коды виртуальных ключей являются независимыми от устройства. Нажатие клавиши A на любой клавиатуре создает тот же код виртуального ключа.

Как правило, коды виртуальных ключей не соответствуют кодам ASCII или любому другому стандарту кодировки символов. Это очевидно, если вы думаете об этом, так как один и тот же ключ может создавать разные символы (a, A, á), а некоторые ключи, такие как ключи функции, не соответствуют ни одному символу.

Таким образом, следующие коды виртуальных ключей сопоставляют с эквивалентами ASCII:

  • От 0 до 9 ключей = ASCII '0' – '9' (0x30 – 0x39)
  • Ключи от A до Z = ASCII «A» – «Z» (0x41 – 0x5A)

В некоторых отношениях это сопоставление является несчастным, поскольку вы никогда не должны рассматривать коды виртуальных ключей как символы, по причинам, рассмотренным.

Файл заголовка WinUser.h определяет константы для большинства кодов виртуальных ключей. Например, код виртуального ключа для клавиши СТРЕЛКА ВЛЕВО VK_LEFT (0x25). Полный список кодов виртуальных ключей см. в разделе Virtual-Key Коды. Константы не определены для кодов виртуальных ключей, соответствующих значениям ASCII. Например, код виртуального ключа для клавиши 'A' — 0x41, но нет константы с именем VK_A. Вместо этого просто используйте числовое значение.

сообщения Key-Down и Key-Up

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

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

  • ALT + любой ключ
  • F10

Клавиша F10 активирует строку меню окна. Различные сочетания клавиш ALT вызывают системные команды. Например, ALT +TAB переключается на новое окно. Кроме того, если в окне есть меню, клавиша ALT может использоваться для активации элементов меню. Некоторые сочетания клавиш ALT не делают ничего.

Все остальные нажатия клавиш считаются несистемными и создают сообщение WM_KEYDOWN. Сюда входят ключи функций, отличные от F10.

Когда вы отпускаете клавишу, система отправляет соответствующее сообщение о отпускании клавиши.

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

Во всех четырех рассмотренных сообщениях клавиатуры параметр wParam содержит код виртуального ключа. Параметр lParam содержит некоторые прочие сведения, упакованные в 32 бита. Обычно вам не нужны сведения в lParam. Полезным может быть флаг бит 30, "предыдущее состояние клавиши", который устанавливается в 1 для повторяющихся сообщений о нажатии клавиш.

Как следует из названия, нажатия системных клавиш в основном предназначены для использования операционной системой. Если вы перехватываете сообщение WM_SYSKEYDOWN, после этого вызовите DefWindowProc. В противном случае операционная система будет блокировать обработку команды.

Символьные сообщения

Нажатия клавиш преобразуются в символы функцией TranslateMessage, которую мы впервые видели в модуле 1. Эта функция обрабатывает сообщения о нажатии клавиш и преобразует их в символы. Для каждого создаваемого символа функция TranslateMessage помещает сообщение WM_CHAR или WM_SYSCHAR в очередь сообщений окна. Параметр wParam сообщения содержит символ UTF-16.

Как можно угадать, WM_CHAR сообщения создаются из WM_KEYDOWN сообщений, а WM_SYSCHAR сообщения создаются из WM_SYSKEYDOWN сообщений. Например, предположим, что пользователь нажимает клавишу SHIFT, а затем клавишу A. При условии стандартной раскладки клавиатуры вы получите следующую последовательность сообщений:

WM_KEYDOWN: SHIFT
WM_KEYDOWN: A
WM_CHAR: "A"

С другой стороны, сочетание ALT+P будет генерировать:

WM_SYSKEYDOWN: VK_MENU
WM_SYSKEYDOWN: 0x50
WM_SYSCHAR: "p"
WM_SYSKEYUP: 0x50
WM_KEYUP: VK_MENU

(Код виртуального ключа для клавиши ALT называется VK_MENU по историческим причинам.)

Сообщение WM_SYSCHAR указывает системный символ. Как и в случае с WM_SYSKEYDOWN, обычно необходимо передать это сообщение непосредственно в DefWindowProc. В противном случае вы можете вмешиваться в стандартные системные команды. В частности, не рассматривать WM_SYSCHAR как текст, введенный пользователем.

Сообщение WM_CHAR — это то, что обычно считается вводом символов. Тип данных для символа wchar_t, представляющий символ Юникода UTF-16. Входные данные символов могут включать символы за пределами диапазона ASCII, особенно с раскладками клавиатуры, которые обычно используются за пределами СОЕДИНЕННЫх Штатов. Вы можете попробовать различные раскладки клавиатуры, установив региональную клавиатуру, а затем с помощью функции экранной клавиатуры.

Пользователи также могут установить редактор метода ввода (IME), чтобы ввести сложные скрипты, такие как японские символы, с стандартной клавиатурой. Например, с помощью японского IME для ввода символа Katakana カ (ka) вы можете получить следующие сообщения:

WM_KEYDOWN: VK_PROCESSKEY (ключ процесса IME)
WM_KEYUP: 0x4B
WM_KEYDOWN: VK_PROCESSKEY
WM_KEYUP: 0x41
WM_KEYDOWN: VK_PROCESSKEY
WM_CHAR: カ
WM_KEYUP: VK_RETURN

Некоторые сочетания клавиш CTRL переводятся в управляющие символы ASCII. Например, CTRL+A преобразуется в управляющий символ ASCII ctrl-A (SOH) с значением 0x01. Для ввода текста обычно следует отфильтровать символы элемента управления. Кроме того, не используйте WM_CHAR для реализации сочетаний клавиш. Вместо этого используйте сообщения WM_KEYDOWN; или, что еще лучше, воспользуйтесь таблицей акселераторов. Таблицы акселератора описаны в следующем разделе, таблицы акселераторов.

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

Заметка

Обязательно включите wchar.h, иначе swprintf_s не будет определен.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    wchar_t msg[32];
    switch (uMsg)
    {
    case WM_SYSKEYDOWN:
        swprintf_s(msg, L"WM_SYSKEYDOWN: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_SYSCHAR:
        swprintf_s(msg, L"WM_SYSCHAR: %c\n", (wchar_t)wParam);
        OutputDebugString(msg);
        break;

    case WM_SYSKEYUP:
        swprintf_s(msg, L"WM_SYSKEYUP: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_KEYDOWN:
        swprintf_s(msg, L"WM_KEYDOWN: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_KEYUP:
        swprintf_s(msg, L"WM_KEYUP: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_CHAR:
        swprintf_s(msg, L"WM_CHAR: %c\n", (wchar_t)wParam);
        OutputDebugString(msg);
        break;

    /* Handle other messages (not shown) */

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

Другие сообщения клавиатуры

Некоторые другие сообщения клавиатуры можно безопасно игнорировать большинством приложений.

  • Сообщение WM_DEADCHAR отправляется для объединения ключа, например диакритического. Например, на клавиатуре испанского языка ввод акцента ('), за которым следует E, создает символ é. WM_DEADCHAR посылается для акцентного символа.
  • Сообщение WM_UNICHAR устарело. Это позволяет программам ANSI получать входные данные символов Юникода.
  • Символ WM_IME_CHAR отправляется, когда IME преобразует последовательность нажатия клавиш в символы. Он отправляется в дополнение к обычному сообщению WM_CHAR.

Состояние клавиатуры

Сообщения клавиатуры управляются событиями. То есть вы получите сообщение, когда происходит что-то интересное, например нажатие клавиши, и сообщение сообщает вам, что только что произошло. Но вы также можете проверить состояние ключа в любое время, вызвав функцию GetKeyState.

Например, рассмотрим способ обнаружения сочетания клавиши ALT и щелчка левой кнопки мыши. Вы можете отслеживать состояние клавиши ALT, прослушивая сообщения нажатия клавиш и сохраняя флаг, но GetKeyState избавляет вас от хлопот. При получении сообщения WM_LBUTTONDOWN просто вызовите GetKeyState следующим образом:

if (GetKeyState(VK_MENU) & 0x8000)
{
    // ALT key is down.
}

Сообщение GetKeyState принимает код виртуального ключа в качестве входных данных и возвращает набор битовых флагов (фактически всего два флага). Значение 0x8000 содержит битовый флаг, который проверяет, нажимается ли ключ в данный момент.

Большинство клавиатур имеют два клавиши ALT, слева и справа. В предыдущем примере проверяется, был ли нажат хотя бы один из них. Вы также можете использовать GetKeyState для различения между левыми и правыми экземплярами клавиш ALT, SHIFT или CTRL. Например, следующий код проверяет, нажимается ли правый клавиша ALT.

if (GetKeyState(VK_RMENU) & 0x8000)
{
    // Right ALT key is down.
}

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

Так как GetKeyState основан на очереди сообщений, он также игнорирует ввод клавиатуры, отправленный в другую программу. Если пользователь переключается на другую программу, все нажатия клавиш, отправляемые этой программе, игнорируются GetKeyState. Если вы действительно хотите знать немедленное физическое состояние клавиатуры, существует функция для этого: GetAsyncKeyState. Для большинства кода пользовательского интерфейса правильной функцией является GetKeyState.

Следующий

Таблицы акселераторов