понедельник, 9 августа 2010 г.

Как мне, #$%, получить имя клавиатуры?

Это перевод How do I get the @!#$% name of the keyboard? Автор: Майкл Каплан.

Я сделал намёк на проблемы с концепцией HKL в моём словарике клавиатурных терминов. Но у меня есть несколько бывших подружек, которые объединены одним общим фактом: они все считают, что я не умею делать тонкие намёки, и вообще мне пора это прекратить. Поэтому: вот вам формальное обсуждение проблем терминологии и значения HKL в Windows.

Многое из нижеследующего я узнал во время разработки MSKLC - мне пришлось закапываться в клавиатурные раскладки, и у меня появился шанс посмотреть, насколько сложны некоторые части (не говоря уже о запутанности).

Проблема начинается ещё в терминологии. HKL (очевидно) изначально означало "handle to a keyboard layout" (описатель клавиатурной раскладки), но после признания факта, что у нас есть много других вещей, кроме клавиатур, он стал расплывчато определяться в Platform SDK как "идентификатор локали ввода" (закрывая глаза на тот факт, что это не идентификатор и не имеет отношения к локали). Также, из описания GetKeyboardLayout (и я думаю, что это очень длинное определение), "...младшее слово содержит идентификатор языка для языка ввода, а старшее слово содержит описатель устройства для физической раскладки клавиатуры".

Очевидно, что это не совсем так на некоторых платформах, где описатели имеют размер 64 бита, поэтому, на самом деле, здесь говорится только о младшей 32-х битной части этого значения. Но всё равно это только запутывает, потому что если у меня загружена только US-English клавиатура, и я вызываю GetKeyboardLayout, то она вернёт мне $409, что означает, что старшее слово равно $0000 - это очевидно недопустимый описатель чего бы то ни было.

Кроме того, у нас есть и проблема полезности. Заметили, что здесь нет настоящей информации о самой клавиатурной раскладке? Тут есть информация о языке, но это не язык клавиатурной раскладки, это язык, под который пользователь поместил раскладку после выбора пары язык/раскладка в диалоге "Добавить клавиатурную раскладку".

Так что же мне делать, чтобы найти раскладку? Ну, скажем, если я хочу (к примеру) загрузить её снова для пользователя, да или даже просто показать ему её имя? Ну, если это текущая раскладка в вашем потоке, то вы можете вызвать функцию GetKeyboardLayoutName, которая утверждает, что она "возвращает имя идентификатора активной локали ввода (ранее называемой клавиатурной раскладкой)". Только... она этого не делает. Она возвращает строку из 8 символов, которая содержит KLID, что не очень-то похоже на имя, если только вы не говорите на языке, в словаре которого есть слова вроде "00030409".

Все остальные люди в мире (включая меня) хотят получать нормальное имя и ожидают увидеть что-то вроде "United States-Dvorak for left hand". Чтобы получить эту строку, мне придётся зайти в HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00030409 и посмотреть на значение "Layout Text". Или, быть может, у меня стоит MUI версия Windows, и я сменил свой язык и у меня Windows >= XP, то это не та строка, а мне нужна "Layout Display Name", в которой записано такое полезное значение как "@%SystemRoot%\system32\input.dll,-5027" (которое, к счастью, может быть скормлено функции SHLoadIndirectString). И самое прекрасное: всё это может в любой момент поменяться, и ничего из этого не является документированным.

Но что если раскладка не активна? Ну, в этом случае - упс. Потому что сейчас у вас нет никакой GetKeyboardLayoutNameEx, которая принимала бы HKL. Принимая во внимание косвенную природу этих "дескрипторных" строк, мне придётся провести кучу времени в недокументированных значениях в ключах HKCU\Keyboard Layout\Preload and HKCU\Keyboard Layout\Substitutes. И опять я должен помнить, что это всё может измениться и не документировано. Что делает еще менее привлекательным выяснение отображений Preload и Substitutes (в случае, если я был достаточно мазохистом, чтобы находить это привлекательным до этого момента)...

Хотя это будет несколько дорогостояще, но я не могу не подумать про вариант создания потока, переключения в нём раскладки с последующим вызовом GetKeyboardLayoutName - что и приведёт к цели. Никто не получит никаких специальных уведомлений, и не будет зависимости от недокументированных структур реестра.

Или, может быть, мне стоит отправить куда-нибудь запрос на GetKeyboardLayoutNameEx? :-)

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.