Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Взаимодействие между драйвером геймпада и драйвером другого оборудования  (Прочитано 13038 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
Alpha
Интересующийся

ru
Offline Offline

« : 13-05-2010 06:21 » 

Здравствуйте!
У меня вопрос по поводу написания драйвера для геймпада Saitek P2500 Rumble Pad под Windows XP.
Я написал драйвер, он отлавливает нажатые кнопки, и в клиентском приложении я показываю, какие кнопки нажаты. Всё бы хорошо, но мне необходимо ещё эмулировать нажатия кнопок на геймпаде, как нажатие клавиш клавиатуры, например, пользователь нажимает кнопку 1 на геймпаде, а Windows понимает, что нажата клавиша <Windows>+<E>.
Не пойму, как это сделать. Надо формировать IRP пакет стандартному драйверу клавиатуры? или надо писать ещё один драйвер-фильтр для клавиатуры, который будет связан с моим драйвером геймпада? Или можно вызвать какую-нибудь функцию WinAPI режима ядра, если, конечно такие бывают?
Как организовать взаимодействие между двумя драйверами для разного оборудования?
Заранее спасибо!
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 13-05-2010 13:31 » 

Ну если "нажимать" Win+E (или чего-то другое) именно в ядре, то мне кажется надо смотреть на Keyboard Class Driver. Он, как я понимаю, обрабатывает как HID так и не HID клавиатуру. В WDK вроде есть даже исходники его (могу ошибаться).

\src\input\kbdclass\
« Последнее редактирование: 13-05-2010 14:09 от resource » Записан
Alpha
Интересующийся

ru
Offline Offline

« Ответ #2 : 15-05-2010 19:41 » 

Посмотрел пример, находящийся в src\input\kbfiltr\sys
Я правильно понимаю, мне необходимо в драйвере создать объект PDO клавиатуры, зарегистрировать GUID клавиатуры? и уже с ней общаться.
Только не пойму, какая функция для этого используется?
в контексте драйвера объявляются структуры, как я понял, которые мне и нужны
Код:
    // Write function from within KbFilter_IsrHook
    //
    IN PI8042_ISR_WRITE_PORT IsrWritePort;

    //
    // Queue the current packet (ie the one passed into KbFilter_IsrHook)
    //
    IN PI8042_QUEUE_PACKET QueueKeyboardPacket;

    //
    // Context for IsrWritePort, QueueKeyboardPacket
    //
    IN PVOID CallContext;
Далее мне нужно создать еще одну очередь управления запросами на запись в клавиатуру
Код:
    // Create a new queue to handle IOCTLs that will be forwarded to us from
    // the rawPDO.
    //
    WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig,
                             WdfIoQueueDispatchParallel);

    //
    // Framework by default creates non-power managed queues for
    // filter drivers.
    //
    ioQueueConfig.EvtIoDeviceControl = KbFilter_EvtIoDeviceControlFromRawPdo;
и наконец в обработчике этой callback-функции написать что-то наподобие этого?
Код:
    // Attach this driver to the initialization and byte processing of the
    // i8042 (ie PS/2) keyboard.  This is only necessary if you want to do PS/2
    // specific functions, otherwise hooking the CONNECT_DATA is sufficient
    //
    case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:

        DebugPrint(("hook keyboard received!\n"));

        //
        // Get the input buffer from the request
        // (Parameters.DeviceIoControl.Type3InputBuffer)
        //
        status = WdfRequestRetrieveInputBuffer(Request,
                            sizeof(INTERNAL_I8042_HOOK_KEYBOARD),
                            &hookKeyboard,
                            &length);
        if(!NT_SUCCESS(status)){
            DebugPrint(("WdfRequestRetrieveInputBuffer failed %x\n", status));
            break;
        }

        ASSERT(length == InputBufferLength);

        //
        // Enter our own initialization routine and record any Init routine
        // that may be above us.  Repeat for the isr hook
        //
        devExt->UpperContext = hookKeyboard->Context;

        //
        // replace old Context with our own
        //
        hookKeyboard->Context = (PVOID) devExt;

        if (hookKeyboard->InitializationRoutine) {
            devExt->UpperInitializationRoutine =
                hookKeyboard->InitializationRoutine;
        }
        hookKeyboard->InitializationRoutine =
            (PI8042_KEYBOARD_INITIALIZATION_ROUTINE)
            KbFilter_InitializationRoutine;

        if (hookKeyboard->IsrRoutine) {
            devExt->UpperIsrHook = hookKeyboard->IsrRoutine;
        }
        hookKeyboard->IsrRoutine = (PI8042_KEYBOARD_ISR) KbFilter_IsrHook;

        //
        // Store all of the other important stuff
        //
        devExt->IsrWritePort = hookKeyboard->IsrWritePort;
        devExt->QueueKeyboardPacket = hookKeyboard->QueueKeyboardPacket;
        devExt->CallContext = hookKeyboard->CallContext;

        status = STATUS_SUCCESS;
        break;
