IOHIDManager OsX : wrong match between HID descriptor and HID report?

1.3k views Asked by At

I'm trying to use IOHIDManager API to read data from HID report of devices on Mac OsX such as X, Y, button1, Button2 of the mouse (Magic Apple Mouse)

With the API, I can dynamicaly read the descriptor but I have several problemes: - The API doesn't give me all the informations I need from the descriptor : for exemple, I don't find the informations about padding bits ! ... I have to calculate the padding myself to build my structure correctly. - The API doesn't give me the features(X, Y, btn1 ...) in the same order that the descriptor or the HID report!! How am I suppose to know the correct order to read the HID report then !?

so I don't have the correct matching with the HID report Data.

here are the informations given to me by the OsX API from the descriptor.

device 0x7f94f4804c70 is Apple Optical USB Mouse (vendor 5ac), max report size 6 
nb element descriptor : 11
        element (usage name) Generic Desktop item 0002 
        element (usage name) Generic Desktop item 0001 
        element (usage name) X 
        element (usage name) Y 
        element (usage name) Z 
        element (usage name) Wheel 
        element (usage name) Button 1 
        element (usage name) Button 2 
        element (usage name) Button 3 
        element (usage name) Button 4 
        element (usage name) Apple Reserved Mouse Data 

so I build a struct : X, Y, Z, Wheel, Btn1|Btn2|Btn3|Btn4, ARMD

here are the RAW informations given to me on Linux from the descriptor.

0x05, 0x01,                    // Usage Page (Generic Desktop)        0
0x09, 0x02,                    // Usage (Mouse)                       2
0xa1, 0x01,                    // Collection (Application)            4
0x05, 0x09,                    //   Usage Page (Button)               6
0x19, 0x01,                    //   Usage Minimum (1)                 8
0x29, 0x04,                    //   Usage Maximum (4)                 10
0x15, 0x00,                    //   Logical Minimum (0)               12
0x25, 0x01,                    //   Logical Maximum (1)               14
0x95, 0x04,                    //   Report Count (4)                  16
0x75, 0x01,                    //   Report Size (1)                   18
0x81, 0x02,                    //   Input (Data,Var,Abs)              20
0x95, 0x01,                    //   Report Count (1)                  22
0x75, 0x04,                    //   Report Size (4)                   24
0x81, 0x01,                    //   Input (Cnst,Arr,Abs)              26
0x05, 0x01,                    //   Usage Page (Generic Desktop)      28
0x09, 0x01,                    //   Usage (Pointer)                   30
0xa1, 0x00,                    //   Collection (Physical)             32
0x09, 0x30,                    //     Usage (X)                       34
0x09, 0x31,                    //     Usage (Y)                       36
0x09, 0x32,                    //     Usage (Z)                       38
0x09, 0x38,                    //     Usage (Wheel)                   40
0x15, 0x81,                    //     Logical Minimum (-127)          42
0x25, 0x7f,                    //     Logical Maximum (127)           44
0x75, 0x08,                    //     Report Size (8)                 46
0x95, 0x04,                    //     Report Count (4)                48
0x81, 0x06,                    //     Input (Data,Var,Rel)            50
0xc0,                          //   End Collection                    52
0x05, 0xff,                    //   Usage Page (Vendor Usage Page 0xff) 53
0x09, 0xc0,                    //   Usage (Vendor Usage 0xc0)         55
0x75, 0x08,                    //   Report Size (8)                   57
0x95, 0x01,                    //   Report Count (1)                  59
0x81, 0x02,                    //   Input (Data,Var,Abs)              61
0xc0,                          // End Collection                      63

so I could built a struct : Btn1|Btn2|Btn3|Btn4|0|0|0|0, X, Y, Z, Wheel, ARMD

From there, base on the OsX API, i'm building a structure almost identical (including padding bits) to "match" the HID report. so I have : X, Y, Z, Wheel, Btn1|Btn2|Btn3|Btn4|0|0|0|0, ARMD

I subscribe to the HID report and I parse it as it should fit my structure ... but it doesn't

Here, it is what I have when I clicked Btn1 on OsX:

device : 0x7fe609007500, id: 0 ---  01  00  00  00  00  00  size - 48
X : 1  Y : 0  Z : 0  Wheel : 0  Button 1 : 0  Button 2 : 0  Button 3 : 0  Button 4 : 0  ARMData : 0

the report tells me that X=1 !!!!

here, it is what I have on Linux

2.384001  B1: 1 | B2: 0 | B3: 0 | B4: 0 | # | X:    0 | Y:    0 | Z:    0 | Wheel:    0 | 0xff00c0: -127

This program works with some few devices as mices except the Magic Apple Mouse but I the similar problem with other Devices ... the API gives me the features in the wrong order and partial informations !

Is there something that i didn't understand? does someone have the same problem or better understand how tu use HID API on OSX?

3

There are 3 answers

2
David Grayson On

I don't have experience with this API so this answer might be off the mark. Also, I found your question kind of confusing.

It sounds like you are using the IOHIDManager API and are having trouble figuring out the exact bit structure of some HID report from a USB device.

I suspect that the exact bit structure is exactly the kind of detail that should be abstracted away from you by a high-level API like this one. Why do you need to know the exact structure? Can you just use IOHIDManagerRegisterInputValueCallback to read data from the device?

0
user1947994 On

I think I found the answer on this question.

The API return you a list of the elements you can find on the device. No matter which report ID and no matter the order the element in the list (there is actually a logic there, but not the one I was expected)

BUT the API adds a key, named "cookie", on each element and this key seems to respect the order of the elements found in the descriptor. I could use this cookie to build my structure in the correct order and compute the correct offset to parse correctly the input report.

device 0x7ff1f42072a0 is Apple Optical USB Mouse (vendor 5ac), max report size 6 
nb element descriptor : 11
    cookie: 1 - element (usage name) Generic Desktop item 0002 
    cookie: 2 - element (usage name) Generic Desktop item 0001 
    cookie: 3 - element (usage name) Button 1 
    cookie: 4 - element (usage name) Button 2 
    cookie: 5 - element (usage name) Button 3 
    cookie: 6 - element (usage name) Button 4 
    cookie: 7 - element (usage name) X 
    cookie: 8 - element (usage name) Y 
    cookie: 9 - element (usage name) Z 
    cookie: 10 - element (usage name) Wheel 
    cookie: 11 - element (usage name) Apple Reserved Mouse Data 

EDIT : After more tests, this solution doesn't work for all the devices. The Cookie Key do not respect descriptor order in the case of touch screen for example :/

0
pmdj On

It's hard to see exactly what it is you're asking, but it seems that you're happy to use the raw input report descriptor, and yet you're trying to rely on Linux' descriptor? (don't forget the driver can rewrite descriptors and reports)

You can access the raw report descriptor on OSX using IOHIDDeviceGetProperty(hid_device_ref, CFSTR(kIOHIDReportDescriptorKey));