2011-09-01 41 views
5

Tôi đang viết trình điều khiển bộ lọc bàn phím cho Windows và tôi cần chèn dữ liệu tổ hợp phím tùy chỉnh của mình vào hàng đợi thư Windows. Tôi đã quản lý để nắm bắt tất cả các phím được ép thiết OnReadCompletion() gọi lại để IoSetCompletionRoutine() trong đọc lái xe của tôi() chức năng như vậy:Làm thế nào để kích hoạt hoặc mô phỏng ngắt bàn phím?

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

tài xế Bộ lọc này được gắn liền với tài xế kbdclass như vậy:

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

}

Vì vậy, tôi có thể bắt tất cả các phím bấm trong OnReadCompletion(). Nhưng tôi cần chèn thông tin của riêng mình vào luồng thông báo bàn phím. Dưới đây là 2 vấn đề với điều đó:

  1. OnReadCompletion() chỉ được gọi khi nhấn phím. Lý tưởng nhất là tôi muốn bằng cách nào đó nó được gọi khi không có gì được nhấn. Tôi có thể làm điều đó bằng cách nào đó không? Tôi cần phải kích hoạt một bàn phím gián đoạn? Tôi đã cố gắng để viết lệnh vào một cổng bàn phím (0x60 và 0x64) với WRITE_PORT_UCHAR() nhưng điều đó không làm việc ra ngoài.

  2. Tôi đã cố gắng chèn dữ liệu của mình vào IRP trong OnReadCompletion() để làm cho nó trông giống như ví dụ một phím được nhấn hai lần trong khi thực tế nó chỉ được nhấn một lần. Ai đó cũng có thể giúp tôi về điều đó, bởi vì những điều sau đây không hiệu quả?

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

Và khi tôi kiểm tra nó ví dụ như trong Notepad, tất cả tôi nhận được chỉ là một lá thư mỗi tổ hợp phím. Tôi thực sự tuyệt vọng. Hãy giúp tôi!

+0

Tôi đã quản lý để thêm dữ liệu mới vào bộ đệm Hệ thống IRP. Bí quyết là sử dụng mã đột quỵ chính khác nhau, không giống như mã lệnh ở trên. Vì vậy, nếu bạn muốn chèn một MakeCode = 2 (bằng cách nhấn nút "1"), làm điều này trong OnReadCompletion(): RtlCopyMemory (newSystemBuffer, keys, Irp-> IoStatus.Information); keys-> MakeCode = 2; RtlCopyMemory (newSystemBuffer + Irp-> IoStatus.Information, keys, Irp-> IoStatus.Information); –

+0

Sự khác biệt là trong "keys-> MakeCode = 2;" thay đổi MakeCode trong thông báo KEYBOARD_INPUT_DATA thứ hai. Và bạn nhận được "1" được thêm sau mỗi lần nhấn phím, ví dụ như trong notepad. –

+0

Vì vậy, câu hỏi duy nhất còn lại là làm cách nào để kích hoạt gián đoạn? –

Trả lời

1

Bốn lựa chọn mà tôi nghĩ nên làm việc:

1) Bạn có thể tạo một IRP mới để gọi người lái xe kbdclass với, như trái ngược với đi qua các IRP mà bạn nhận được xuống. Bạn sẽ hoàn thành IRP ban đầu bất cứ khi nào bạn muốn chèn dữ liệu cũng như bất cứ khi nào bạn có tổ hợp phím thực để truyền.

2) Bạn có thể có hai thiết bị, thiết bị thứ hai là thiết bị bàn phím. Sau đó, bạn sẽ sử dụng bộ lọc kbdclass để xóa các tổ hợp phím và thiết bị bàn phím để thêm chúng.

3) Bạn có thể thiết kế lại trình điều khiển để trở thành bộ lọc phía trên cho các thiết bị bàn phím, tương tự như trình điều khiển mẫu MSDN kbfiltr.

4) Bạn có thể có hai thiết bị, thiết bị thứ hai là bộ lọc trên cho một hoặc nhiều thiết bị bàn phím. Bạn sẽ sử dụng bộ lọc kbdclass để xóa các tổ hợp phím và bộ lọc thiết bị bàn phím để thêm chúng.

Tôi nghĩ tùy chọn đầu tiên sẽ là tốt nhất, nhưng tôi không có chuyên gia.

+0

Cảm ơn bạn đã trả lời, bạn đời! Nhưng trình điều khiển của tôi là một trình điều khiển lọc, nếu tôi hiểu thuật ngữ. Nó thực hiện chính xác những gì Kbdfiltr làm. Tôi phát hiện ra rằng bạn có hai tùy chọn để sửa đổi một IRP trong một trình điều khiển lọc. Đầu tiên là khi hệ điều hành thực hiện việc đọc đến ngăn xếp trình điều khiển bàn phím. Đọc này được ghi lại bởi trình điều khiển của bạn. Bạn có thể trả lời ngay lập tức, do đó việc gửi tổ hợp phím đến hệ điều hành chưa bao giờ được nhấn. Nếu bạn không làm điều đó đọc này được vào dưới cùng của ngăn xếp và bị chặn ở đó cho đến khi người dùng nhấn một phím. Sau đó, IRP di chuyển lên ngăn xếp và có thể bị bắt bởi trình điều khiển của bạn một lần nữa và sửa đổi. –

+0

Vì vậy, bạn có thể sửa đổi IRP hai lần. Nhưng khi nó bị chặn bởi một người lái xe bên dưới ngăn xếp, bạn không thể làm gì và đợi cho đến khi nó quay trở lại. Đó chính là vấn đề. Bởi vì nếu tôi có dữ liệu đến thông qua ioclt mà tôi cần phải chèn tôi cần phải chờ đợi một tổ hợp phím để có được một cơ hội để chèn nó vào IRP. –

+0

Như ý tưởng thứ hai của bạn liên quan đến bàn phím khác - ý bạn là thực sự kết nối bàn phím thứ hai với máy tính hoặc chỉ tạo trình điều khiển bộ lọc cho một thiết bị không tồn tại, như \\ Device \\ KeyboardClass1? –

Các vấn đề liên quan