2011-09-01 13 views
5

Sto scrivendo un driver di filtro della tastiera per Windows e ho bisogno di inserire i miei dati di battitura personalizzati nella coda dei messaggi di Windows. Sono riuscito a catturare tutti i tasti che vengono premuti insediano OnReadCompletion() di callback per IoSetCompletionRoutine() in Per saperne di mio autista() la funzione in questo modo:Come attivare o simulare l'interruzione della tastiera?

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) 
{ 
// ... 
} 

Questo driver di filtro è attaccato al conducente kbdclass in questo modo:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) 
{ 
// ... 
CCHAR ntNameBuffer[64] = "\\Device\\KeyboardClass0"; 
status = IoAttachDevice(deviceObject, &uKeyboardDeviceName, &DeviceExtension->pKeyboardDevice); 
// ... 

}

Quindi, posso prendere tutti i tasti premuti in OnReadCompletion(). Ma ho bisogno di inserire le mie informazioni nel flusso dei messaggi della tastiera. Qui ci sono 2 problemi:

  1. OnReadCompletion() viene richiamato solo quando viene premuto un tasto. Idealmente mi piacerebbe in qualche modo chiamarlo quando non viene premuto nulla. Posso farlo in qualche modo? Devo attivare un interrupt di tastiera? Ho provato a scrivere comandi su una tastiera (0x60 e 0x64) con WRITE_PORT_UCHAR() ma non ha funzionato.

  2. Ho cercato di inserire i miei dati in IRP in OnReadCompletion() per far sembrare che ad esempio un tasto sia stato premuto due volte mentre in realtà è stato premuto una sola volta. Qualcuno può aiutarmi anche su quello, perché il seguente non ha funzionato?

    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; 
    } 
    

E quando verifico che per esempio in Blocco note, tutto quello che ottiene è solo una lettera per ogni tasto. Sono davvero disperata. Per favore aiuto!

+0

Sono riuscito ad aggiungere nuovi dati al buffer del sistema IRP. Il trucco consisteva nell'usare un codice diverso per il tratto chiave, non lo stesso come nel codice sopra. Quindi, se vuoi inserire un MakeCode = 2 (uguale a premere il pulsante "1"), fallo in OnReadCompletion(): RtlCopyMemory (newSystemBuffer, keys, Irp-> IoStatus.Information); keys-> MakeCode = 2; RtlCopyMemory (newSystemBuffer + Irp-> IoStatus.Information, keys, Irp-> IoStatus.Information); –

+0

La differenza è in "keys-> MakeCode = 2;" che cambia MakeCode nel secondo messaggio KEYBOARD_INPUT_DATA. E ricevi un "1" aggiunto dopo ogni sequenza di tasti, ad esempio nel blocco note. –

+0

Quindi l'unica domanda rimane è come posso attivare un interrupt? –

risposta

1

quattro opzioni che a mio avviso dovrebbe funzionare:

1) è possibile creare un nuovo IRP per chiamare il driver kbdclass con, al contrario di passare l'IRP che hai ricevuto in giù. Completare l'IRP originale ogni volta che si desidera inserire dati, nonché ogni volta che si hanno trasmissioni di tasti reali da trasmettere.

2) Si possono avere due dispositivi, il secondo è un dispositivo a tastiera. Dovresti quindi usare il filtro kbdclass per rimuovere le battute e il dispositivo tastiera per aggiungerle.

3) È possibile ridisegnare il driver in modo che sia un filtro superiore per i dispositivi della tastiera, simile al driver di esempio MSDN kbfiltr.

4) Si possono avere due dispositivi, il secondo è un filtro superiore per uno o più dispositivi della tastiera. Dovresti usare il filtro kbdclass per rimuovere le sequenze di tasti e il filtro del dispositivo della tastiera per aggiungerle.

Penso che la prima opzione sarebbe la migliore, ma non sono esperto.

+0

Grazie per la risposta, amico! Ma il mio driver è un driver di filtro, se capisco la terminologia. Fa esattamente quello che fa Kbdfiltr. Ho scoperto che hai due opzioni per modificare un IRP in un driver di filtro. Il primo è quando il sistema operativo legge la pila del driver della tastiera. Questa lettura è catturata dal tuo autista. A puoi rispondere immediatamente, inviando così le battute al sistema operativo che non sono mai state premute. Se non lo fai, questa lettura arriva in fondo allo stack e viene bloccata lì finché l'utente non preme un tasto. Quindi l'IRP si sposta sullo stack e può essere nuovamente catturato dal driver e modificato. –

+0

Quindi è possibile modificare l'IRP in due occasioni. Ma quando quando viene bloccato da un autista sotto lo stack non puoi fare nulla e aspettare che torni. Questo è il problema. Perché se ho ricevuto i dati tramite ioclt che devo inserire devo aspettare una sequenza di tasti per avere l'opportunità di inserirli nell'IRP. –

+0

Per quanto riguarda la tua seconda idea riguardante un'altra tastiera, intendi effettivamente connettere una seconda tastiera al computer o semplicemente creare un driver di filtro su un dispositivo non esistente, come \\ Device \\ KeyboardClass1? –