Hey all,
Newbie here, I am writing a driver for a device that I want to use as a HID mouse/pointer and I am having some weird issues with reporting the mouse data to the system. I started from the HidUsbFx2 sample driver and altered the code as necessary (ie. changed report descriptor and implemented other customized code). My driver receives data from the device successfully but does not send the mouse input report to the system correctly. From my debug print statements I can see that the driver is receiving accurate relative x,y data from the device. I also see that the driver is sending data because the system continues to send read requests (after each time the driver sends new mouse data) but the pointer never moves. My report descriptor looks alright to me and my mouse input report structure matches the descriptor. I can’t figure out what the problem is. Does anyone have any thoughts on what could be causing this behavior?
I also want the device to function as a fake HID keyboard so that I can send keyboard shortcuts to the system or active application (eg. rotate, zoom, etc.). Am I correct in thinking that I can accomplish this by including a keyboard TLC in my report descriptor, creating a keyboard input structure and reporting the key scan codes to the system under the report ID that I specified in my keyboard TLC?
Here’s my mouse report descriptor, input structure and report function:
REPORT DESCRIPTOR:
// Mouse Collection
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORTID_MOUSE, // REPORT_ID (Mouse) (REPORTID_MOUSE = 0x01)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x02, // USAGE_MAXIMUM (Button 2)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x02, // REPORT_COUNT (2)
0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767)
0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
MOUSE DATA INPUT STRUCTURE:
typedef struct _HID_MOUSE_REPORT
{
UCHAR reportID;
UCHAR buttons;
SHORT xData;
SHORT yData;
}HID_MOUSE_REPORT, *PHID_MOUSE_REPORT;
FUNCTION THAT REPORTS MOUSE DATA:
VOID MouseReport(PDEVICE_EXTENSION devContext,GESTURE_DATA gestureData)
{
PHID_MOUSE_REPORT report;
NTSTATUS status;
WDFREQUEST request;
DbgPrint(“MouseReport”);
status = WdfIoQueueRetrieveNextRequest(devContext->InterruptMsgQueue, &request);
if(!NT_SUCCESS(status)){
DbgPrint(“WdfIoQueueRetrieveNextRequest failed with status: 0x%x\n”,status);
}else if (NT_SUCCESS(status)){
//
// 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_MOUSE_REPORT),
&report,
NULL); //bufferLength
if (!NT_SUCCESS(status)) { // should never happen
TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
“WdfRequestRetrieveOutputBuffer failed with status: 0x%x\n”, status);
DbgPrint((“Retrieve error\n”));
WdfRequestComplete(request, status);
}else{
// KdPrint(("mem size %d ", sizeof(HID_MOUSE_REPORT)));
// memset(report, 0, sizeof(HID_MOUSE_REPORT));
report->reportID = REPORTID_MOUSE;
report->buttons = 0x00;
report->xData = gestureData.tMotionData2D.lX;
report->yData = (-1)*gestureData.tMotionData2D.lY; // Device reports negated Y data for some reason
DbgPrint(" rpID: %d, x: %d, y: %d, buttons: %d\n",report->reportID,gestureData.tMotionData2D.lX,
(-1)*gestureData.tMotionData2D.lY,report->buttons);//report->ReportID,report->wXData,report->wYData);
WdfRequestComplete(request, status);
}
}
}
When I receive an “IOCTL_HID_READ_REPORT” request in my InternalDeviceControl function I forward the request to the appropriate queue with the following line of code (followed by the appropriate code to check for a failed forwarding attempt):
status = WdfRequestForwardToIoQueue(Request, devContext->InterruptMsgQueue);
Then, I call the MouseReport function from my EvtUsbInPipeReadComplete function (this is a function that is part of HidUsbFx2 sample code that I’ve made additions to in order to isolate the event in which I need to report the mouse data but the main functionality of this function is the same as the sample code).