问题描述
我正在尝试编写一个 KMDF 驱动程序来模拟击键。
当驱动程序收到 IOCTL_HID_READ_REPORT
时,它会将请求重定向到队列:
switch (IoControlCode)
{
case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
KdPrint(("GET DEVICE DESCRIPTOR\n"));
_Analysis_assume_(deviceContext->HidDescriptor.bLength != 0);
status = RequestCopyFromBuffer(Request,&deviceContext->HidDescriptor,deviceContext->HidDescriptor.bLength);
break;
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
KdPrint(("GET DEVICE ATTRIBUTES\n"));
status = RequestCopyFromBuffer(Request,&queueContext->DeviceContext->HidDeviceAttributes,sizeof(HID_DEVICE_ATTRIBUTES));
break;
case IOCTL_HID_GET_REPORT_DESCRIPTOR:
KdPrint(("GET REPORT DESCRIPTOR\n"));
status = RequestCopyFromBuffer(Request,deviceContext->ReportDescriptor,deviceContext->HidDescriptor.DescriptorList[0].wReportLength);
break;
case IOCTL_HID_READ_REPORT:
WdfRequestForwardToIoQueue(Request,QueueContext->DeviceContext->ManualQueue); // <= HERE
break;}
使用计时器,项目会定期出队,并在请求中复制键盘输入报告
void EvtTimerFunc(_In_ WDFTIMER Timer)
{
NTSTATUS status;
WDFQUEUE queue;
PMANUAL_QUEUE_CONTEXT queueContext;
WDFREQUEST request;
KdPrint(("EvtTimerFunc\n"));
queue = (WDFQUEUE)WdfTimerGetParentObject(Timer);
queueContext = GetManualQueueContext(queue);
//
// see if we have a request in manual queue
//
status = WdfIoQueueRetrieveNextRequest(queueContext->Queue,&request);
if (NT_SUCCESS(status))
{
KdPrint(("Handling"));
HID_XFER_PACKET hidXferPacket;
BYTE keycodes[6] = {0};
keycodes[0] = 0x04;
HID_KEYBOARD_INPUT_REPORT report;
report.ReportId = REPORT_ID_KEYBOARD_INPUT;
report.Modifiers = 0;
report._reserved = 0;
memcpy(&report.KeyCodes,&keycodes,6);
hidXferPacket.reportBuffer = (UCHAR*)&report;
hidXferPacket.reportBufferLen = sizeof(HID_KEYBOARD_INPUT_REPORT);
hidXferPacket.reportId = REPORT_ID_KEYBOARD_INPUT;
RequestCopyFromBuffer(request,hidXferPacket.reportBuffer,sizeof(HID_KEYBOARD_INPUT_REPORT));
WdfRequestComplete(request,status);
}
}
尽管一切正常,但不会发出任何击键。我错过了什么?!
描述符:
HID_REPORT_DESCRIPTOR g_reportDescriptor[] = {
0x05,0x01,// USAGE_PAGE (Generic Desktop)
0x09,0x02,// USAGE (Mouse)
0xA1,// COLLECTION (Application)
0x85,REPORT_ID_MOUSE_INPUT,0x09,// USAGE_PAGE (Pointer)
0xA1,0x00,// COLLECTION (Physical)
0x05,// USAGE_PAGE (Buttons)
0x19,// USAGE_MINIMUM (1)
0x29,0x03,// USAGE_MAXIMUM (3)
0x15,// LOGICAL_MINIMUM (0)
0x25,// LOGICAL_MAXIMUM (1)
0x95,// REPORT_COUNT (3)
0x75,// REPORT_SIZE (1)
0x81,// INPUT (Data,Variable,Absolute)
0x95,// REPORT_COUNT (1)
0x75,0x05,// REPORT_SIZE (5)
0x81,// INPUT (Constant)
0x05,0x30,// USAGE (X)
0x09,0x31,// USAGE (Y)
0x15,0x81,// LOGICAL_MINIMUM (-127)
0x25,0x7F,// LOGICAL_MAXIMUM (127)
0x75,0x08,// REPORT_SIZE (8)
0x95,// REPORT_COUNT (2)
0x81,0x06,// Input (Data,Relative)
0xC0,// END_COLLECTION
0xC0,// END_COLLECTION
0x05,// USAGE (Undefined)
0xa1,REPORT_ID_MOUSE_OUTPUT,// USAGE (Undefined)
0x15,// LOGICAL_MINIMUM (0)
0x26,0xff,// LOGICAL_MAXIMUM (255)
0x95,// REPORT_SIZE (8)
0x91,// OUTPUT (Data,Absolute)
0xc0,// USAGE (Keyboard)
0xA1,REPORT_ID_KEYBOARD_INPUT,0x07,// USAGE_PAGE (Keyboard Key Codes)
0x19,0xE0,// USAGE_MINIMUM (224)
0x29,0xE7,// USAGE_MAXIMUM (231)
0x15,// LOGICAL_MAXIMUM (1)
0x75,// REPORT_SIZE (1)
0x95,// REPORT_COUNT (8)
0x81,// REPORT_SIZE (8)
0x81,// INPUT (Constant)
0x19,// USAGE_MINIMUM (0)
0x29,0x65,// USAGE_MAXIMUM (101)
0x15,// LOGICAL_MAXIMUM (101)
0x95,// REPORT_COUNT (6)
0x75,Array,Absolute)
0x05,// USAGE_PAGE (LEDs)
0x19,// USAGE_MINIMUM (Num Lock)
0x29,// USAGE_MAXIMUM (Kana)
0x95,// REPORT_COUNT (5)
0x75,// REPORT_SIZE (1)
0x91,// REPORT_SIZE (3)
0x91,// OUTPUT (Constant)
0xC0,REPORT_ID_KEYBOARD_OUTPUT,// REPORT_COUNT (8)
0x75,Absolute)
0xc0 // END_COLLECTION
};
HID_DESCRIPTOR g_hidDescriptor = {
0x09,// length of HID descriptor
0x21,// descriptor type == HID 0x21
0x0100,// hid spec release
0x00,// country code == Not Specified
0x01,// number of HID class descriptors
{ // DescriptorList[0]
0x22,// report descriptor type 0x22
sizeof(g_reportDescriptor) // total length of report descriptor
}
};
解决方法
我使用 Hyper V 虚拟机作为调试机器,这就是它不起作用的原因。 我一使用另一台计算机,就发送了按键。
如果您想模拟击键或鼠标移动,这就是我的建议:
-
查看 https://github.com/djpnewton/vmulti(将 HidMapper 集成到您的驱动程序)
-
避免使用 Hyper V 进行测试