Rolling One Own Keyboard/Система ввода в C/С++

Вопрос:

Какие ресурсы необходимы, чтобы узнать, как создать собственную систему ввода/вывода?

Мое собственное понимание:

Я знаю, что это очень зависит от операционной системы, поэтому позвольте разделить Linux и Windows и перечислить ресурсы для обеих операционных систем (если это возможно). Для Linux, я предполагаю, что справедливое знание системы X Window требуется. Для Windows я предполагаю API win32. Тем не менее, я предполагаю, что в этом есть нечто большее, чем просто знать их, как бы если бы я предпочел написать систему ввода в С++.

Причина для запроса:

Я пробовал читать исходный код OIS (так как это будет написано либо в C, либо C++), и просто не понравилось, как оно было написано. Поэтому я взял на себя обязательство научиться писать собственную систему ввода/вывода на клавиатуре для простой игры в понг (написанной в C++).

Ответ 1

Обновление: Вот библиотека, которую я написал для обработки ввода с клавиатуры. Он использует лицензию FreeBSD. Я даже отметил его как v1.0, поэтому считаю, что это "качество выпуска".

https://github.com/depp/keycode

Недавно я очень много работал, чтобы получить это "просто право" для игр, и я еще не закончил. Я расскажу то, что знаю.

Коды клавиш

Для игр коды клавиш обычно вам нужны.

Когда вы нажимаете клавишу на клавиатуре, ОС сначала переводит кнопку нажатием на key code. key code указывает физическое местоположение ключа на клавиатуре. Например, код 4 может соответствовать знаку A на клавиатуре США (даже если у этого ключа есть другой ярлык во Франции или России). Каждая платформа имеет другой набор кодов клавиш или, возможно, несколько наборов. Вы можете узнать их под другим именем, например, коды сканирования или коды виртуальных клавиш.

  • Windows использует коды виртуальных ключей (документация MSDN). Они стабильны в различных конфигурациях оборудования и программного обеспечения. Вы можете найти определения в заголовочном файле <Winuser.h>. В Windows, если вы нажмете левую верхнюю клавишу строки дома (A в США, Q во Франции), вы получите код 65.

  • Mac OS X имеет коды клавиш, которые были стабильными с 80-х годов. Они определены в <Carbon/Events.h>. Вам действительно не нужно ссылаться на Carbon, чтобы использовать коды клавиш, но вам нужен заголовок. В OS X, если вы нажмете левую верхнюю клавишу строки дома, вы получите код 4.

  • Linux имеет несколько расходящихся наборов ключей. Итак, на Linux у вас есть несколько вариантов. Вы можете использовать ключевые сим (которые имеют недостатки, которые я объясню ниже), вы можете предположить, что пользователь использует специальный драйвер ввода (в наши дни Evdev - очень хорошее предположение), или вы можете каким-то образом выяснить, какой драйвер ввода машина использует. Чтобы получить коды ключей, вы должны прочитать файлы определения клавиатуры. Например, посмотрите на /usr/share/X11/xkb/keycodes/evdev для кодов ключей Evdev. С помощью Evdev, если вы нажмете левую верхнюю клавишу строки дома, вы получите код 38.

Конечно, было бы слишком легко, если бы key code были одинаковыми на разных платформах. Вы можете использовать платформу key code или перевести ее в независимое от платформы значение. Я предлагаю использовать коды USB HID (pdf) в качестве независящих от платформы кодов, поскольку ряд умных людей уже столкнулся с проблемой согласия на что нужно называть каждый ключ.

В библиотеке, которую я разместил выше, есть таблицы для каждой платформы, такие как WIN_NATIVE_TO_HID для перевода кодов клавиш в коды USB HID.

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

Коды символов

Вы не хотите использовать коды символов, даже если их проще использовать, если вы живете в США, а ваша аудитория также живет в США.

После перевода кнопки нажмите key code, затем OS переводит key code в код символа. На код символа влияет текущая раскладка клавиатуры и часто на нее влияют также ключи-модификаторы.

