我正在为Windows编写键盘过滤器驱动程序,我需要将我的自定义键击数据插入到Windows消息队列中。我已经成功地捕捉到所有被压在我的驾驶读(设置OnReadCompletion()回调至IoSetCompletionRoutine函数())函数,像这样的按键:如何触发或模拟键盘中断?
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按下所有键()。但我需要将自己的信息插入到键盘消息流中。这里有两个问题:
OnReadCompletion()仅在按下按键时调用。理想情况下,我想以某种方式在没有任何按下时调用它。我能以某种方式做到吗?我需要触发键盘中断?我尝试使用WRITE_PORT_UCHAR()将命令写入键盘端口(0x60和0x64),但没有成功。
我试图将我的数据插入到OnReadCompletion()中的IRP中,使其看起来像一个键被按下两次,而实际上它只被按下一次。有人可以帮我解决这个问题吗,因为以下方面没有解决?
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; }
当我测试它例如在记事本中,我得到的只是每一个按键字母。 我真的很绝望。请帮忙!
我设法将新数据添加到IRP系统缓冲区。诀窍是使用不同的关键笔划代码,不像上面的代码中那样。所以如果你想插入一个MakeCode = 2(等于按下按钮“1”),在OnReadCompletion()中执行以下操作:RtlCopyMemory(newSystemBuffer,keys,Irp-> IoStatus.Information); keys-> MakeCode = 2; RtlCopyMemory(newSystemBuffer + Irp-> IoStatus.Information,keys,Irp-> IoStatus.Information); –
区别在于“keys-> MakeCode = 2;”这会在第二个KEYBOARD_INPUT_DATA消息中更改MakeCode。在每次击键之后,例如在记事本中,你会得到一个“1”。 –
所以唯一的问题是如何触发中断? –