потому что IOCTL_INTERNAL_I8042_HOOK_KEYBOARD перехватывает прерывания, идущие клавиатуре
Но как-то не понятно, а где собственно изменение данных?
Callback-функции, которые присваиваются в этой части кода очень интересные - они перенаправляют запрос вниз по стеку драйверов, или нет? Например функция, которая вызывается в начале прерывания клавиатуры
Код:
BOOLEAN
KbFilter_IsrHook(
    PVOID                  IsrContext,
    PKEYBOARD_INPUT_DATA   CurrentInput,
    POUTPUT_PACKET         CurrentOutput,
    UCHAR                  StatusByte,
    PUCHAR                 DataByte,
    PBOOLEAN               ContinueProcessing,
    PKEYBOARD_SCAN_STATE   ScanState
    )
/*++

Routine Description:

    This routine gets called at the beginning of processing of the kb interrupt.

    i8042prt specific code, if you are writing a packet only filter driver, you
    can remove this function

Arguments:

    DeviceObject - Our context passed during IOCTL_INTERNAL_I8042_HOOK_KEYBOARD

    CurrentInput - Current input packet being formulated by processing all the
                    interrupts

    CurrentOutput - Current list of bytes being written to the keyboard or the
                    i8042 port.

    StatusByte    - Byte read from I/O port 60 when the interrupt occurred

    DataByte      - Byte read from I/O port 64 when the interrupt occurred.
                    This value can be modified and i8042prt will use this value
                    if ContinueProcessing is TRUE

    ContinueProcessing - If TRUE, i8042prt will proceed with normal processing of
                         the interrupt.  If FALSE, i8042prt will return from the
                         interrupt after this function returns.  Also, if FALSE,
                         it is this functions responsibilityt to report the input
                         packet via the function provided in the hook IOCTL or via
                         queueing a DPC within this driver and calling the
                         service callback function acquired from the connect IOCTL

Return Value:

    Status is returned.

--*/
{
    PDEVICE_EXTENSION devExt;
    BOOLEAN           retVal = TRUE;

    devExt = (PDEVICE_EXTENSION)IsrContext;

    if (devExt->UpperIsrHook) {
        retVal = (*devExt->UpperIsrHook) (
                        devExt->UpperContext,
                        CurrentInput,
                        CurrentOutput,
                        StatusByte,
                        DataByte,
                        ContinueProcessing,
                        ScanState
                        );

        if (!retVal || !(*ContinueProcessing)) {
            return retVal;
        }
    }

    *ContinueProcessing = TRUE;
    return retVal;
}

Помогите, пожалуйста, разобраться, как всё-таки сэмулировать нажатие кнопки на клавиатуре Улыбаюсь
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 16-05-2010 20:24 » 

изменения - это по воле пользователя. их просто не включили в код... чтобы по умолчанию драйвер работал "прозрачно" для системы.
дома DDK не стоит. а на работе увы - дел не в проворот...
я так понимаю что это должен быть драйвер фильтр. который пропускает через себя запросы прерываний от клавиатуры и передает их собственно драйверу клавиатуры. собственно вам, насколько я понимаю, необходимо отправлять дополнительные запросы путем вызова
Код:
retVal = (*devExt->UpperIsrHook) (
                        devExt->UpperContext,
                        CurrentInput,
                        CurrentOutput,
                        StatusByte,
                        DataByte,
                        ContinueProcessing,
                        ScanState
                        );
... если я правильно...)) время будет - посмотрю повнимательней.. но ничего не обещаю А черт его знает....... работа Ага
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Alpha
Интересующийся

ru
Offline Offline

« Ответ #4 : 17-05-2010 06:43 » 

