我是一名实习生,是驱动程序开发的新手。我的公司希望我为他们制造的几个多点触控 HID 设备编写 KMDF 驱动程序。他们雇用了比我更早的人来解决这个问题,他试图使用 Windows 触摸用法并遇到了一些问题,因此无法完成驱动程序。所以,我们决定我应该编写驱动程序,以便设备像鼠标和键盘复合设备一样工作。这样,我们可以在使用单点触摸时发送系统鼠标数据,并在识别某些多点触摸手势(旋转、缩放等)时发送键盘数据(激活键盘快捷键的击键)。我有手势识别,鼠标部分工作得很好。我从 WDK 中的 HidUsbFx2 示例开始,目前面临两个问题。
问题#1:只有当我在报告描述符中注释掉我的键盘 TLC 时,鼠标才会起作用,并且我的键盘报告功能只有在我在报告描述符中注释掉鼠标 TLC 时才会起作用(直到我完成它为止)。我不知道为什么会这样。这是我的报告描述符:`// Mouse Collection
0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0
0x09, 0x02, // USAGE (Mouse) 2
0xa1, 0x01, // COLLECTION (Application) 4
0x85, REPORTID_MOUSE, // REPORT_ID (Mouse) 6
0x09, 0x01, // USAGE (Pointer) 8
0xa1, 0x00, // COLLECTION (Physical) 10
0x05, 0x09, // USAGE_PAGE (Button) 12
0x19, 0x01, // USAGE_MINIMUM (Button 1) 14
0x29, 0x02, // USAGE_MAXIMUM (Button 2) 16
0x15, 0x00, // LOGICAL_MINIMUM (0) 18
0x25, 0x01, // LOGICAL_MAXIMUM (1) 20
0x75, 0x01, // REPORT_SIZE (1) 22
0x95, 0x02, // REPORT_COUNT (2) 24
0x81, 0x02, // INPUT (Data,Var,Abs) 26
0x95, 0x06, // REPORT_COUNT (6) 28
0x81, 0x03, // INPUT (Cnst,Var,Abs) 30
0x05, 0x01, // USAGE_PAGE (Generic Desktop) 32
0x09, 0x30, // USAGE (X) 34
0x09, 0x31, // USAGE (Y) 36
0x75, 0x10, // REPORT_SIZE (16) 38
0x95, 0x02, // REPORT_COUNT (2) 40
0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767) 42
0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) 44
0x81, 0x06, // INPUT (Data,Var,Rel) 47
0xc0, // END_COLLECTION 49
0xc0, // END_COLLECTION 50/51
// 键盘集合
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORTID_KEYBOARD, // REPORT_ID (2)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x09, 0xe0, // USAGE (Keyboard LeftControl)
0x09, 0xe7, // USAGE (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x08, // REPORT_COUNT (8)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x08, // REPORT_COUNT (8)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x09, 0x01, // USAGE (Num Lock)
0x09, 0x03, // USAGE (Scroll Lock)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
0x91, 0x01, // OUTPUT (Cnst,Ary,Abs)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x09, 0x00, // USAGE (Reserved (no event indicated))
0x09, 0xff, // USAGE (Unkown)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
`
问题#2:根据我的调试打印语句,我用来发送键盘输入报告的功能似乎正在将数据发送到系统,但击键从未出现。驱动程序成功完成键盘报告功能,系统继续向驱动程序发送读取请求。唯一的问题是我尝试发送的字符永远不会出现在记事本中(我正在使用记事本测试我是否成功发送击键)。这是我用来发送键盘输入报告的功能:
VOID Gh_HidKeyboardReport(PDEVICE_EXTENSION devContext, UCHAR eventID){
PHID_KEYBOARD_REPORT report;
NTSTATUS status;
WDFREQUEST request;
int i;
//size_t bufferLength = 0;
DbgPrint("Gh_HidKeyboardReport\n");
status = WdfIoQueueRetrieveNextRequest(devContext->InterruptMsgQueue, &request);
//status = WdfIoQueueRetrieveNextRequest(devContext->ReadRequestQueue, &request);
if(!NT_SUCCESS(status)){
DbgPrint(" WdfIoQueueRetrieveNextRequest failed with status: 0x%x\n",status);
}else if (NT_SUCCESS(status)){
//DbgPrint("Check 1\n");
//
// IOCTL_HID_READ_REPORT is METHOD_NEITHER so WdfRequestRetrieveOutputBuffer
// will correctly retrieve buffer from Irp->UserBuffer. Remember that
// HIDCLASS provides the buffer in the Irp->UserBuffer field
// irrespective of the ioctl buffer type. However, framework is very
// strict about type checking. You cannot get Irp->UserBuffer by using
// WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER
// internal ioctl.
//
status = WdfRequestRetrieveOutputBuffer(request,
sizeof(HID_KEYBOARD_REPORT),
&report,
NULL); //bufferLength
//DbgPrint("Check 2: 0x%x\n", status);
//DbgPrint("Check 3: 0x%x\n", status);
if (!NT_SUCCESS(status)) { // should never happen
DbgPrint("Went Wrong!\n");
TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
"WdfRequestRetrieveOutputBuffer failed with status: 0x%x\n", status);
DbgPrint(("Retrieve error: 0x%x\n", status));
WdfRequestComplete(request, status);
}else{
//DbgPrint("Check 4\n");
report->reportID = REPORTID_KEYBOARD;
report->modifierKeys = NO_MODIFIERS;
report->reserved = 0x00;
for(i=0; i<6; i++){
report->key[i] = 0x00;
}
if(eventID == NO_EVENT){
goto leave;
}else if(eventID == PUSH_BUTTON){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == RING_ENCODER_CLKWSE){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == RING_ENCODER_CNTRCLKWSE){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == ROTARY_CLKWSE){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == ROTARY_CNTRCLKWSE){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == ROTATE_CLKWSE){
report->key[0] = KEY_A;
//report->key[1] = KEY_B;
//report->key[2] = KEY_C;
//report->key[3] = KEY_D;
//report->key[4] = KEY_E;
//report->key[5] = KEY_F;
}else if(eventID == ROTATE_CNTRCLKWSE){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == SWIPE_UP){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == SWIPE_DOWN){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == SWIPE_RIGHT){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == SWIPE_LEFT){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == ZOOM_IN){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}else if(eventID == ZOOM_OUT){
report->key[0] = KEY_A;
report->key[1] = KEY_B;
report->key[2] = KEY_C;
report->key[3] = KEY_D;
report->key[4] = KEY_E;
report->key[5] = KEY_F;
}
leave: DbgPrint("0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 状态: %d\n", 报告->reportID、report->reserved、report->modifierKeys、report->key[0]、report->key[1]、report->key[2]、report->key[3]、report->key [4],报告->键[5],状态);
WdfRequestCompleteWithInformation(request,status,sizeof(HID_KEYBOARD_REPORT));
// WdfRequestComplete(request, status);
}
}
}
*注意:一旦我可以真正让它们成功发送,我将更改我为每个事件发送的击键。我使用这些键码:KEY_A = 4,KEY_B = 5...KEYPAD_PERIOD = 99。
任何关于这些问题的任何信息将不胜感激。我被困了一段时间,需要在八月底之前完成这件事。