I remember seeing on a janaxelson related website about using multiple mouse in programs. Well, I am trying to get a report descriptor right but I believe I might have done something wrong. Anyone willing to take a look?
Its a really a simple report descriptor in which an intermediate device passes input down the chain to a mouse device its connected to. I have an error somewhere in the code descriptor or driver code but I believe its in the descriptor. I can post what it returns for the usage too if anyone needs it.
Here's the report descriptor:
HID_REPORT_DESCRIPTOR G_DefaultReportDescriptor[] = {
0x06, 0x00,0xFF, // (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined
0x09, 0x01, // (LOCAL) USAGE 0xFF000001
0xA1, 0x01, //(MAIN) COLLECTION 0x01 Application (Usage=0xFF000001: Page=Vendor-defined, Usage=, Type=)
0x85, 0x0F, // (GLOBAL) REPORT_ID 0x0F (15)
0x09, 0x01, // (LOCAL) USAGE 0xFF000001
0x15, 0x00, // (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0
0x26, 0xFF,0x00, // (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255)
0x75, 0x08, //(GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
0x95, 0x09, // go back to (GLOBAL) REPORT_COUNT 0x0009 (9) Number of fields
0xB1, 0x00, // (MAIN) FEATURE 0x00000000 (9 fields x 8 bits) 0=Data 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
0x09, 0x01, // (LOCAL) USAGE 0xFF000001
0x95, 0x01, // go back to (GLOBAL) REPORT_COUNT 0x0001 (1) Number of fields
0x81, 0x00, // (MAIN) INPUT 0x00000000 (1 field x 8 bits) 0=Data 0=Array 0=Absolute 0=Ignored 0=Ignored 0=PrefState 0=NoNull
0x09, 0x01, //(LOCAL) USAGE 0xFF000001
0x95, 0x07, // (GLOBAL) REPORT_COUNT 0x0007 (7) Number of fields
0x91, 0x00, //(MAIN) OUTPUT 0x00000000 (7 fields x 8 bits) 0=Data 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
0xC0, //(MAIN) END_COLLECTION Application
0x05, 0x01, // (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
0x09, 0x02, // (LOCAL) USAGE 0x00010002 Mouse (CA=Application Collection)
0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0x00010002: Page=Generic Desktop Page, Usage=Mouse, Type=CA)
0x09, 0x01, // (LOCAL) USAGE 0x00010001 Pointer (CP=Physical Collection)
0xA1, 0x02, // (MAIN) COLLECTION 0x02 Logical (Usage=0x00010001: Page=Generic Desktop Page, Usage=Pointer, Type=CP) <-- Warning: USAGE type should be CL (Logical)
0x05, 0x0A, // (GLOBAL) USAGE_PAGE 0x000A Ordinal Page
0x09, 0x01, // (LOCAL) USAGE 0x000A0001 Instance 1 (UM=Usage Modifier)
0x85, 0x01, // (GLOBAL) REPORT_ID 0x01 (1)
0xA1, 0x00, // (MAIN) COLLECTION 0x00 Physical (Usage=0x000A0001: Page=Ordinal Page, Usage=Instance 1, Type=UM) <-- Warning: USAGE type should be CP (Physical)
0x05, 0x09, // (GLOBAL) USAGE_PAGE 0x0009 Button Page
0x19, 0x01, // (LOCAL) USAGE_MINIMUM 0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot)
0x29, 0x03, // (LOCAL) USAGE_MAXIMUM 0x00090003 Button 3 Tertiary (MULTI=Selector, On/Off, Momentary, or One Shot)
0x15, 0x00, // (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0
0x25, 0x01, // (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
0x75, 0x01, // (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
0x95, 0x03, // (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields
0x81, 0x02, // (MAIN) INPUT 0x00000002 (3 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
0x95, 0x05, // (GLOBAL)REPORT_COUNT 0x05 (5) Number of fields
0x81, 0x03, // (MAIN)INPUT 0x00000003 (5 fields x 1 bit) 1 = Constant 1 = Variable 0 = Absolute 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0x05, 0x01, // (GLOBAL)USAGE_PAGE 0x0001 Generic Desktop Page
0x09, 0x30, // (LOCAL)USAGE 0x00010030 X(DV = Dynamic Value)
0x09, 0x31, // (LOCAL)USAGE 0x00010031 Y(DV = Dynamic Value)
0x15, 0x81, // (GLOBAL)LOGICAL_MINIMUM 0x81 (-127)
0x25, 0x7F, // (GLOBAL)LOGICAL_MAXIMUM 0x7F (127)
0x75, 0x08, // (GLOBAL)REPORT_SIZE 0x08 (8) Number of bits per field
0x95, 0x02, // (GLOBAL)REPORT_COUNT 0x02 (2) Number of fields
0x81, 0x06, // (MAIN)INPUT 0x00000006 (2 fields x 8 bits) 0 = Data 1 = Variable 1 = Relative 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0xC0, // END_COLLECTION Physical
0x05, 0x0A, // (GLOBAL)USAGE_PAGE 0x000A Ordinal Page
0x09, 0x02, // (LOCAL)USAGE 0x000A0002 Instance 2 (UM = Usage Modifier)
0x85, 0x02, // (GLOBAL)REPORT_ID 0x02 (2)
0xA1, 0x00, // (MAIN)COLLECTION 0x00 Physical(Usage = 0x000A0002: Page = Ordinal Page, Usage = Instance 2, Type = UM) < --Warning: USAGE type should be CP(Physical)
0x05, 0x09, // (GLOBAL)USAGE_PAGE 0x0009 Button Page
0x19, 0x01, // (LOCAL)USAGE_MINIMUM 0x00090001 Button 1 Primary / trigger(MULTI = Selector, On / Off, Momentary, or One Shot)
0x29, 0x03, // (LOCAL)USAGE_MAXIMUM 0x00090003 Button 3 Tertiary(MULTI = Selector, On / Off, Momentary, or One Shot)
0x15, 0x00, // (GLOBAL)LOGICAL_MINIMUM 0x00 (0)
0x25, 0x01, // (GLOBAL)LOGICAL_MAXIMUM 0x01 (1)
0x75, 0x01, // (GLOBAL)REPORT_SIZE 0x01 (1) Number of bits per field
0x95, 0x03, // (GLOBAL)REPORT_COUNT 0x03 (3) Number of fields
0x81, 0x02, // (MAIN)INPUT 0x00000002 (3 fields x 1 bit) 0 = Data 1 = Variable 0 = Absolute 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0x95, 0x05, // (GLOBAL)REPORT_COUNT 0x05 (5) Number of fields
0x81, 0x03, // (MAIN)INPUT 0x00000003 (5 fields x 1 bit) 1 = Constant 1 = Variable 0 = Absolute 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0x05, 0x01, // (GLOBAL)USAGE_PAGE 0x0001 Generic Desktop Page
0x09, 0x30, // (LOCAL)USAGE 0x00010030 X(DV = Dynamic Value)
0x09, 0x31, // (LOCAL)USAGE 0x00010031 Y(DV = Dynamic Value)
0x15, 0x81, // (GLOBAL)LOGICAL_MINIMUM 0x81 (-127)
0x25, 0x7F, // (GLOBAL)LOGICAL_MAXIMUM 0x7F (127)
0x75, 0x08, // (GLOBAL)REPORT_SIZE 0x08 (8) Number of bits per field
0x95, 0x02, // (GLOBAL)REPORT_COUNT 0x02 (2) Number of fields
0x81, 0x06, // (MAIN)INPUT 0x00000006 (2 fields x 8 bits) 0 = Data 1 = Variable 1 = Relative 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0xC0, // END_COLLECTION Physical
0x05, 0x0A, // (GLOBAL)USAGE_PAGE 0x000A Ordinal Page
0x09, 0x03, // (LOCAL)USAGE 0x000A0003 Instance 3 (UM = Usage Modifier)
0x85, 0x03, // (GLOBAL)REPORT_ID 0x03 (3)
0xA1, 0x00, // (MAIN)COLLECTION 0x00 Physical(Usage = 0x000A0003: Page = Ordinal Page, Usage = Instance 3, Type = UM) < --Warning: USAGE type should be CP(Physical)
0x05, 0x09, // (GLOBAL)USAGE_PAGE 0x0009 Button Page
0x19, 0x01, // (LOCAL)USAGE_MINIMUM 0x00090001 Button 1 Primary / trigger(MULTI = Selector, On / Off, Momentary, or One Shot)
0x29, 0x03, // (LOCAL)USAGE_MAXIMUM 0x00090003 Button 3 Tertiary(MULTI = Selector, On / Off, Momentary, or One Shot)
0x15, 0x00, // (GLOBAL)LOGICAL_MINIMUM 0x00 (0)
0x25, 0x01, // (GLOBAL)LOGICAL_MAXIMUM 0x01 (1)
0x75, 0x01, // (GLOBAL)REPORT_SIZE 0x01 (1) Number of bits per field
0x95, 0x03, // (GLOBAL)REPORT_COUNT 0x03 (3) Number of fields
0x81, 0x02, // (MAIN)INPUT 0x00000002 (3 fields x 1 bit) 0 = Data 1 = Variable 0 = Absolute 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0x95, 0x05, // (GLOBAL)REPORT_COUNT 0x05 (5) Number of fields
0x81, 0x03, // (MAIN)INPUT 0x00000003 (5 fields x 1 bit) 1 = Constant 1 = Variable 0 = Absolute 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0x05, 0x01, // (GLOBAL)USAGE_PAGE 0x0001 Generic Desktop Page
0x09, 0x30, // (LOCAL)USAGE 0x00010030 X(DV = Dynamic Value)
0x09, 0x31, // (LOCAL)USAGE 0x00010031 Y(DV = Dynamic Value)
0x15, 0x81, // (GLOBAL)LOGICAL_MINIMUM 0x81 (-127)
0x25, 0x7F, // (GLOBAL)LOGICAL_MAXIMUM 0x7F (127)
0x75, 0x08, // (GLOBAL)REPORT_SIZE 0x08 (8) Number of bits per field
0x95, 0x02, // (GLOBAL)REPORT_COUNT 0x02 (2) Number of fields
0x81, 0x06, // (MAIN)INPUT 0x00000006 (2 fields x 8 bits) 0 = Data 1 = Variable 1 = Relative 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0xC0, // END_COLLECTION Physical
0x05, 0x0A, // (GLOBAL)USAGE_PAGE 0x000A Ordinal Page
0x09, 0x04, // (LOCAL)USAGE 0x000A0004 Instance 4 (UM = Usage Modifier)
0x85, 0x04, // (GLOBAL)REPORT_ID 0x04 (4)
0xA1, 0x00, // (MAIN)COLLECTION 0x00 Physical(Usage = 0x000A0004: Page = Ordinal Page, Usage = Instance 4, Type = UM) < --Warning: USAGE type should be CP(Physical)
0x05, 0x09, // (GLOBAL)USAGE_PAGE 0x0009 Button Page
0x19, 0x01, // (LOCAL)USAGE_MINIMUM 0x00090001 Button 1 Primary / trigger(MULTI = Selector, On / Off, Momentary, or One Shot)
0x29, 0x03, // (LOCAL)USAGE_MAXIMUM 0x00090003 Button 3 Tertiary(MULTI = Selector, On / Off, Momentary, or One Shot)
0x15, 0x00, // (GLOBAL)LOGICAL_MINIMUM 0x00 (0)
0x25, 0x01, // (GLOBAL)LOGICAL_MAXIMUM 0x01 (1)
0x75, 0x01, // (GLOBAL)REPORT_SIZE 0x01 (1) Number of bits per field
0x95, 0x03, // (GLOBAL)REPORT_COUNT 0x03 (3) Number of fields
0x81, 0x02, // (MAIN)INPUT 0x00000002 (3 fields x 1 bit) 0 = Data 1 = Variable 0 = Absolute 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0x95, 0x05, // (GLOBAL)REPORT_COUNT 0x05 (5) Number of fields
0x81, 0x03, // (MAIN)INPUT 0x00000003 (5 fields x 1 bit) 1 = Constant 1 = Variable 0 = Absolute 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0x05, 0x01, // (GLOBAL)USAGE_PAGE 0x0001 Generic Desktop Page
0x09, 0x30, // (LOCAL)USAGE 0x00010030 X(DV = Dynamic Value)
0x09, 0x31, // (LOCAL)USAGE 0x00010031 Y(DV = Dynamic Value)
0x15, 0x81, // (GLOBAL)LOGICAL_MINIMUM 0x81 (-127)
0x25, 0x7F, // (GLOBAL)LOGICAL_MAXIMUM 0x7F (127)
0x75, 0x08, // (GLOBAL)REPORT_SIZE 0x08 (8) Number of bits per field
0x95, 0x02, // (GLOBAL)REPORT_COUNT 0x02 (2) Number of fields
0x81, 0x06, // (MAIN)INPUT 0x00000006 (2 fields x 8 bits) 0 = Data 1 = Variable 1 = Relative 0 = NoWrap 0 = Linear 0 = PrefState 0 = NoNull 0 = NonVolatile 0 = Bitmap
0xC0, // END_COLLECTION Physical
0xC0, // END_COLLECTION Logical
0xC0, // END_COLLECTION Application
};
Here's the code in the original program which uses the default usage for a generic vendor device (really needs to be changed to a mouse device):
BOOLEAN
CheckIfOurDevice(
HANDLE file)
{
PHIDP_PREPARSED_DATA Ppd; // The opaque parser info describing this device
HIDP_CAPS Caps; // The Capabilities of this hid device.
USAGE MyUsagePage = 0xff00;
USAGE MyUsage = 0x0001;
HIDD_ATTRIBUTES attr; // Device attributes
if (!HidD_GetAttributes(file, &attr))
{
printf("Error: HidD_GetAttributes failed \n");
return FALSE;
}
printf("Device Attributes - PID: 0x%x, VID: 0x%x \n", attr.ProductID, attr.VendorID);
if ((attr.VendorID != HIDMINI_DEFAULT_VID) || (attr.ProductID != HIDMINI_DEFAULT_PID))
{
printf("Device attributes doesn't match the sample \n");
return FALSE;
}
if (!HidD_GetPreparsedData (file, &Ppd))
{
printf("Error: HidD_GetPreparsedData failed \n");
return FALSE;
}
if (!HidP_GetCaps (Ppd, &Caps))
{
printf("Error: HidP_GetCaps failed \n");
HidD_FreePreparsedData (Ppd);
return FALSE;
}
if ((Caps.UsagePage == MyUsagePage) && (Caps.Usage == MyUsage)){
printf("Success: Found my device.. \n");
return TRUE;
}
return FALSE;
}