[Из песочницы] Ассемблер/дизассемблер клавиатурных раскладок Windows с помощью flat assembler
Знакомый линуксоид упрекнул меня, мол, в винде ни переключения языка Caps Lock’ом нет, ни даже раскладку нельзя отредактировать. Посмотрел я, и правда, все раскладки содержатся в файлах C:\Windows\System32\kbd*.dll, и редактировать такое hex-редактором ну никак не назвать удобным.
Как достичь удобства? Для переключения раскладок Caps Lock’ом можно использовать всякие навесные программы, тяжёлые вроде Punto Switcher, или простые вроде lswitch. Для редактирования раскладок есть MSKLC, но он малофункционален и неудобен, а аналоги вроде KbdEdit или KLM32 платные.
И тогда я решил написать на flat assembler’е код, собирающий DLL раскладки.
За основу была взята раскладка kbdusx.dll, в системе она называется «США Международная». Мне она понравилась тем, что в ней есть ряд комбинаций для дополнительных символов. Не нравилась она тем, что превращает клавиши <`~>, <6^>, <'"> в так называемые dead keys, «мёртвые клавиши». Их особенность — при нажатии ничего не печатается, но изменяется следующий набранный символ. Таким образом можно вводить латинские буквы с диакритикой, для которых нет отдельного сочетания клавиш. Но мне, как программисту, было очень неприятно «залипание» таких часто используемых клавиш, и изначально я просто обнулил поля в hex-редакторе, отвечающие за мёртвые клавиши.
Пришла пора разобраться с форматом раз и навсегда. Поначалу дело шло неспешно, потом я нашёл kbd.h и несколько примеров раскладок из Windows Driver Kit.
Забавно, что Microsoft решили поместить раскладки в формат DLL, хотя за исключением корейской kbdkor.dll и японской kbdjpn.dll там кода нет совсем, если не считать экспортируемую функцию KbdLayerDescriptor, возвращающую указатель на главную таблицу с раскладкой.
Таблица имеет такой вид:
32-bit Windows | 64-bit или WOW64 | |||
---|---|---|---|---|
Название | Размер | Смещение | Размер | Смещение |
modifiers | 4 | 0×00 | 8 | 0×00 |
vk2wchar | 4 | 0×04 | 8 | 0×08 |
deadkeys | 4 | 0×08 | 8 | 0×10 |
keynames | 4 | 0×0C | 8 | 0×18 |
keynamesExt | 4 | 0×10 | 8 | 0×20 |
keynamesDead | 4 | 0×14 | 8 | 0×28 |
scancode2vk | 4 | 0×18 | 8 | 0×30 |
scancode2vk_size | 1 | 0×1C | 1 | 0×38 |
e0scancode2vk | 4 | 0×20 | 8 | 0×40 |
e1scancode2vk | 4 | 0×24 | 8 | 0×48 |
locale_flags | 2 | 0×28 | 2 | 0×50 |
version | 2 | 0×2A | 2 | 0×52 |
ligature_chars | 1 | 0×2C | 1 | 0×54 |
ligature_size | 1 | 0×2D | 1 | 0×55 |
ligatures | 4 | 0×30 | 8 | 0×58 |
type | 4 | 0×34 | 4 | 0×60 |
subtype | 4 | 0×38 | 4 | 0×64 |
Таким образом, файл раскладки содержит в себе таблицы названия клавиш, конвертации скан-кодов в виртуальные (0×1C → VK_RETURN), конвертации виртуальных кодов в символы, комбинации мёртвых клавиш, «лигатуры».
Судя по всему, названия клавиш используются редко, мне не удалось на своём компьютере найти программы, которая бы выводила их список из раскладки.
Изменяя таблицу скан-кодов, можно переназначить любую клавишу на другую. Если сразу захотелось переназначить кнопки питания (Power, Sleep, WakeUp), то это тоже можно, но это не отменит их оригинальной функции. Её можно отключить в настройках электропитания.
В таблице символов самый сок. Она решает, к чему приведёт нажатие клавиш K, Shift+K, AltGr+K, Shift+AltGr+K, влияет ли на неё Caps Lock, использует ли он тот же ряд символов, что и Shift+K или отдельный, влияет ли на неё Kana; будет ли символ напечатан сразу, или занесётся в очередь мёртвых клавиш, или напечатается ряд символов из «лигатуры», или или не произойдёт ничего.
AltGr — так называется либо правый Alt, либо сочетание клавиш Ctrl+Alt.
Список мёртвых клавиш содержит пары символов, которые должны преобразовываться в третий символ. Этот символ может печататься сразу, или снова проходить по списку для дальнейшего преобразования. Если пара символов не найдена в списке, то она просто напечатается как есть. С помощью цепочек мёртвых клавиш можно сымитировать поведение Compose Key, но некоторые программы, например, Firefox, не распознают преобразования дальше первого.
Список «лигатур», который по сути является набором макросов, может позволить набирать до четырёх символов WCHAR по нажатию клавиши. На самом деле, у меня в Windows 7 работает до 16 символов, но с крайне неприятным исключением: Firefox при натыкании на такую раскладку напрочь зависает, а если раскладка с длинными «лигатурами» системная, то и вовсе перестаёт запускаться.
Сперва я хотел сделать две удобных раскладки, русскую и английскую, подходящую как для написания статей, так и программ. Типографская раскладка Ильи Бирмана хороша, но могло быть ещё лучше, тем более если делать лично для себя.
Потом я узнал про клавишу Kana. Kana — переключающаяся подобно Caps Lock’у кнопка на японской клавиатуре. И тут я решил объединить английскую и русскую раскладки в одну, и переключаться между ними клавишей Kana. Которую я переназначил на Caps Lock. Написал простую программу-индикатор для отображения состояния Kana лампочкой Caps Lock’а.
У такой объединённой раскладки возник один приятный сюрприз: раскладка теперь одна на всю систему, и остаётся при переключении между программами, а также «шибко умные» программы больше не могут переключать раскладку по своему желанию при редактировании текста или перемещении курсора.
И один неприятный сюрприз: Psi+ почему-то стал съедать первый символ, введённый после переключения раскладки нажатием Kana.
Тем не менее, я оставил эту раскладку в архиве вместе с индикатором Kana.
Потом я обнаружил, что Caps Lock’у можно назначить отдельный ряд символов и заменил Kana на Caps Lock. Программа-индикатор стала ненужной, неприятный сюрприз изчез. При переделке обнаружилось только одно ограничение: Caps Lock работает только с рядами K и Shift+K — на него нельзя повесить AltGr+K и т.п.
В попытках уместить все мёртвые клавиши в два ряда (с Kana было четыре), я наткнулся на идею перевернуть их порядок: так, чтоб набиралась AltGr+буква, а потом модификатор. Это позволило мне назначить гораздо больше символов, чем раньше. Я назвал это «undead keys», «восставшие из мёртвых клавиши».
И вот идеальная раскладка была готова.
- Переключение между русским и английским одной клавишей Caps Lock.
- Индикатор Caps Lock показывает текущий язык.
- Глобальное состояние раскладки для всех приложений.
- Невозможность «шибко умных» программ спонтанно менять раскладку.
- Возможность вводить буквы с диакритикой и кучу других символов.
- Возможность легко отредактировать раскладку по вкусу.
Комбинация клавиш | Результат |
---|---|
AltGr+5 | € |
AltGr+9 | » |
AltGr+0 | » |
AltGr± | — |
AltGr+= | ≠ |
AltGr+; | ° |
AltGr+, | < |
AltGr+. | > |
AltGr+Shift+/ | /me |
AltGr+a,' | á |
AltGr+e,` | è |
AltGr+o,» | ő |
AltGr+n,~ | ñ |
AltGr+c,^ | ĉ |
р, ы, AltGr+q,', б, а | ры́ба |
AltGr+c, o | © |
AltGr+r, o | ® |
AltGr+t, m | ™ |
AltGr+m, u | µ |
AltGr+h, s | ☭ |
AltGr+f,2 | ½ |
AltGr+b, f | █ |
Я просто заменяю системный файл C:\Windows\System32\kbdru.dll на свою раскладку, ведь она во всех отношениях лучше. На Windows XP или 2000 в таком случае нужно не забыть удалить C:\Windows\System32\dllcache\kbdru.dll.
Но если вам не по душе такой насильный апгрейд винды, то раскладку можно скопировать в папку C:\Windows\System32\ и зарегистрировать в системе с помощью такого reg-файла:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\07430419]
"Layout Text"="US+RU"
"Layout Display Name"="United States-International + Russian + Extra"
"Layout File"="kbdusru_undead.dll"
"Layout Id"="00d0"
Первая часть кода, 0743 — произвольные цифры для уникальной идентификации раскладки, а 0419 — код языка «Русский», под которым должна появиться раскладка. От кода языка зависит поведение раскладки в неюникодных (ANSI) программах.
Программировать на flat assembler’е мне доставляет одно удовольствие: мощный язык макросов, красивый и послушный синтаксис, ненужность всяких линковщиков и каши параметров в командной строке.
Поэтому я решил написать на нём программу, которая при ассемблировании читает DLL раскладки, а на выходе — исходный код. Странно, правда? Использовать ассемблер, как дизассемблер. Но мощь fasm’а это позволяет.
В результате у меня получились раскладки, которые позволяют переключаться между языками Caps Lock’ом без внешних программ глобально для всей системы, а также набор инструментов, который позволяет нам удобно редактировать раскладки клавиатуры Windows.
Всё выложено на https://github.com/grompe/kbdasm как общественное достояние.
Если у вас 64-битная Windows, можно скачать архив, распаковать и запустить make.bat, а затем install.bat. Для 32-битной придётся сперва подправить файл kbdusru_undead.asm.
Также в архиве есть программа get_scancodes. Если у вас есть хитрая клавиатура с дополнительными клавишами, с помощью программы можно узнать скан-коды и задействовать эти клавиши в раскладке.