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

Серьёзно. Клавиатура - это то, через что мы взаимодействуем с компом каждый день. Часами. Годами. И система ввода до сих пор завязана на предположении что все сидят на 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”. Или делать свои инструменты для обхода этой хуйни.


Может, когда-нибудь, операционные системы начнут поддерживать другие языки, помимо английского.

Но видимо пока рано.