Keyboard events in a Kernel mode driver

I would like to receive the events from keyboard in my kernel-mode
driver (Windows NT 4.0), not using the Win32 application.
Is it possible?
Thank you. Alex.
MadorskyAsked:
Who is Participating?
 
agreenCommented:
Yes it's possible by hooking onto the keyboard I/O path.
Here's the sample (by M. Russinovich). Converts caps-locks into controls.

NTSTATUS DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING RegistryPath )
{
    PDEVICE_OBJECT         deviceObject        = NULL;
    NTSTATUS               ntStatus;
    WCHAR                  deviceNameBuffer[]  = L"\\Device\\Ctrl2cap";
    UNICODE_STRING         deviceNameUnicodeString;
    WCHAR                  deviceLinkBuffer[]  = L"\\DosDevices\\Ctrl2cap";
    UNICODE_STRING         deviceLinkUnicodeString;

    DbgPrint (("Ctrl2cap.SYS: entering DriverEntry\n"));

    //
    // Create our device.
    //
          
    RtlInitUnicodeString (&deviceNameUnicodeString,
                          deviceNameBuffer );
   
    ntStatus = IoCreateDevice (DriverObject,
                               0,
                               &deviceNameUnicodeString,
                               FILE_DEVICE_CTRL2CAP,
                               0,
                               TRUE,
                               &deviceObject );

    if (NT_SUCCESS(ntStatus)) {

       //
       // Create a symbolic link so that ctr2lcap can be dynamically loaded.
         //

       RtlInitUnicodeString (&deviceLinkUnicodeString,
                         deviceLinkBuffer );
       ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
                                &deviceNameUnicodeString );
       if (!NT_SUCCESS(ntStatus))
            DbgPrint (("Ctrl2cap.SYS: IoCreateSymbolicLink failed\n"));

       //
       // Create dispatch points for all the IRPs the keyboard class device
         // handles.
         //

        DriverObject->MajorFunction[IRP_MJ_READ]         
                     = Ctrl2capDispatchRead;
       DriverObject->MajorFunction[IRP_MJ_CREATE]         =
       DriverObject->MajorFunction[IRP_MJ_CLOSE]          =
       DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]  =
       DriverObject->MajorFunction[IRP_MJ_CLEANUP]        =
       DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
                         = Ctrl2capDispatchGeneral;
    }

    if (!NT_SUCCESS(ntStatus)) {

       //
       // Something went wrong, so clean up (free resources etc)
       //

         if (deviceObject )
            IoDeleteDevice (deviceObject);
    }

    return Ctrl2capInit( DriverObject );
}
NTSTATUS Ctrl2capInit( IN PDRIVER_OBJECT DriverObject )
{
    CCHAR             ntNameBuffer[64];
    STRING             ntNameString;
    UNICODE_STRING       ntUnicodeString;
    NTSTATUS             status;

    //
    // Only hook onto the first keyboard's chain.
    //

    sprintf( ntNameBuffer, "\\Device\\KeyboardClass0" );
    RtlInitAnsiString( &ntNameString, ntNameBuffer );
    RtlAnsiStringToUnicodeString( &ntUnicodeString, &ntNameString, TRUE );

    //
    // Create device object for the keyboard.
    //

    status = IoCreateDevice( DriverObject,
                       0,
                       NULL,
                       FILE_DEVICE_KEYBOARD,
                       0,
                       FALSE,
                       &HookDeviceObject );

    if( !NT_SUCCESS(status) ) {

       DbgPrint(("Ctrl2cap: Keyboard hook failed to create device!\n"));

       RtlFreeUnicodeString( &ntUnicodeString );

       return STATUS_SUCCESS;
    }
   
    //
    // Keyboard uses buffered I/O so we must as well.
    //

    HookDeviceObject->Flags |= DO_BUFFERED_IO;

    //
    // Attach to the keyboard chain.
    //

    status = IoAttachDevice( HookDeviceObject, &ntUnicodeString, &kbdDevice );

    if( !NT_SUCCESS(status) ) {

       DbgPrint(("Ctrl2cap: Connect with keyboard failed!\n"));

       IoDeleteDevice( HookDeviceObject );

       RtlFreeUnicodeString( &ntUnicodeString );
      
       return STATUS_SUCCESS;
    }

    //
    // Done! Just free our string and be on our way...
    //

    RtlFreeUnicodeString( &ntUnicodeString );

    DbgPrint(("Ctrl2cap: Successfully connected to keyboard device\n"));

    //
    // This line simply demonstrates how a driver can print
    // stuff to the bluescreen during system initialization.
    //
 
    HalDisplayString( "Ctrl2cap Initialized\n" );

    return STATUS_SUCCESS;
}
NTSTATUS Ctrl2capReadComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
                        IN PVOID Context )
{
    PIO_STACK_LOCATION        IrpSp;
    PKEYBOARD_INPUT_DATA      KeyData;
    int                       numKeys, i;

    //
    // Request completed - look at the result.
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );
    if( NT_SUCCESS( Irp->IoStatus.Status ) ) {

        //
      // Do caps-lock down and caps-lock up. Note that
        // just frobbing the MakeCode handles both the up-key
        // and down-key cases since the up/down information is specified
        // seperately in the Flags field of the keyboard input data
        // (0 means key-down, 1 means key-up).
        //

        KeyData = Irp->AssociatedIrp.SystemBuffer;
        numKeys = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);

        for( i = 0; i < numKeys; i++ ) {

            DbgPrint(("ScanCode: %x ", KeyData[i].MakeCode ));
            DbgPrint(("%s\n", KeyData[i].Flags ? "Up" : "Down" ));

            if( KeyData[i].MakeCode == CAPS_LOCK) {

              KeyData[i].MakeCode = LCONTROL;
            }
        }
    }

    if( Irp->PendingReturned ) {

        IoMarkIrpPending( Irp );

    }

    return Irp->IoStatus.Status;
}
NTSTATUS Ctrl2capDispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
    PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION nextIrpStack    = IoGetNextIrpStackLocation(Irp);

    //
    // Push params down for keyboard class driver.
    //

    *nextIrpStack = *currentIrpStack;

    //  
    // Set the completion callback, so we can "frob" the keyboard data.
    //         

    IoSetCompletionRoutine( Irp, Ctrl2capReadComplete, DeviceObject, TRUE, TRUE, TRUE );

    //
    // Return the results of the call to the keyboard class driver.
    //
          
    return IoCallDriver( kbdDevice, Irp );
}
NTSTATUS Ctrl2capDispatchGeneral(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp )
{
    PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION nextIrpStack    = IoGetNextIrpStackLocation(Irp);

    //
    // Default to success.
    //

    Irp->IoStatus.Status      = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    //
    // If this call was directed at the hook device, pass it to
    // the keyboard class device, else handle it ourselves.
    //

   if( DeviceObject == HookDeviceObject ) {

       *nextIrpStack = *currentIrpStack;

       return IoCallDriver( kbdDevice, Irp );

   } else {

       return STATUS_SUCCESS;

   }
}

0
 
shankar_msCommented:
agreen:
  I would like to simulate "ctrl+alt+del" event through program. I think it should be handled using interrupts at driver level. Any help on this.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.