2011-09-01 9 views
5

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:

  1. 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ó.

  2. 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!

+0

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); –

+0

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. –

+0

Entonces, la única pregunta que queda es ¿cómo disparo una interrupción? –

Respuesta

1

cuatro opciones que creo que debería funcionar:

1) Se puede crear un nuevo IRP a llamar al conductor con kbdclass, en lugar de pasar el IRP que ha recibido abajo. Debería completar el IRP original cada vez que quisiera insertar datos y cada vez que tuviera pulsaciones de teclas reales para transmitir.

2) Usted podría tener dos dispositivos, el segundo es un dispositivo de teclado. Luego, usaría el filtro kbdclass para eliminar las pulsaciones de teclas y el dispositivo del teclado para agregarlas.

3) Se puede rediseñar su conductor para ser un filtro superior para los dispositivos de teclado, similar al controlador kbfiltr muestra de MSDN.

4) puede tener dos dispositivos, el segundo es un filtro superior para uno o más de los dispositivos de teclado. Debería usar el filtro kbdclass para eliminar las pulsaciones de teclas y el filtro del dispositivo de teclado para agregarlas.

Creo que la primera opción sería mejor, pero no soy un experto.

+0

Gracias por la respuesta, amigo! Pero mi controlador es un controlador de filtro, si entiendo la terminología. Hace exactamente lo que hace Kbdfiltr. Descubrí que tienes dos opciones para modificar un IRP en un controlador de filtro. Primero es cuando el sistema operativo lee una pila de controladores de teclado. Esta lectura es capturada por su controlador. Puede responder de inmediato, enviando así las pulsaciones de teclas al sistema operativo que nunca se han pulsado. Si no lo haces, esta lectura llega al final de la pila y se bloquea allí hasta que el usuario presiona una tecla. Luego, el IRP sube la pila y puede volver a capturarlo y modificarlo. –

+0

Para que pueda modificar el IRP en dos ocasiones. Pero cuando un conductor debajo de la pila lo bloquea, no puede hacer nada y esperar hasta que vuelva. Ese es el problema. Porque si recibo datos a través de ioclt que necesito insertar, necesito esperar una pulsación para tener la oportunidad de insertarlos en el IRP. –

+0

En cuanto a su segunda idea con respecto a otro teclado, ¿quiere decir realmente conectar un segundo teclado a la computadora o simplemente hacer un controlador de filtro a un dispositivo no existente, como \\ Device \\ KeyboardClass1? –

Cuestiones relacionadas