Есть ли способ эмулировать клавиши со стрелками в драйверах клавиатуры Windows? - PullRequest
3 голосов
/ 14 марта 2011

В настоящее время я пишу драйвер клавиатуры для Windows, который предоставляет дополнительный модификатор и позволяет напрямую вводить некоторые дополнительные символы. Например, реальные кавычки («,», ‘,’,…) и некоторые математические символы (ℕ, ℝ, ℚ, ℤ, √,…).

Теперь я хочу предоставить клавиши со стрелками просто так. (alt_gr + e = вверх; alt_gr + s = слева; alt_gr + d = вниз; alt_gr + f = вправо)

Так что мой вопрос, если есть клавиши управления Unicode для клавиш со стрелками, которые я мог бы использовать в моем aVkToWcharTable или, возможно, другом решении. Это было бы очень полезно.

1 Ответ

3 голосов
/ 18 марта 2011

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

Однако я использую макет NEO (или точнее вариант AdNW) и мне было любопытно, поэтому я скачал DDK, чтобы посмотреть, что я могу узнать из документации. У меня действительно нет решения для вас, и я думаю, что вы, возможно, уже знаете некоторые из этих вещей, но я подумал, что записать то, что я нашел, может все-таки пригодиться, хотя бы немного прояснить ситуацию.

Обзор

Насколько я могу судить, существует два пути получения данных с клавиатуры. Есть устройства PS / 2, а затем есть USB-клавиатуры. Оба выбирают разные пути (данные USB имеют свой источник в инфраструктуре HID, а данные PS / 2 генерируются драйвером I8042prt), но в конечном итоге получают так называемый «драйвер класса клавиатуры».

С этого момента данные передаются либо в DirectInput, либо в устаревший интерфейс user32. Не совсем понятно, где макет вступает в игру, но я думаю, что он реализован поверх драйвера класса Keyboard.

Компоновка

Раскладки клавиатуры в основном кажутся набором структур данных, соответствующих структуре KBDTABLES, определенной в kbd.h. Обычно низкоуровневые драйверы создают ScanCode, и интерпретация этих кодов выполняется с помощью этой структуры.

Первыми важными являются pusVSCtoVK, pVSCtoVK_E0 и pVSCtoVK_E1, которые отображают необработанные коды сканирования (и расширенные коды сканирования) драйвера на аппаратно-независимые коды виртуальных ключей. Эти коды клавиш описывают клавишу . Отображение персонажа приходит позже. Таким образом, левая клавиша курсора выдает VK_LEFT, а клавиша S выдает VK_S, даже если раскладка превращает это во что-то еще позже.

Далее следует pCharModifiers, который указывает, какие виртуальные ключи являются модификаторами и какие комбинации создают различные состояния сдвига.

Наконец, есть pVkToWcharTable, который отображает все виртуальные ключи в символ Unicode, в зависимости от состояния сдвига. Это где большая часть фактического макета находится. Существуют некоторые специальные значения для мертвых ключей и лигатур, но давайте пока это оставим.

Приложения

Что теперь получают приложения в конце? Очевидно, они могут получить код виртуального ключа и код сканирования из обычных оконных сообщений, таких как WM_INPUT, WM_KEYDOWN,…. Они также могут запрашивать макет для символа Unicode, используя такие функции, как ToUnicodeEx. Коды виртуальных клавиш и символы Unicode предоставляются макетом.

Для обычных персонажей все хорошо. Приложение получит входное событие, запросит раскладку для персонажа и все готово. Клавиши курсора отличаются, потому что отображение виртуальной клавиши на символ не является ни необходимым, ни значимым. Приложение заботится о ключе, но не о персонаже. Таким образом, действие будет основано на коде виртуальной клавиши. Если это VK_LEFT, курсор перемещается влево. Если это VK_RIGHT, курсор перемещается вправо и т. Д.

Это ставит нас перед дилеммой: если мы хотим заставить ModX + S переместить курсор влево, pVkToWcharTable с учетом модификаторов нам не поможет, потому что приложения никогда не запрашивают символ, а только клавишу. И ясно, что S - это не та же клавиша, что и левая клавиша. Создание управляющего символа (которого, насколько я могу судить, не существует), скорее всего, тоже не поможет, потому что приложения не будут его запрашивать и не интерпретируют.

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

А как насчет Нумпада?

Кажется, Numpad делает то, что требуется. Сканирующий код ключей остается неизменным, но в зависимости от состояния Numlock они создают разные коды виртуальных ключей. Я думаю, однако, что Windows делает некоторую особую обработку здесь. Эти клавиши имеют флаг KBDNUMPAD, установленный в pusVSCtoVK. Похоже, что Windows обнаружит это и обменяется виртуальными ключами в зависимости от состояния Numlock.

Я, по крайней мере, нашел доказательства этого. Попробуйте поискать «xxxNumpadCursor» в Google. Оказывается с каким-то, казалось бы, утекшим кодом Windows. Есть проверка на KBDNUMPAD и код, который, кажется, заменяет виртуальный ключ, в зависимости от Shift и Numlock. Я сомневаюсь, что это может быть использовано для этой цели.

Это вообще возможно?

Так что, если макет не может сделать это, кто может? Очевидно, какой-то низкоуровневый драйвер, который производит необработанные коды сканирования. В DDK есть пример так называемого драйвера фильтра, который называется «kbfiltr». По сути, кажется, что такой драйвер фильтра может подключаться поверх существующих драйверов и перезаписывать данные, поступающие от драйвера, поэтому должна быть возможность переписать код сканирования клавиши S влево, если нажата другая клавиша.

Обратите внимание, что это будет драйвер, а не макет. Я не уверен, что это практическое решение. Насколько я понимаю, он не знает о выбранном макете, поэтому изменения будут применяться ко всем макетам. (Возможно, здесь будет возможно реализовать весь макет с ключом для его выключения.) Я также не уверен, насколько сложной будет установка такого драйвера, и если вам нужно подписать драйвер, что все хуже.

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

Обновление

Я провел еще несколько исследований. Я думаю, что это можно сделать с помощью драйвера фильтра. Этот драйвер обычно находится между инфраструктурой HID или драйвером I8042prt и драйвером класса Keyboard. Затем он может изменить данные до того, как они поступят в драйвер класса, и заменить / удалить / добавить ключевые события до того, как они поступят туда. В конце вам придется использовать специальную раскладку (для дополнительных символов юникода), а также драйвер, который можно установить для отдельной клавиатуры через диспетчер устройств. Затем это решение должно работать для всех приложений.

Проблема здесь в подписи драйвера. Как драйвер режима ядра он должен быть подписан, чтобы загрузить его без уродливых хаков в 64-битной Vista / Win7. И это не дешево подписать водителя, так что вам в принципе не повезло с таким подходом. Я думал, что этого можно избежать, написав драйвер пользовательского режима (который не обязательно должен быть подписан), но проблема в том, что фильтр должен быть установлен ниже драйвера класса Keyboard. К сожалению, кажется, что драйвер фильтра режима пользователя не может иметь драйвер режима ядра выше него. Так что это не вариант.

Так что я думаю, что вы в основном застряли с AutoHotkey. Если вы не хотите и не можете написать драйвер режима ядра и жить с проблемой подписи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...