Курсовая разраб. драйвера клавы. Разработка драйвера клавиатуры
Скачать 113.94 Kb.
|
Министерство науки и высшего образования Российской Федерации ФГБОУ ВО «Дагестанский государственный технический университет» Факультет КТВТиЭ Кафедра ПОВТиАС Пояснительная записка к курсовой работе по дисциплине: «Системное программное обеспечение» на тему: «Разработка драйвера клавиатуры» Выполнил: ст-т 3 курса, гр. ЗУ92 Тепляков Д.А. Принял: ст. пр. Кобзаренко Д.Н. Махачкала 2021 г. Аннотация Основной целью данного проекта является разработка программного обеспечения для упрощения буквенно-цифрового ввода при невозможности использовать весь функционал стандартной буквенной клавиатуры. Программный продукт должен быть совместим с современными ОС семейства Windows (Windows XP, Windows Vista, Windows 7), работающими на архитектуре x86. Проект содержит код для написания программы. Министерство Науки и Высшего Образования РФ ФГБОУ ВО «Дагестанский государственный технический университет» Факультет Компьютерных технологий, вычислительной техники и энергетики Кафедра Программное обеспечение вычислительной техники и автоматизированных систем Направление Управление в технических системах. Профиль Управление и информатика в технических системах З А Д А Н И Е на курсовую работу Студенту 3 курса ЗУ-92 группы Теплякову Денису Алексеевичу 1. Тема курсовой работы Разработка драйвера клавиатуры. 2. Дата выдачи задания «30» ноября 2021 г. 3. Дата сдачи курсовой работы на кафедру «21» декабря 2021 г. 4.Цель курсовой работы Разработать драйвер клавиатуры 5. Исходные данные (технические; экономические, организационные и другие требования и решения для выполнения проекта) ОС - Windows, Язык программирования –С++ 6. Перечень разделов, подлежащих разработке в курсовой работе 6.1.Введение. Глава 1. Теоретический раздел Глава 2. Технологический раздел Заключение 6.2. Список использованных источников Конспект лекций по СПО за 2021 год. 7. Календарный план-график выполнения работ по проектированию
Задание выдал руководитель (Д.Н. Кобзаренко) Задание принял студент (Д.А. Тепляков) Содержание
Введение Функциональные возможности стандартной 101/102 кнопочной клавиатуры достаточно широки и удовлетворяют большинству потребностей рядового пользователя. Однако бывают ситуации, когда возможность воспользоваться ими в полном объёме отсутствует. Например, при выходе из строя части букв на дополнительной клавиатуре и невозможности её немедленной замены может возникнуть необходимость завершить набор какой-либо текстовой информации. В такой ситуации необходимо будет воспользоваться экранной клавиатурой, что не очень удобно. Альтернативной возможностью является использование специализированного программного обеспечения, которое предоставит достаточно удобный, функциональный и привычный способ набора данных, например реализация классического телефонного буквенного ввода на дополнительной клавиатуре. Глава I. Теоретический разделАнализ задачиДля реализации поставленной задачи требуется написать два взаимосвязанных приложения: приложение-драйвер клавиатуры и приложение пользовательского режима, взаимодействующее с драйвером и упрощающее работу с ним. Приложение-драйвер должно обладать следующими функциями: . Обеспечивать ввод букв русского и английского алфавита с дополнительной клавиатуры аналогичный по принципу, применяемому в мобильных телефонах; . Так как дополнительная клавиатура является функциональным элементом, предоставляющим возможность быстрого ввода цифровой информации, необходимо обеспечивать режимы работы как стандартный, так и расширенный, с возможностью ввода буквенной информации; . Обеспечить корректную работу в любом текстовом редакторе или окне ввода; . Быть простым в использовании; . Не нарушать и не замедлять работу системы. В свою очередь, приложение пользовательского режима должно дополнять драйвер следующим функционалом: . Обеспечить вывод корректной информации о выбранном символе в дополнительное окно вывода; . Предоставить элементы управления, для быстрого переключения режимов ввода (обычный цифровой ввод / расширенный ввод). Определение типа разрабатываемого программного обеспеченияВ связи с описанными выше требованиями к функциональности, становится очевидным, что реализуемый драйвер должен выполняться в режиме ядра, так как нам необходимо разработать драйвер устройства, напрямую взаимодействующий с подсистемами ядра ОС. Это связано также с тем, что разрабатываемый драйвер, в частности, должен обрабатывать запросы на ввод-вывод, посылаемые всеми приложениями, используемыми пользователем. Необходимо так же определить какой тип и класс драйвера будет разрабатываться, о чём будет сказано в дальнейшем. Классификация драйверов• Драйверы режима ядра • Драйверы файловых систем • Унаследованные • Драйверы Plug and Play (PnP) • Видеодрайверы • Драйверы пользовательского режима • Драйверы виртуальных устройств Модель WDMWindows driver model (WDM) - это спецификация, созданная для упрощения процесса построения драйверов, в данный момент являющаяся стандартной. В соответствие с требованиями корпорации Microsoft все новые драйверы должны разрабатываться, следуя данной спецификации. Это, помимо следования структуре WDM подразумевает также поддержку Plug and Play (PnP) и управления электропитанием. В модели WDM используется многоуровневый подход, в соответствии с которым каждое устройство управляется минимум двумя драйверами: драйвером шины и функциональным драйвером. Также к устройству могут быть подключены драйверы фильтров. В категории драйверов WDM выделяют: Драйверы шин - управляют логическими или физическими шинами. Отвечают за распознавание устройств, подключённых к управляемой ими шине и оповещение о них диспетчера PnP. В контексте WDM шина — это любое устройство, к которому подключены другие физические, логические или виртуальные устройства. Функциональные драйверы - драйверы, реализующие все операции, необходимые для поддержки работы устройства. Драйверы классов - драйверы, предназначенные для управления устройствами, относящимися к определенному классу (например, мышь, клавиатура). Минидрайверы - драйверы, предоставляющие драйверам классов специфическую поддержку для конкретного производителя. Следует отметить, что зачастую производитель пишет минидрайвер, который реализует специфический функционал, а для дальнейшего обслуживания устройства вызывает драйвер класса. Вместе, драйвер класса и минидрайвер работают как функциональный драйвер для устройства. Драйверы фильтров - драйверы, перехватывающие операции ввода/вывода для конкретных устройств с целью их расширения или модификации. Их также можно подразделить на: • Драйверы фильтров шин; • Низкоуровневые драйверы фильтров (используются для перехвата обращений к портам ввода-вывода); • Высокоуровневые драйверы фильтров (используются при обработке запросов, идущих от пользователя). Как известно, большинство операций ввода-вывода, за исключением операций быстрого ввода/вывода, осуществляются с использованием IRP пакетов. Диспетчер ввода-вывода создаёт IRP пакет и передаёт указатель на него драйверу конкретного устройства. Каждый драйвер имеет связанный с ним объект устройства - структуру данных, содержащую указатели на рабочие процедуры драйвера, которые позволяют взаимодействовать драйверу с диспетчером ввода-вывода. Объекты устройств объединены в стек устройства. Внизу стека устройств находится создаваемый драйвером шины объект физического устройства (Physical Device Object - PDO), который создаётся драйвером шины при обнаружении подключения физического устройства. Основным компонентом стека устройств является объект функционального устройства (Functional Device Object - FDO), связанный с функциональным драйвером. Вокруг функционального объекта может быть расположено произвольное количество устройств - фильтров (Filter Device Object - FiDO), создаваемых драйверами фильтров. В данной работе реализуется обработка и модификация запросов, приходящих с клавиатуры (от пользователя), поэтому наиболее подходящим вариантом решения данной задачи является разработка драйвера - фильтра верхнего уровня. Модель WDFВ связи с наличием у драйверной модели WDM ряда недостатков ей на смену приходит новая драйверная модель - Windows Driver Foundation (WDF). WDF представляет собой событийно-управляемую, объектно-ориентированную среду для драйверов режима ядра KMDF (Kernel-Mode Driver Framework) и для драйверов пользовательского режима UMDF (User-Mode Driver Framework). Модель WDF значительно упрощает разработку драйверов. Данная модель построена на понятии инфраструктуры - Framework, на которую возложено: управление жизненным циклом объектов; управление потоком запросов ввода/вывода и уведомлениями питания PnP; определение объектов WDF, которые могут быть инстанцированы WDF-драйверами; предоставление набора DDI - функций, которые могут использоваться WDF - драйверами для управления объектами. Для предоставления функциональности, специфичной для конкретного устройства Framework вызывает драйвер WDF. Модель WDF определяет набор объектов, представляющих структурные компоненты драйверов: устройства, память, очереди, запросы ввода/вывода и сам драйвер. Объекты инфраструктуры предоставляют программный интерфейс, который включает в себя: • Методы - функции, которые могут быть вызваны драйвером для выполнения операций над объектами и изменения их свойств; • Свойства - доступные драйверу характеристики объекта; • Функции обратного вызова, необходимые для обработки событий, которые могут быть сгенерированы инфраструктурным объектом. Драйвер не оперирует самим объектом WDF, вместо этого он получает его дескриптор, с помощью которого он может обращаться к объекту. Для разработки данного драйвера была выбрана инфраструктура KMDF, так как она представляет программную модель, поддерживающую разработку функциональных драйверов, драйверов-фильтров и драйверов шин. Сама инфраструктура является разделяемой между многими драйверами реентерабельной библиотекой. Структура KMDF-драйвераВсе драйверы KMDF должны иметь следующие компоненты: • Функция DriverEntry, которая является главной точкой входа в драйвер и создает инфраструктурный объект драйвера. • Функцию обратного вызова по событию EvtDriverDeviceAdd, которая создает и инициализирует объект устройства, а также вспомогательные объекты, необходимые для работы драйвера. • Одну или несколько функций обратного вызова EvtXxx, необходимых для обработки событий, возникающих во время работы драйвера. События PnP обычно реализуются стандартными методами инфраструктуры, поэтому их обработка не входит в состав базовых компонент драйвера. Также драйверам устройств PnP в общем случае не требуется реализовывать функцию выгрузки, так как инфраструктура предоставляет ее по умолчанию. DriverEntryDriverEntry (PDRIVER_OBJECT DriverObject, // указатель на объект драйвера WDM PUNICODE_STRING RegistryPath // указатель на путь в реестре ) { … } Это первая функция, вызываемая при загрузке драйвера в ОС. Ее вызывает диспетчер ввода/вывода; функция вызывается только один раз. Она должна выполнять следующие действия: • Создание объекта драйвера (WDFDRIVER), который представляет загруженный в память экземпляр драйвера; создание этого объекта регистрирует драйвер в инфраструктуре. • Регистрация функции обратного вызова EvtDriverDeviceAdd. • выделение требуемых глобально для драйвера ресурсов. • Регистрация функции обратного вызова EvtDriverUnload, если непосредственно перед выгрузкой драйверу необходимо совершить какие-либо операции. В случае успешного завершения функция возвращает STATUS_SUCCESS, в противном случае - код ошибки. Функция обратного вызова по событию EvtDriverDeviceAdd NTSTATUS KbFilter_EvtDeviceAdd (WDFDRIVER Driver, // дескриптор объекта драйвера PWDFDEVICE_INIT DeviceInit // указатель на структуру инициализации ) { … } Функция отвечает за создание и инициализацию объекта устройства (WDFDEVICE) и связанных с ним ресурсов. Вызывается инфраструктурой при получении уведомления от менеджера PnP об обнаружении нового подключенного устройства, контролируемого драйвером. Данная функция выполняет следующий набор операций: • заполнение структуры инициализации информацией, необходимой для создания объекта устройства; • организация области контекста объекта устройства (создание структуры расширения); • создание объекта устройства; • регистрация функций обратного вызова для событий ввода/вывода и создание очередей ввода/вывода для объекта устройства; • создание интерфейса устройства, если это требуется; • создание объекта прерываний, если устройство поддерживает прерывания; • создание объектов WMI. В случае успешного завершения функция возвращает STATUS_SUCCESS, в противном случае - код ошибки. Функции обратного вызова для обработки событий Драйвер KMDF создает эти функции для обработки связанных с объектом событий, например, поступления запроса ввода/вывода или изменения в состоянии энергопотребления, и регистрирует их в инфраструктуре. Инфраструктура предоставляет стандартные обработчики для событий, поэтому драйвер регистрирует только те из них, которые имеют отношение к обслуживаемым им устройствам. Например, если драйверу необходимо получать от приложения или компонент системы управляющие запросы (IRP с кодом IRP_MJ_CONTROL), он регистрирует функции обратного вызова EvtIoDeviceControl и EvtIoInternalDeviceControl соответственно. Для перехвата, идущего от устройства запроса и его обработки, в драйвере-фильтре предназначена функция обратного вызова KbFilter_Service Callback. Для решения задачи необходимо определить, какая из функций драйвера будет отвечать за преобразование вводимых с клавиатуры символов. Функция DriverEntry, отвечающая за загрузку драйвера, вызывается только один раз при загрузке системы, поэтому она для этой цели не подходит. Функция EvtDriverDeviceAdd вызывается только при подключении нового устройства, поэтому она тоже не подходит. Для решения задачи необходимо использовать функцию, использующуюся для обработки запросов ввод-вывода, то есть одну из функций обратного вызова. Так как для преобразования символов необходимо перехватывать и обрабатывать запросы, поступающие от клавиатуры, очевидно, что необходимо воспользоваться функцией KbFilter_Service Callback. Алгоритм работыДля выполнения поставленной задачи реализуемый драйвер должен выполнять следующие действия: . Включение и выключение режима расширения клавиатуры по нажатию заданной клавиши. Для реализации данной возможности в драйвере написаны функции включения и выключения. Данные функции активируются приложением пользовательского режима посредством IOCTL запросов. Приложение пользовательского режима предоставляет, в свою очередь, удобный интерфейс пользователя для управления работой драйвера. . Определение скан кода нажатой клавиши на дополнительной клавиатуре и вывод соответствующего символа алфавита из набора символов, ассоциированного с данной клавишей. Так как мы реализуем не просто замену одного символа на другой, а сопоставляем одну клавишу группе символов - нам необходимо реализовать механизм выбора требуемой буквы. Для этого производится сравнение текущей нажатой клавиши с предыдущей. Если скан код клавиши не изменился, то мы увеличиваем значение счётчика нажатий на 1, на основании чего впоследствии сможем сопоставить количеству нажатий нужную букву из ассоциированного клавише массива символов. Вывод выбранного символа производится при нажатии клавиши нуль. Ниже приводится таблица, в которой описано используемое в драйвере сопоставление клавиш. Таблица соответствия цифровых клавиш символам алфавита
Таким образом, весь алгоритм преобразований, производимых в реализованном драйвере-фильтре, выглядит следующим образом: . Анализ поля, отвечающего за статус драйвера: включён / выключен. Если включён - п. 2, иначе - п. 4; . Цикл по всем IRP-пакетам, приходящим с клавиатуры; . Для каждого IRP-пакета: 1. Установить переменную, определяющую, является ли пакет пакетом для вывода в TRUE; 2. Определить скан-код нажатой клавиши; 3. Проверить, нажат ли символ дополнительной клавиатуры, если да - перейти к п. 4., иначе - к п. 6.; 4. Установить переменную, определяющую, является ли пакет пакетом для вывода в FALSE; 5. Если кнопка была отжата - обновить статус: 5.1. Если скан-код не изменился - перейти к п. 5.2., иначе - к п. 5.3.; 5.2. Увеличить счётчик нажатий на 1; 5.3. Если кнопка была нажата: setted:=TRUE, преобразовать выбранный код в букву, иначе п. 5.4.; 5.4. Если кнопка была отпущена: setted:=TRUE, devExt->Working:=FALSE, преобразовать выбранный код в букву, иначе п. 5.5; 5.5. Если скан код нажатой клавиши равен 0x78, то изменить поле, отвечающее за используемый язык, иначе п. 5.6.; 5.6. Если кнопка была отжата - проинициализировать структуры новыми значениями. 6. Если пакет - пакет не для вывода - удалить его, иначе - п. 7; 7. Обработка пакета закончена, если указатель на пакет равен указателю на конечный пакет (цикл завершён) перейти к п. 4, иначе к п. 1.; . Передать IRP-пакет далее по стеку устройства подсистеме ядра. В Приложении А приведен исходный код, реализующий данный алгоритм, с комментариями (стр. 24-26). Ниже приведена схема данного алгоритма. Глава II. Технологический раздел2.1 Выбор платформы для разработкиВ качестве платформы для разработки драйвера была выбрана ОС Windows XP SP3, установленная на виртуальную машину, функционирующую под управлением Oracle Virtual Box версии 4.0.4. Virtual Box от Oracle был выбран потому, что он предоставляет широкий функционал для развёртывания виртуальных машин самых разных конфигураций, ограничивая пользователя лишь физическими характеристиками используемой машины. Благодаря функциональности данного программного обеспечения предоставляется возможность проверить работоспособность драйвера на разных конфигурациях оборудования. Ещё одним неоспоримым преимуществом данного программного продукта является то, что он распространяется по лицензии GNU GPL, т.е. реализация проекта с использованием Oracle Virtual Box не требует существенных финансовых вложений. 2.2 Выбор языка и среды программированияПри разработке драйверов режима ядра для Windows основным языком разработки является язык Си в сочетании с набором библиотек WDK. Поэтому именно они были выбраны для реализации данного задания. Язык Си обеспечивает высокую скорость работы, надёжность, позволяет осуществлять множество манипуляций с памятью. При этом данный язык является языком высокого уровня, предоставляющим высокий уровень абстракции. WDK — это полностью интегрированная система разработки, включающая в себя: набор необходимых библиотек, средств построения драйвера и наборы тестов для проверки его стабильности и надёжности. К сожалению, WDK не предоставляет IDE для разработки драйверов. Вследствие чего требуется использовать специализированные IDE или Visual Studio. Так как полная интеграция среды разработки Visual Studio с WDK не представляется возможной, компромиссным решением может быть использование плагина к Visual Studio - VisualDDK, который упрощает процесс интеграции возможностей WDK в Visual Studio. Так же обязательным требованием является наличие отладчика режима ядра. Для тестирования данной программы была выбрана программа DebugView, которая позволяет отслеживать корректность работы драйвера, выводя на экран отладочную печать. 2.3 Windows Driver KitКак было указано выше WDK является полностью интегрированной средой разработки. В её состав, в частности, входят следующие компоненты: Windows Driver Foundation (WDF), упрощающий разработку и поддержку драйверов для ОС Windows. Проверочные и статистические средства, такие как PREfast, Static Driver Verifier, помогающие найти ошибки в процессе компиляции. Кроме того, данный пакет включает набор отладочных средств для ОС семейства Windows. 2.4 VisualDDKЭто плагин для Visual Studio, предоставляющий ей дополнительную функциональность, позволяющую заниматься разработкой драйверов, используя привычный интерфейс среды Visual Studio. 2.5 Безопасность использованияДанный драйвер разрабатывался для операционной системы Microsoft Windows XP. В целях проверки безопасности и стабильности данного программного обеспечения, было проведено его тестирование на нескольких экземплярах виртуальных машины разных конфигураций под управлением ОС MS Windows XP SP 3, Windows Vista SP2, Windows 7 SP1. Также тестирование производилось на нескольких физических машинах с установленной ОС MS Windows. 2.6 Типы и структуры данныхСкан-коды нажатых или отпущенных клавиш хранятся в системном буфере. Доступ к этому буферу можно получить, если прочитать данные по адресу, хранящемуся в IRP пакете. Адрес хранится в поле AssociatedIrp.SystemBuffer. Буфер представляет собой массив структур типа KEYBOARD_INPUT_DATA. Эта структура состоит из следующих полей: UnitId типа USHORT. В нем хранится номер устройства, на котором нажали или отпустили клавишу; MakeCode типа USHORT. В этом поле хранится скан-код нажатой или отпущенной клавиши. Скан-код, переданный в этом поле, не определяет клавишу однозначно. Для полной идентификации клавиши необходимо значение поля Flags; Flags типа USHORT. Это поле несет дополнительную информацию о клавише, а так же определяет, нажали клавишу или отпустили. Если нулевой бит равен 0, то значит клавиша нажата, если же он равен 1, то она отпущена. Биты 1 и 2 используются для идентификации клавиши; Reserved типа USHORT. Поле является зарезервированным; ExtraInformation типа ULONG. Это поле содержит дополнительную информацию об устройстве. 2.7 Установка драйвераУстановка драйвера производится с помощью диспетчера устройств Windows: Пуск → Выполнить → devmgmt.msc; В открывшемся окне в списке устройств выбираем пункт «Клавиатуры», в выпадающем списке выделяем нужное устройство, кликаем правой кнопкой мыши, выбираем пункт «Обновить драйвер»; Откроется окно мастера обновления оборудования; Выбираем пункт «Установка из указанного места»; Выбираем пункт «Не выполнять поиск, я сам выберу нужный драйвер»; В появившемся окне нажимаем кнопку «Установить с диска» и указываем расположение установочного (*.inf) файла. 2.8 Управление драйвером. Пользовательский интерфейс.Для упрощения процесса взаимодействия с драйвером предоставляется приложение пользовательского режима, общий вид которого показан на рисунке (рис.1). Рис. 1. Вид основного окна управляющего приложения Приложение предоставляет минимально необходимый функционал: · вывод информации о клавиатуре; · управление состоянием драйвера (вкл. / выкл.); · управление режимом отображения (перекрывать / не перекрывать другие окна); · отображение выбранного символа. Интерфейс клиентского приложения предельно просто и не требует дополнительных разъяснений. 2.9 ТестированиеДрайвер был протестирован с использованием тестирующей утилиты DriverVerifier пакета WDK. С его помощью были проведены стандартные тесты, такие как: Корректность операций с пулами памяти Корректность уровней IRQL, на которых выполняется код драйвера Все тесты прошли успешно. Для того чтобы скомпилировать и собрать окончательную версию драйвера, была использована среда x86 Free Build Environment из пакета WDK. Драйвер был установлен на 4 физические машины, на которых использовался в течение пяти дней. За это время никаких нарушений в работе системы обнаружено не было. ЗаключениеПри выполнении курсового проекта была проделана следующая работа: • Изучена структура драйверов модели WDM и WDF; • Изучен стек устройства, путь запроса от приложения через стек устройства; • Определено место разрабатываемого драйвера в стеке устройства и выбрана структура программного обеспечения; • Изучен механизм встраивания драйвера-фильтра в стек драйверов; • Разработан функциональный механизм сопоставления некоторой цифровой клавише на дополнительной клавиатуре набора букв заданного алфавита; • Разработано программное обеспечение, удовлетворяющее требованиям технического задания; • Проведено тестирование, подтвердившее работоспособность и надёжность разработанного программного обеспечения. Список литературыПрограммирование принципы и практика с использованием C++, 2-е издание 2015 год. Орвик П. Windows Driver Foundation: разработка драйверов. - М.: Издательство «Русская редакция»; СПб.: «БХВ-Петербург», 2008. - 880 с. Солдатов В. П. Программирование драйверов Windows. - М.: ООО «Бином-Пресс», 2011. - 576 с. Лекции по дисциплине СПО за 2021г. Приложение АЛистинг исходного кода. Фрагмент драйвера._ServiceCallback (PDEVICE_OBJECT DeviceObject,PKEYBOARD_INPUT_DATA InputDataStart,PKEYBOARD_INPUT_DATA InputDataEnd,OUT PULONG InputDataConsumed) { BOOLEAN Setted = FALSE;_EXTENSION devExt;hDevice;_INPUT_DATA cur;_INPUT_DATA k;= WdfWdmDeviceGetWdfDeviceHandle(DeviceObject);= FilterGetData(hDevice); // Анализ поля, отвечающего за статус драйвера: включён / выключен. Если // включён - п.2, иначе - п. 4; if (devExt->Running) { // Цикл по всем IRP-пакетам, приходящим с клавиатуры for (cur = InputDataStart, k = InputDataStart; cur < InputDataEnd; cur++) { // Для каждого IRP-пакета DbgPrint("Scan code: %d", InputDataStart->MakeCode); // Установить переменную, определяющую, является ли пакет // пакетом для вывода в TRUE;= TRUE; // Определить скан-код нажатой клавиши // Если нажата клавиша в нумпаде if (IsNumPadKey(cur->MakeCode)) {("NumPad"); // Установить переменную, определяющую, является ли пакет // пакетом для вывода в FALSE; Setted = FALSE; // Далее если кнопка была отжата, то обновляем статус(TRUE) {("Break!"); // Если скан код не изменился if (devExt->Working && cur->MakeCode == devExt->CurMakeCode && cur->Flags & KEY_BREAK) {("Inc!"); // Увеличиваем // Если раскладка русская - везед делим по // модулю 4(!devExt->RusLat)>CurChar = (devExt->CurChar + 1) % 4; // значит раскладка английскаяif (devExt->CurMakeCode == 71 || devExt->CurMakeCode == 73)>CurChar = (devExt->CurChar + 1) % 4;>CurChar = (devExt->CurChar + 1) % 3; } // Если кнопка не была отпущена setted установить в TRUE и преобразовать // выбранный код в букву else if (devExt->Working && cur->MakeCode == 82 && !(cur->Flags & KEY_BREAK)) {("Out1!"); // если ноль, то выводим Setted = TRUE;(devExt->RusLat)>MakeCode = GetCharLat(devExt->CurMakeCode, devExt->CurChar);>MakeCode = GetCharRus(devExt->CurMakeCode, devExt->CurChar); } // Если кнопка была отпущена setted установить в TRUE, devExt->Working в // FALSE и преобразовать выбранный код в букву else if (devExt->Working && cur->MakeCode == 82 && cur->Flags & KEY_BREAK) {("Out2!"); // если ноль, то выводим Setted = TRUE;>Working = FALSE;(devExt->RusLat)>MakeCode = GetCharLat(devExt->CurMakeCode, devExt->CurChar);>MakeCode = GetCharRus(devExt->CurMakeCode, devExt->CurChar); } // Если скан код нажатой клавиши равен 0x78, то изменить поле, отвечающее за // используемый язык else if (cur->MakeCode == 78 && cur->Flags & KEY_BREAK) {>RusLat = !devExt->RusLat; }if (cur->Flags & KEY_BREAK) {("Start!"); // Иначе переинициализируем>Working = TRUE;>CurChar = 0;>CurMakeCode = cur->MakeCode; } } } // Если этот пакет не для вывода, то удаляем его if (!Setted) {>MakeCode = 0; } } // Обработка пакета закончена } (*(PSERVICE_CALLBACK_ROUTINE)(ULONG_PTR) devExt->UpperConnectData.ClassService)(>UpperConnectData.ClassDeviceObject,,, InputDataConsumed); } |