Здравствуйте!
Подскажите, пожалуйста, по следующей проблеме:
1. Имеется рабочее USB (не HID) Touch Screen устройство.
2. К нему идет оригинальный драйвер (речь о Windows), благодаря которому с помощью touch screen`а можно эмулировать мышку (перемещать курсор и т.д.). После инсталляции устройство в device mannager`е отображается как "Мыши и иные указывающие устройства"->"USB touch screen"
Моя задача заключается в том, чтобы написать подобный драйвер. Что сделано:
1. Написан PnP драйвер, который загружается при подключении устройства. Оно распознается как отдельное USB устройство.
2. Драйвер инициализирует USB устройство, считывает данные с него и затем рассчитывает X и Y.
Проблема — как ОС указать, что нужно переместить курсор:
1. Как драйвер может заставить OC переместить курсор? Есть ли в ядре эквивалент Win32 функции SendInput()?
2. В Inf файле оригинального драйвера указан класс устройства Class = Mouse, у меня же собственный класс Class = TestDevice. На сколько это важно?
A_>Проблема — как ОС указать, что нужно переместить курсор: A_>1. Как драйвер может заставить OC переместить курсор? Есть ли в ядре эквивалент Win32 функции SendInput()?
Ну, например, SetCursorPos() внутри себя использует IOCTL_VIDEO_SET_CURSOR_POSITION, попробуй.
A_>2. В Inf файле оригинального драйвера указан класс устройства Class = Mouse, у меня же собственный класс Class = TestDevice. На сколько это важно?
Для WDM-драйверов это важно, т.к. при установке драйвера системе нужно знать, в какой стек включать данный экземпляр. Подробнее у Уолтера Они и, конечно же, в документации.
Здравствуйте, x64, Вы писали:
A_>>Проблема — как ОС указать, что нужно переместить курсор: A_>>1. Как драйвер может заставить OC переместить курсор? Есть ли в ядре эквивалент Win32 функции SendInput()?
x64>Ну, например, SetCursorPos() внутри себя использует IOCTL_VIDEO_SET_CURSOR_POSITION, попробуй.
Поглядел описание в h файле — сложилось впечатление, что это довольно низкий уровень. У меня мысль была, что должна быть определенная очередь (input event queue или что-то подобное), добавив в которое событие мышки можно съэмулировать ее перемещение через touch screen. Кстати, оригинальный драйвер имеет class upper driver mouclass.sys и покопавшись в WDK http://msdn.microsoft.com/en-us/library/ms790230.aspx обнаружил такую фразу:
Connection of a class service callback routine that a function driver uses to transfer data from the input data buffer of the device to the data buffer of the class driver.
Остается понять, как подключить этот class driver. Возможно это и будет ответ на вопрос #2.
A_>>2. В Inf файле оригинального драйвера указан класс устройства Class = Mouse, у меня же собственный класс Class = TestDevice. На сколько это важно?
x64>Для WDM-драйверов это важно, т.к. при установке драйвера системе нужно знать, в какой стек включать данный экземпляр. Подробнее у Уолтера Они и, конечно же, в документации.
Спасибо. Скачал Уолтера, возможно в ней найду ответ.
x64>>IOCTL_VIDEO_SET_CURSOR_POSITION A_>сложилось впечатление, что это довольно низкий уровень.
Ну в общем, да, по крайне мере к стеку мышки отношения никакого не имеет.
A_>Остается понять, как подключить этот class driver.
Подключать его не надо, он сам придёт ибо системный, тебе нужно только попасть в стек класса "Mouse" к твоему устройству (группа запуска "Pointer Port"). Твой драйвер должен корректно обработать запрос IOCTL_INTERNAL_MOUSE_CONNECT, его тебе пошлёт mouclass.sys, предоставив адрес колбека в буфере. Всякий раз, когда твой драйвер получает информацию от физического устройства, он должен вызвать вышеуказанный колбек (в случае, если, конечно, таковой уже был зарегистрирован) и передать данные из своих внутренних буферов. Драйвер класса скопирует твои данные в свою внутреннюю очередь и затем уже будет отдавать эту информации подсистеме Win32 (процесс csrss.exe) через IRP_MJ_READ запрос. Но к твоему драйверу это уже не будет иметь никакого отношения, твоя задача перегнать данные в буфера mouclass'а, когда они у тебя появились, вот и всё. Схематично это выглядит так:
hardware <- bus <- port -> class -> win32 -> applications
Ты пишешь port driver, если я правильно понял.
Re[4]: Touch screen driver
От:
Аноним
Дата:
10.10.09 06:04
Оценка:
Здравствуйте, x64, Вы писали:
x64>>>IOCTL_VIDEO_SET_CURSOR_POSITION A_>>сложилось впечатление, что это довольно низкий уровень.
x64>Ну в общем, да, по крайне мере к стеку мышки отношения никакого не имеет.
A_>>Остается понять, как подключить этот class driver.
x64>Подключать его не надо, он сам придёт ибо системный, тебе нужно только попасть в стек класса "Mouse" к твоему устройству (группа запуска "Pointer Port"). Твой драйвер должен корректно обработать запрос IOCTL_INTERNAL_MOUSE_CONNECT, его тебе пошлёт mouclass.sys, предоставив адрес колбека в буфере. Всякий раз, когда твой драйвер получает информацию от физического устройства, он должен вызвать вышеуказанный колбек (в случае, если, конечно, таковой уже был зарегистрирован) и передать данные из своих внутренних буферов. Драйвер класса скопирует твои данные в свою внутреннюю очередь и затем уже будет отдавать эту информации подсистеме Win32 (процесс csrss.exe) через IRP_MJ_READ запрос. Но к твоему драйверу это уже не будет иметь никакого отношения, твоя задача перегнать данные в буфера mouclass'а, когда они у тебя появились, вот и всё. Схематично это выглядит так:
x64>
x64>hardware <- bus <- port -> class -> win
32 -> applications
x64>Ты пишешь port driver, если я правильно понял.
Да, получается что port driver . Есть определенный прогресс:
1. Подглядел оригинальный Inf файл, чтобы мой драйвер добавлялся в Mouse stack.
2. Добавил обработчики IOCTL_INTERNAL_MOUSE_CONNECT и IOCTL_INTERNAL_MOUSE_DISCONNECT. Первый из них срабатывает и я получаю корректные указатель на device и callback
3. Буферов/очередей для данных, которые считываются с touch screen устройства у меня нет. Я создал поток, который с помощью KeWaitForSingleObject ожидает данных с него. Как только данные получены они передаются с вызовом callback`а:
то есть с каждым вызовом передается одна пара координат.
4. Структуры формирую как указано в MSDN. После вызова callback`а в MouseInputs заносится 1. То есть вроде бы вызов прошел успешно, но мышка ни в какую не хочет двигаться. Есть подозрение, что не верно устанавливаю USHORT UnitId; структуры MOUSE_INPUT_DATA. Судя по исходникам mouclass.c это значение можно получить с помощью IOCTL_MOUSE_QUERY_ATTRIBUTES, однако в описании MOUSE_UNIT_ID_PARAMETER указано, что "Mouclass does not use the UnitID value."
Здравствуйте, x64, Вы писали:
A_>>Проблема решена — не обрабатывался IOCTL_MOUSE_QUERY_ATTRIBUTES запрос.
x64>Никто не знает твой код лучше, чем ты сам
Ну на самом деле хорошо было бы услышать мнение экспертов, так как это сократило бы время разработки. Так я убил пару дней, а человек, который прошел огонь и воду в конкретной области — может в течение часа ткнуть пальцем и сказать где проблема. В принципе, пишу для души, поэтому по времени ограничений нет, в случае же реального проекта — пришлось бы сидеть по вечерам/ночам.
Некоторые мысли по делу:
1. IOCTL_MOUSE_QUERY_ATTRIBUTES прилетает, только в случае успешного завершения обработчика IRP_MJ_CREATE. То есть последовательность при подключении устройства такая: IOCTL_INTERNAL_MOUSE_CONNECT -> IRP_MJ_CREATE -> IOCTL_MOUSE_QUERY_ATTRIBUTES. После этого можно вызывать callback. Если же обработчика IRP_MJ_CREATE в драйвере нет или он ошибку возвращает, то IOCTL_MOUSE_QUERY_ATTRIBUTES запроса не будет и смысла вызывать callback нет.
2. При отключении устройства срабатывает только IRP_MJ_CLOSE. IOCTL_INTERNAL_MOUSE_DISCONNECT почему-то не прилетает, что мне кажется странным. По идее этот запрос комплементарный к IOCTL_INTERNAL_MOUSE_CONNECT.
3. Проверил так же на нескольких подключенных устройствах — для каждого в отдельности выполняется такая цепочка. То есть несколько устройств работают вместе без проблем.
A_>1. IOCTL_MOUSE_QUERY_ATTRIBUTES прилетает, только в случае успешного завершения обработчика IRP_MJ_CREATE. То есть последовательность при подключении устройства такая: IOCTL_INTERNAL_MOUSE_CONNECT -> IRP_MJ_CREATE -> IOCTL_MOUSE_QUERY_ATTRIBUTES. После этого можно вызывать callback. Если же обработчика IRP_MJ_CREATE в драйвере нет или он ошибку возвращает, то IOCTL_MOUSE_QUERY_ATTRIBUTES запроса не будет и смысла вызывать callback нет.
Если бы ты был чуть более внимателен, ты бы заметил вызов MouEnableDisablePort() в mouclass'е, который для PnP-портов выливается в IoGetDeviceObjectPointer(), а эта функция внутри себя вызывает ZwOpenFile(), т.е. посылает IRP_MJ_CREATE. Кроме этого, большинство запросов device control, переданных тебе, это не mouclass шлёт, а подсистема Win32, а тебе попадают как нижнему по стеку. Ну это так, на заметку.
A_>2. При отключении устройства срабатывает только IRP_MJ_CLOSE. IOCTL_INTERNAL_MOUSE_DISCONNECT почему-то не прилетает, что мне кажется странным. По идее этот запрос комплементарный к IOCTL_INTERNAL_MOUSE_CONNECT.
А это вообще нормальное поведение для компонентов ядра, хотя соглашусь, что не совсем логичное. Например, TDI-клиенты тоже не шлют TDI_DISCONNECT и TDI_DISASSOCIATE_ADDRESS и так далее, вместо этого сразу ZwClose(). Полагаю, это всё сделано в целях оптимизации производительности, так что ничего страшного.
A_>3. Проверил так же на нескольких подключенных устройствах — для каждого в отдельности выполняется такая цепочка. То есть несколько устройств работают вместе без проблем.
Здравствуйте, x64, Вы писали:
A_>>1. IOCTL_MOUSE_QUERY_ATTRIBUTES прилетает, только в случае успешного завершения обработчика IRP_MJ_CREATE. То есть последовательность при подключении устройства такая: IOCTL_INTERNAL_MOUSE_CONNECT -> IRP_MJ_CREATE -> IOCTL_MOUSE_QUERY_ATTRIBUTES. После этого можно вызывать callback. Если же обработчика IRP_MJ_CREATE в драйвере нет или он ошибку возвращает, то IOCTL_MOUSE_QUERY_ATTRIBUTES запроса не будет и смысла вызывать callback нет.
x64>Если бы ты был чуть более внимателен, ты бы заметил вызов MouEnableDisablePort() в mouclass'е, который для PnP-портов выливается в IoGetDeviceObjectPointer(), а эта функция внутри себя вызывает ZwOpenFile(), т.е. посылает IRP_MJ_CREATE. Кроме этого, большинство запросов device control, переданных тебе, это не mouclass шлёт, а подсистема Win32, а тебе попадают как нижнему по стеку. Ну это так, на заметку.
То есть в моем случае судя по исходникам IOCTL_INTERNAL_MOUSE_CONNECT создается с нуля mouclass`ом, а IOCTL_MOUSE_QUERY_ATTRIBUTES "транслируется" им нижестоящему драйверу (то есть моему).
A_>>2. При отключении устройства срабатывает только IRP_MJ_CLOSE. IOCTL_INTERNAL_MOUSE_DISCONNECT почему-то не прилетает, что мне кажется странным. По идее этот запрос комплементарный к IOCTL_INTERNAL_MOUSE_CONNECT.
x64>А это вообще нормальное поведение для компонентов ядра, хотя соглашусь, что не совсем логичное. Например, TDI-клиенты тоже не шлют TDI_DISCONNECT и TDI_DISASSOCIATE_ADDRESS и так далее, вместо этого сразу ZwClose(). Полагаю, это всё сделано в целях оптимизации производительности, так что ничего страшного.
На мой взгляд передача указателей, тем более callback`ов между компонентами — не безопасная операция, и интерфейс должен быть логичным в этом случае, чтобы точно знать, когда адрес валидный и его можно использовать, а когда нет. Пока не прочитал в MSDN, что IOCTL_INTERNAL_MOUSE_DISCONNECT не реализован, подсознательно думал, что что-то не так в моем коде. Сейчас получается, что адрес валидный на период между обработками IOCTL_INTERNAL_MOUSE_CONNECT и IRP_MJ_CLOSE. В обработчике IRP_MJ_CLOSE структуру CONNECT_DATA забиваю нулями через memset, чтобы наверняка в указателе NULL был.
A_>>3. Проверил так же на нескольких подключенных устройствах — для каждого в отдельности выполняется такая цепочка. То есть несколько устройств работают вместе без проблем.
x64>Ну кто бы сомневался.