Как умудрились насрать в такую базовую вещь, как ввод с клавиатуры?
Серьёзно. Клавиатура - это то, через что мы взаимодействуем с компом каждый день. Часами. Годами. И система ввода до сих пор завязана на предположении что все сидят на QWERTY.
Поменял раскладку на Colemak? Хоткеи в играх сломались. Переключился на Rulemak? Aseprite не понимает что происходит. Юзаешь не-QWERTY в какой-нибудь старой проге? Добро пожаловать в ад.
И это не баг. Это фича. Англоцентричная фича, которой 40 лет.
Как должно работать
Есть железо. Есть кнопки. У каждой кнопки есть физическая позиция.
Scan code - это просто номер этой позиции. Нажал клавишу в левом верхнем углу - получил scan code. Не важно какая там буква нарисована. Не важно какой язык. Это просто “кнопка номер 16”.
Правильный подход: программа (игра, редактор, что угодно) слушает scan codes. Хоткей Ctrl+Z привязан к физической позиции кнопки Z - не к символу Z, не к виртуальному коду VK_Z, а к scan code. Тогда при любой раскладке хоткей работает одинаково.
Что пошло не так: где-то в конце 80-х индустрия решила что удобнее работать с символами и виртуальными кодами. Потому что “ну все же на QWERTY сидят, чо там”.
И с тех пор каждый слой абстракции, добавленный поверх scan code, создавал проблемы для всех кто не на QWERTY.
PS/2 клавиатуры кстати поддерживают три сета scan codes. XT (set 1), AT (set 2), и 3270 (set 3). Современные клавы шлют set 2, контроллер на материнке транслирует в set 1. Живити с этой информацией.
Windows: три слоя боли
Ввод с клавиатуры в Windows проходит три уровня:
scan_code -> virtual_key -> Symbol
Scan code - единственная адекватная вещь. Присваивается драйвером клавиатуры, не меняется от раскладки. В современных дровах можно ремапить матрицу, но это редкость.
Virtual key - бесполезное говно. Появилось ещё в Windows 3.1. Тогда проблема была такая: есть приложение написанное под QWERTY, а юзер во Франции сидит на AZERTY. Хоткеи не работают. Решение Microsoft: давайте создадим прослойку которая мапит физическую кнопку на “QWERTY-эквивалент”. Типа “какая буква была бы на этой кнопке если бы раскладка была QWERTY”.
Изначально идея была здравая. Но vk должен был умереть вместе с Win16 приложениями.
Он не умер.
Он в WinAPI до сих пор. GetKeyState(VK_CONTROL), WM_KEYDOWN с VK-кодами. Весь нативный Windows-софт сидит на VK. И ты не можешь просто взять и игнорить VK, потому что весь WinAPI через него работает.
Symbol - уже конкретные символы в соответствии с раскладкой. Тут всё ок - нажал кнопку с учётом Shift/AltGr, получил букву.
Проблема в том что между scan code и приложением два уровня абстракции. И каждое приложение выбирает свой.
Игры: каждый дрочит как хочет
DirectInput
Ебучий устаревший DirectInput мапит по VK.
Это API из 90-х. Microsoft сами признали его устаревшим ещё в 2005. Рекомендуют XInput для геймпадов и Raw Input для клавиатур.
Но он до сих пор жив. Некоторые игры до сих пор на нём. Всё что на DirectInput - всё говно для не-QWERTY раскладок.
Unity
Сраный Unity придумал свой Input Manager. Input.getKey анально привязан к Symbol.
То есть хоткей привязан не к кнопке, а к букве которую эта кнопка вводит в ТЕКУЩЕЙ раскладке. Переключил раскладку - хоткеи улетели.
Вродь они обновили систему инпута на “New Input System”. Теперь можно хапать клавиши через scan codes типа Keyboard.current.wKey. Но серавно в каких-то ситуациях происходит хуйня с кастомными раскладками.
То есть они типа починили, но не до конца. Классика.
Unreal Engine
В UE если разраб не въебнёт галочку “use scan code” - инпут будет через VK.
По дефолту VK. То есть каждая игра на Unreal потенциально сломана. Зависит от того, заморачивался ли разраб.
Source Engine
А вот дядушка Габен в сурсе (TF2, CS2, Portal…) юзает scan codes для ввода движения.
И оно просто работает. На любой раскладке. Без перенастроек.
сколько не хейти valve - что-то да хорошее делать они умеют.
Хорошие примеры
Кроме сурса есть нормальные ребята.
Minecraft. Где-то до 1.9-1.12 (точно не помню) в майне был другой код инпута - всё привязывалось к VK.
То есть если у тебя раскладка не QWERTY (а в некоторых раскладках vk отличается, например во французской и немецкой) - тебе приходилось ребиндить. Каждый раз. При каждом обновлении.
Потом в районе 1.12+ переписали на scan codes. И всё стало пиздато работать. Потому что физическая кнопка W - это всегда физическая кнопка W, не важно какая там буква в твоей раскладке.
в миникрафт бедроке пошли нахуй, у нас DirectInput йоу
Софт: Aseprite и остальные
А ебучий Aseprite блять по Symbol хуярит.
Ты рисуешь пиксельарт. Переключился на русскую раскладку (или любую другую не-QWERTY). И хоткеи улетают куда-то хуй пойми куда.
Потому что B в русской раскладке это И. И Aseprite думает “ага, нажата кнопка И, смотрю в своей таблице хоткеев… а там нет хоткея на И”.
Хотя физически ты нажал ту же кнопку.
Так многие проги. Aseprite просто самый больной пример - в нём работа завязана на хоткеи.
В остальном весь софт ходит через WinAPI - соответственно VK. А VK мапится на “QWERTY-эквивалент”. На некоторых не-QWERTY раскладках (французская AZERTY, немецкая QWERTZ) этот эквивалент отличается от QWERTY. И хоткеи летят лесом.
Нормальные ребята юзают scan codes. Их меньшинство.
Linux: свои грабли
В Linux тоже насрали, и кабуда даже сильнее.
Начнём с того, что там три слоя абстракции до символа.
Аппаратный scan code. Клавиатура (PS/2 или USB HID) шлёт сырой scan code. Ядро получает.
linux_keycode. Ядро переваривает scan code в условные KEY_Q, KEY_W, KEY_E. Это уже не физический номер, а “QWERTY-позиция”. То есть на этом уровне ты уже потерял чистый scan code.
То есть Linux kernel сразу же делает англоцентричное предположение.
XKB. X Keyboard Extension берёт что ядро высрало (KEY_Q, KEY_W…) и высерает свои позиции: <AD01>, <AD02> … <AB01>, <AB02>.
И уже эти координаты XKB мапит напрямую в символы (Keysyms). Типа <AD01> = q, а в русской раскладке = Cyrillic_shorti (й).
Проблема линукса в том, что если прога слушает linux_keycode напрямую (а многие так делают, особенно старые X11 проги и некоторые игры через SDL), ты получаешь те же проблемы что и с VK в Windows.
Но если прога слушает XKB Keysyms - она получает уже окончательные символы. И если она привязывает хоткеи к символам а не к scan codes - опять слом.
Что делать
Программистам: биндите инпут на scan codes. Всегда. Физическая позиция кнопки не меняется от раскладки.
Разрабам игр: загляните в Source(Quake(Doom)). Всё за вас придумали 30+ лет назад.
Пользователям не-QWERTY раскладок: страдать. Или писать баг-репорты с тегом “keyboard layout”. Или делать свои инструменты для обхода этой хуйни.
Может, когда-нибудь, операционные системы начнут поддерживать другие языки, помимо английского.
Но видимо пока рано.