Я пишу драйвер фильтра клавиатуры для Windows, и мне нужно вставить свои пользовательские данные нажатия клавиш в очередь сообщений Windows. Мне удалось перехватить все нажатые клавиши, установив обратный вызов OnReadCompletion () для IoSetCompletionRoutine () в функции Read () моего драйвера следующим образом:
NTSTATUS Read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, OnReadCompletion, DeviceObject, TRUE, TRUE, TRUE);
return IoCallDriver (deviceExtension->pKeyboardDevice, Irp);
}
NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
// ...
}
Этот драйвер фильтра подключен к драйверу kbdclass следующим образом:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
// ...
CCHAR ntNameBuffer[64] = "\\Device\\KeyboardClass0";
status = IoAttachDevice(deviceObject, &uKeyboardDeviceName, &DeviceExtension->pKeyboardDevice);
// ...
}
Итак, я могу отлавливать все клавиши, нажимаемые в OnReadCompletion (). Но мне нужно вставить свою собственную информацию в поток сообщений клавиатуры. Вот 2 проблемы с этим:
OnReadCompletion () вызывается только при нажатии клавиши. В идеале я бы хотел, чтобы это как-то вызывалось, когда ничего не нажимается. Могу ли я сделать это как-нибудь? Мне нужно вызвать прерывание клавиатуры? Я пытался записывать команды на порты клавиатуры (0x60 и 0x64) с помощью WRITE_PORT_UCHAR (), но это не сработало.
Я попытался вставить свои данные в IRP в OnReadCompletion (), чтобы это выглядело, например, как клавиша была нажата дважды, в то время как фактически она была нажата только один раз. Может ли кто-нибудь помочь мне с этим тоже, потому что следующее не сработало?
NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
PIO_STACK_LOCATION IrpStackLocation = NULL;
INT BufferLength;
INT numKeys = 0, i = 0;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
IrpStackLocation = IoGetCurrentIrpStackLocation(Irp);
BufferLength = IrpStackLocation->Parameters.Read.Length;
if(Irp->IoStatus.Status == STATUS_SUCCESS)
{
PCHAR newSystemBuffer, oldSystemBuffer;
PKEYBOARD_INPUT_DATA keys = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
numKeys = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);
for(i = 0; i < numKeys; i++)
{
// here we print whatever was pressed
DbgPrint("%s -- ScanCode: %x\n", __FUNCTION__, keys[i].MakeCode);
}
// allocate new buffer twice as big as original
newSystemBuffer = ExAllocatePool(NonPagedPool, Irp->IoStatus.Information * 2);
// copy existing buffer twice into new buffer
RtlCopyMemory(newSystemBuffer, keys, Irp->IoStatus.Information);
RtlCopyMemory(newSystemBuffer + Irp->IoStatus.Information, keys, Irp->IoStatus.Information);
// assign new buffer to Irp->AssociatedIrp.SystemBuffer
oldSystemBuffer = Irp->AssociatedIrp.SystemBuffer;
Irp->AssociatedIrp.SystemBuffer = newSystemBuffer;
// tell IRP that we now have twice as much data
Irp->IoStatus.Information *= 2;
// free the old buffer
ExFreePool(oldSystemBuffer);
}
if(Irp->PendingReturned)
IoMarkIrpPending(Irp);
return Irp->IoStatus.Status;
}
И когда я проверяю это, например, в Блокноте, все, что я получаю, это всего лишь одна буква за нажатие клавиши.
Я действительно в отчаянии. Пожалуйста помоги!