Итак, если вы нажмете A на клавиатуре, вы получите коды клавиш 65, 4 или 38, в зависимости от того, на какой платформе вы находитесь. Но вы получите код символа 'a' или 'a' в зависимости от того, нажата ли клавиша сдвига, или вы можете получить 'Q', если раскладка клавиатуры установлена ​​на французский язык или 'Ф', если установлена ​​раскладка клавиатуры на русский. Итак, если вы кодируете WASD в свою игру и используете коды символов, вход будет полностью нарушен, когда кто-то из другой страны будет играть в вашу игру. Вам нужно будет использовать ZQSD во Франции, ЦФЫВ в России, и довольно скоро у вас болит голова.

Я сам использую не-QWERTY-макет (Dvorak), и большинство игр полностью сломаны. Вместо ключа W находится ,, который становится <, если у вас есть клавиша shift, а некоторые игры не распознают это как один и тот же ключ. Например, я бы нажал ,, чтобы двигаться вперед, но если бы я отпустил кнопку, когда клавиша смены была опущена, игра подумала бы, что я выпустил < и думаю, что ,, поэтому я буду продолжать двигаться вперед. Большинство игр, использующих SDL, разбиты на Mac для меня, даже если я переключусь на раскладку клавиатуры в США (я думаю, что это сбой в SDL).

LibSDL

SDL 2.0 предоставляет не зависящие от платформы коды ключей, называемые кодами сканирования. Используйте заголовок "SDL_scancode.h". Разработчики SDL пришли к тому же выводу, что коды сканирования должны быть переведены обратно на коды USB HID, поэтому коды сканирования SDL полностью совместимы с библиотекой, которую я опубликовал выше (см. keycode.h и SDL_scancode.h, числовые значения идентичны).

По этой и другим причинам, если вы используете SDL 1.2, я настоятельно рекомендую обновить до 2.0.

Ответ 2

Последующее относится только к обработке ввода в Windows.

Как упомянуто capr в комментарии к ответу Дитриха Эппа, коды VK_ меняются в зависимости от языка раскладки клавиатуры, которую вы используете. Поэтому, если ваша раскладка клавиатуры французская и вы нажимаете "Q" на QWERTY-клавиатуре, создается виртуальная клавиша "A". Если ваш макет, например, en-US, создается виртуальный ключ для "Q", как и ожидалось.

Поскольку фактические коды сканирования зависят от аппаратного обеспечения (и, следовательно, не могут использоваться), я обошел эту проблему зависимости компоновки, переведя сгенерированный код сканирования в виртуальную клавишу, соответствующую раскладке клавиатуры в США. Затем его можно преобразовать в коды HID USB, как описано Дитрихом Эппом. Это приводит к тому же ожидаемому коду USB HID независимо от языка компоновки.

Способ перевода скан-кода в ВК ан-сша,

// Get and store the name of the currently used locale
wchar_t defaultLayoutName[KL_NAMELENGTH];
GetKeyboardLayoutName(defaultLayoutName)

// Load and store a handle to the locale for en-US ("00000409")
HKL defaultEnUSInputLocale = LoadKeyboardLayout(TEXT("00000409"), KLF_NOTELLSHELL);

// Load the locale that was in use before so as not to change the keyboard layout of the user
LoadKeyboardLayout(defaultLayoutName, KLF_ACTIVATE);

--- (at windowProc) ---
case WM_INPUT:
    // Use the handle to the en-US locale to translate the scan codes to VK_.
    virtualKey = MapVirtualKeyExW(scanCode, MAPVK_VSC_TO_VK_EX, defaultEnUSInputLocale);

    // translate virtualKey to USB HID by using e.g. the codes supplied by Dietrich Epp
    int8_t usbHIDkey = VK_TO_HID[virtualKey];

Обратите внимание, что есть некоторые дополнительные препятствия, связанные с виртуальными ключами в Windows. Я обнаружил, что этот сайт очень помогает в этом вопросе: https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/