Работа с клавиатурой в играх

QWERY+AZERTY клавиатура Волей случая мне пришлось познать работу с клавиатурой в игровом проекте. Надо отметить, что тема эта оказалась сложее, чем ожидалось. И, к примеру, в Unreal Engine и Cry Engine с клавиатурой есть проблемы. Обычно их не видно, но в процессе интернационализации они проявляются очень сильно.

Далее будут использоваться термины Windows, но общая идея справедлива для всех операционных систем.

Беда в том, что для клавиатуры существует не только несколько понятий “нажатости” клавиши:

  1. клавиша физически нажата на клавиатуре (состояние клавиши по данным DirectInput);
  2. пришло событие о нажатии клавиши (события WM_KEYDOWN/WM_KEYUP из операционной системы).

Но и несколько способов идентификации клавиши:

  1. по физической позиции на клавиатуре (сканкод);
  2. по символу, который соответствует данной клавише.

Проблема идентификации клавиши

Проблема идентификации клавиши возникает из-за существования нескольких раскладок. При этом важно осознавать, что не на всех этих раскладках латинские буквы находятся в одном и том же месте.

Многие слышали про клавиатуру Дворака, но есть и менее экзотические случаи. К примеру, на французской AZERTY-раскладке кнопки WASD находятся не там, где мы их привыкли видеть.

Хуже того, технически можно переключать клавиатуру между AZERTY и QWERTY раскладкой на лету, а подписи клавиш могут вообще отсутствовать.

То есть кнопки, привязанные к месторасположению, должны быть назначены через сканкод.

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

Получить значение символа для сканкода в текущей раскладке можно функцией типа MapVirtualKeyEx. Название клавиши можно получить функцией GetKeyNameText).

Для ситуации, когда по какой-то причине надо привязаться к конкретному символу (например, назначить вывод карты на кнопку “M”), у меня хорошего решения нет.

Разные понятия “нажатости” клавиш

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

В игре для управления персонажем, в первую очередь, важен факт нажатости клавиши на момент начала кадра. Для этого удобнее всего проверять состояния клавиш через DirectInput.

Использовать события WM_KEYDOWN/WM_KEYUP для управления персонажем нельзя, так как события WM_KEYDOWN и WM_KEYUP далеко не всегда приходят парой. Самый простой пример: при переключении на другое приложение событие WM_KEYUP может быть потеряно.

В интерфейсе все несколько сложнее: нужно делить клавиатуру вместе со сторонними подсистемами, такими как оверлеи и системы ввода иероглифов (IME). При этом, если в случае с оверлеями можно просто заявить, что они не поддерживаются, то поддержка IME является обязательным условием для выхода на некоторые азиатские рынки.

В этом случае при работе с клавиатурой важен не только факт нажатия клавиши, но и то, в контексте какой подсистемы она должна быть обработана. В этом случае необходимо работать на основании событий от операционной системы. В противном случае можно получить неожиданное поведение таких клавиш как Esc, Backspace и Enter.

Для примера: в случае, если во время IME нажать Backspace, то эта клавиша будет обработана на стороне IME то вместо события WM_KEYDOWN в приложение будет отправлено событие WM_IME_NOTIFY, хотя DirectInput будет считать клавишу нажатой. Если при этом поле ввода будет использовать данные от DirectInput, то одна и та же клавиша будет обработана дважды и его поведение его будет не корректным.

Резюмируя

Подводя итог хочется сказать:

  1. Если важно физическое расположение клавиш, то предпочтительнее использовать сканкод.
  2. Для интерфейса предпочтительнее использовать системные события.
  3. Существуют и используются раскладки, отличные от QWERTY.
  4. IME сулит много проблем. Там действительно водятся драконы.
comments powered by Disqus