Estoy escribiendo un controlador de filtro de teclado para Windows y necesito insertar mis datos de pulsaciones de teclas personalizadas en la cola de mensajes de Windows. Me las he arreglado para capturar todas las teclas que se pulsan estableciendo OnReadCompletion() de devolución de llamada a IoSetCompletionRoutine() en Leer de conducir() de este modo:¿Cómo disparar o simular la interrupción del teclado?
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)
{
// ...
}
Este controlador de filtro está unido al conductor kbdclass de este modo:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
// ...
CCHAR ntNameBuffer[64] = "\\Device\\KeyboardClass0";
status = IoAttachDevice(deviceObject, &uKeyboardDeviceName, &DeviceExtension->pKeyboardDevice);
// ...
}
lo tanto, puedo coger todas las teclas pulsadas en OnReadCompletion(). Pero necesito insertar mi propia información en el flujo de mensajes del teclado. Aquí hay 2 problemas con eso:
OnReadCompletion() solo se invoca cuando se presiona una tecla. Idealmente, me gustaría que se llame de alguna manera cuando no se presiona nada. ¿Puedo hacer eso de alguna manera? Necesito activar una interrupción del teclado? Traté de escribir comandos en los puertos del teclado (0x60 y 0x64) con WRITE_PORT_UCHAR() pero eso no funcionó.
Intenté insertar mis datos en el IRP en OnReadCompletion() para que pareciera, por ejemplo, que se presionó una tecla dos veces mientras que en realidad solo se presionó una vez. ¿Alguien puede ayudarme en eso también, porque lo siguiente no funcionó?
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; }
Y cuando lo prueba por ejemplo en el Bloc de notas, lo único que consigue es sólo una letra por tecla. Estoy realmente desesperado. ¡Por favor ayuda!
He conseguido añadir nuevos datos a la memoria intermedia Sistema IRP. El truco consistía en utilizar un código de pulsación de tecla diferente, no el mismo que en el código anterior. Así que si usted quiere insertar un MakeCode = 2 (equivalente al botón "1" prensado), hacer esto en el OnReadCompletion(): RtlCopyMemory (newSystemBuffer, llaves, IRP-> IoStatus.Information); keys-> MakeCode = 2; RtlCopyMemory (newSystemBuffer + Irp-> IoStatus.Information, keys, Irp-> IoStatus.Information); –
La diferencia está en "keys-> MakeCode = 2;" que cambia MakeCode en el segundo mensaje KEYBOARD_INPUT_DATA. Y se agrega un "1" después de cada pulsación de tecla, por ejemplo en el bloc de notas. –
Entonces, la única pregunta que queda es ¿cómo disparo una interrupción? –