А что собственно такого? Да, можно написать собственный фильтр, прицепиться к стеку драйверов, создать CompletionRoutine, там перехватить IRP, изменить его и, сняв пометку об обработке отправить назад. Пример есть на
www.sysinternals.com, называется ctrl2cap. У меня почти такая же задача, только обратно отправлять не надо, по этому примеру все сделал.
NTSTATUS PulseDispatchRead( IN PDEVICE_OBJECT pDeviceObject,
IN PIRP Irp )
{ PDEVICE_EXTENSION devExt;
PIO_STACK_LOCATION currentIrpStack;
PIO_STACK_LOCATION nextIrpStack;
//
// Инициализируем наши переменные
//
devExt = (PDEVICE_EXTENSION) pDeviceObject->DeviceExtension;
currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
nextIrpStack = IoGetNextIrpStackLocation(Irp);
//
// Пропускаем пакет ниже, к драйверу класса
//
*nextIrpStack = *currentIrpStack;
//
// Здесь устанавливаем свою callback-функцию для того чтобы
// подправить данные мыши
//
IoSetCompletionRoutine( Irp, PulseReadComplete,
pDeviceObject, TRUE, TRUE, TRUE );
//
// Возвращаем результаты вызова драйверу класса
//
return IoCallDriver( devExt->pTopOfStack, Irp );
}
и вот так
//---------------------------------------------------------------------
// PulseReadComplete()
// Получает управление после завершения операции чтения
//---------------------------------------------------------------------
NTSTATUS PulseReadComplete( IN PDEVICE_OBJECT pDevice,
IN PIRP Irp, IN PVOID pContext )
{ PIO_STACK_LOCATION IrpSp;
PMOUSE_INPUT_DATA pMouseData;
int numMoves, i,
nBuffer;
NTSTATUS status;
LARGE_INTEGER llnSystemTime;
ULONG dwDifference;
PDEVICE_EXTENSION devExt;
// Обработка закончена ловим результаты
IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (NT_SUCCESS(Irp->IoStatus.Status))
{ // Отключаем события средней кнопки.
// Просто удаляем их из пакета
pMouseData = Irp->AssociatedIrp.SystemBuffer;
numMoves = Irp->IoStatus.Information/sizeof(MOUSE_INPUT_DATA);
devExt = pDevice->DeviceExtension;
for (i=0;i<numMoves;i++)
{ if (pMouseData[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
{ pMouseData[i].ButtonFlags &= !(MOUSE_MIDDLE_BUTTON_DOWN);
//По нажатию считаем пульс
// Запрос системного времени, для подсчета пульса
KeQuerySystemTime(&llnSystemTime);
// Нам нужна только младшая часть, притом не в 100 нс
// формате, а в 10 мс
nBuffer = llnSystemTime.LowPart/100000;
if (llnSystemTime.LowPart%100000 > 50000)
nBuffer++;
dwDifference = nBuffer - devExt->dwLastTickTime;
devExt->dwLastTickTime = nBuffer;
// Сдвигаем окно отсчетов
devExt->pdwFrame[0] = devExt->pdwFrame[1];
devExt->pdwFrame[1] = devExt->pdwFrame[2];
devExt->pdwFrame[2] = devExt->pdwFrame[3];
devExt->pdwFrame[3] = devExt->pdwFrame[4];
devExt->pdwFrame[4] = dwDifference;
dwDifference = devExt->pdwFrame[0] + devExt->pdwFrame[1] +
devExt->pdwFrame[2] + devExt->pdwFrame[3] +
devExt->pdwFrame[4];
// Приводим сумму к ударам в минуту
nBuffer = 30000/dwDifference;
if (30000%dwDifference > dwDifference/2)
nBuffer++;
devExt->nTickPerMin = nBuffer;
}
if (pMouseData[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
pMouseData[i].ButtonFlags &= !(MOUSE_MIDDLE_BUTTON_UP);
}
}
// Вот и все возвращаем пакет
if (Irp->PendingReturned)
IoMarkIrpPending(Irp);
return Irp->IoStatus.Status;
}
Только пометку об обработке надо снять и отправить вниз с IoCallDriver()