... мне необходимо эмулировать нажатия кнопок на геймпаде, как нажатие клавиш клавиатуры, например, пользователь нажимает кнопку 1 на геймпаде, а Windows понимает, что нажата клавиша <Windows>+<E>...
Т.е. я написал драйвер под геймпад, который является USB HID-устройством, а теперь мне надо добавить в него такую функциональность, как эмулирование нажатия кнопок клавиатуры кнопками на геймпаде
Спасибо за советы, Ochkarik ! Сейчас буду пробовать.
По идее работают же "горячие" кнопки, например, на мультимедийной клавиатуре. Значит и с геймпадом такое тоже можно сделать.
Я правильно написал, что ещё в драйвере необходимо создать PDO клавиатуры, зарегистрировать её GUID и подключиться к стеку драйверов клавиатуры, чтобы была возможность отслеживать IRP пакеты клавиатуры?
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 18-05-2010 06:58 » 

да нет, то что это возможно "в принципе" - вопросов не вызывает)
а вот как это сделать лучше...)
вам по сути отслеживать клавиатуру не надо... вам надо как-то отсылать пакеты  о нажатых кнопках от ее имени.

а вот тут есть варианты... может, раз у вас все равно HID устройство... напрямую от имени драйвера геймпада нельзя напрямую такую информацию отсылать? как будто это HID клавиатура?)

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

PS а что у вас за драйвер получился? можно полюбопытствовать?)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 18-05-2010 14:57 » 

Там всё маленько не так. Там идет ирп в стэк славиатуры. Проходит до самого низа (т.е. если это усб клава, то скорее всего до HIDCLASS) и ждет. Когда нажимается кнопка, то ирп заполняется, завершается и идет обратно.

Что за драйвер для HID-геймпада - я представляю очень примерно, потому как для HID мышей, клав, геймпадов дров писать специальных не надо как правило. Да и для хид-девайсов там драйвер то и не делает ничего. Надо только структуры заполнить и всё.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 18-05-2010 22:15 » 

Цитата
Проходит до самого низа (т.е. если это усб клава, то скорее всего до HIDCLASS) и ждет. Когда нажимается кнопка, то ирп заполняется, завершается и идет обратно.
хм, забавно... и немного странно...
но если IRP запрос отсылается сверху и доходит до самого низа стека, то он там и будет ожидать завершения? таким образом, получается, что фильтром тут обойтись нельзя, так как новый IRP не будет послан, пока не завершится предыдущий, который ожидает события клавиатуры, а старый завершить нельзя, потому что мы его уже пропустили ниже?
либо на каждый приходящий сверху IRP надо отправлять дублирующий для ниже-лежащего устройства, а входящий IRP задерживать, пока не завершится его дубль, либо пока не будет надобности сгенерировать эмуляцию нажатия? какой то дурацкий вариант получается....

PS я почему то думал, что инициатором должно  являться устройство. тупо по прерыванию, будь то USB или PS/2 А черт его знает...
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 19-05-2010 06:11 » 

Да, не всё так просто получается. Тут подумать придется.

Цитата: Ochkarik
PS я почему то думал, что инициатором должно  являться устройство. тупо по прерыванию, будь то USB или PS/2 А черт его знает...

Я прям утверждать не буду, что всё 100% так, как я описал. Но.... я думаю что оно так.
К тому же устройство как может быть инициатором? Чтоб данные считать нужен ИРП. А я что-то не очень представляю как устройство по прерыванию может сказать системе, что есть данные, и уже можно слать ИРП чтоб их прочитать. Тут ведь системный сервис, а не свой собственный.
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 19-05-2010 06:23 » new

Кстати, kbdclass, опять же как я думаю, прерывания не обслуживает, HIDClass выступает в роли шины, но сам он, так же, прерываний никаких не обслуживает (USB же). Он получает PDO от шины USB, и дальше разрывает стэк, т.е. по сути создает новый стэк уже следующего уровня. Я просто этой темой не озадачивался. Но если бы озадачился, то первым делом посмотрел бы стэк устройств. Самый интерес тут - часть от HIDClass до kbdclass - что там между ними есть. Картинки из WDK это конечно хорошо, но лучше видеть всё своими глазами.
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 19-05-2010 15:21 » 

Такой вариант в конечном итоге потребует отменять ИРПы (которые сидят внизу). Не знаю, можно ли отменять не свои ИРПы, и что из этого получится.
Возможно самым красивым будет вариант - поднять девайс "клавиатура". И совершенно легально и быстро выполнять свою задачу.
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 19-05-2010 15:29 » 

в общем, тут коллега правильно подсказал, что не за чем велосипеды мастерить. Можно в юзер-моде вызывать себе спокойно SendInput и всё будет круто.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines