HID Usage is property of a HID top-level-collection, not of a HID device #453

Open
opened 2022-09-11 08:00:11 -05:00 by JoergAtGithub · 8 comments
JoergAtGithub commented 2022-09-11 08:00:11 -05:00 (Migrated from github.com)

The HID standard doesn't define a Usage for an whole HID device. These property belongs to a top level collection.

  • This fits only with HIDAPIs Windows backend, because an hid_device structure is returned per top-level collection.
  • For the other backends, the hid_device structure is returned for an whole HID device, which can consist multiple top-level collections. Therefore you can get only the Usage of the first top-level collection that appears in the report descriptor of an HID device.

From USB HID spec 1.11 page 34:
grafik

The HID standard doesn't define a Usage for an whole HID device. These property belongs to a top level collection. - This fits only with HIDAPIs Windows backend, because an hid_device structure is returned per top-level collection. - For the other backends, the hid_device structure is returned for an whole HID device, which can consist multiple top-level collections. Therefore you can get only the Usage of the first top-level collection that appears in the report descriptor of an HID device. From USB HID spec 1.11 page 34: ![grafik](https://user-images.githubusercontent.com/64457745/189528411-62a448a0-6463-4e5e-811f-e579a2bbdf56.png)
Youw commented 2022-09-11 08:30:41 -05:00 (Migrated from github.com)

Sure, that is true.
But to "fix" it right, we would have to introduce a breaking API change - hid_device_info should contain some kind of collection of usage_page/usage pages, instead of a single one. That way the API/behavior will be uniform on all platforms.
Current approach (with duplicating the devices) is more about having the functionality and keep full backward compatibility.

I'd say, to make it "right" - is something we should consider for V1.

Sure, that is true. But to "fix" it right, we would have to introduce a breaking API change - `hid_device_info` should contain some kind of collection of usage_page/usage pages, instead of a single one. That way the API/behavior will be uniform on all platforms. Current approach (with duplicating the devices) is more about having the functionality _and_ keep full backward compatibility. I'd say, to make it "right" - is something we should consider for V1.
mcuee commented 2023-03-19 22:32:23 -05:00 (Migrated from github.com)

@Youw

Just a minor thing, you change the title of this issue to "a HID" from "an HID", but actually I think it is more correct to use "an HID".

Ref: https://www.pristineword.com/grammar-an-h/

@Youw Just a minor thing, you change the title of this issue to "a HID" from "an HID", but actually I think it is more correct to use "an HID". Ref: https://www.pristineword.com/grammar-an-h/
Youw commented 2023-03-20 05:46:55 -05:00 (Migrated from github.com)

Be aware that the choice between a and an depends on the initial sound of the following word

It’s an H. Because the character H starts with a vowel sound (aitch)

So the question here is what is the correct pronounce of a HID - is it 'an (aitch i di)', or as a single word - 'a (hid)'.
Maybe I'm biased by my cultural environment (english in not my native), but I always pronounce it as 'a hid'.

> Be aware that the choice between a and an depends on the _initial sound of the following word_ > It’s **an H**. Because the character **H** starts with a vowel sound (_aitch_) So the question here is what is the correct pronounce of a HID - is it '_an_ (_aitch i di_)', or as a single word - '_a_ (_hid_)'. Maybe I'm biased by my cultural environment (english in not my native), but I always pronounce it as '_a hid_'.
mcuee commented 2023-03-20 06:12:16 -05:00 (Migrated from github.com)

So the question here is what is the correct pronounce of a HID - is it 'an (aitch i di)', or as a single word - 'a (hid)'. Maybe I'm biased by my cultural environment (english in not my native), but I always pronounce it as 'a hid'.

I see, I always pronouce it as H-I-D, but I am not a native English speaker either...

> So the question here is what is the correct pronounce of a HID - is it '_an_ (_aitch i di_)', or as a single word - '_a_ (_hid_)'. Maybe I'm biased by my cultural environment (english in not my native), but I always pronounce it as '_a hid_'. I see, I always pronouce it as H-I-D, but I am not a native English speaker either...
Youw commented 2023-03-20 11:05:13 -05:00 (Migrated from github.com)

Got some interesting argument from my colleague:
MS documentation refers to HID as "a HID":
image
and multiple other occurrences.

Got some interesting argument from my colleague: [MS](https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/hid-architecture) documentation refers to HID as "a HID": ![image](https://user-images.githubusercontent.com/5939659/226399312-8b1a02e6-9e49-4ef0-ada5-a9ec51e61c8e.png) and multiple other occurrences.
k1-801 commented 2024-03-14 06:32:14 -05:00 (Migrated from github.com)

But to "fix" it right, we would have to introduce a breaking API change

Or, we could just introduce a separate structure called something in the lines of hid_device_collection or hid_top_level_device that represents the top-level collection (a single physical device) and can contain multiple hid_device_info's. Then we introduce a function hid_enumerate_collections() that makes them. Problem solved.

The structure would be basically a copy of hid_device_info with no usage_page and on Windows it's path field would be empty. On other systems it would be able to be opened by path, if necessary.

Might interfere with the current hotplug implementation, though. On Windows each of them gets a separate event and there isn't much we can do.

UPD: hid_free_collection would also be needed.
UPD2: found a solution on how to merge them on Windows, but it might degrade the performance.
UPD3: if we really care about performance, we can avoid writing the hid_device_info's into the collection structure and instead have a separate function hid_enumerate_collection_devices() that retrieves all hid_device_info's for one on request. This will save some time on Linux and on MacOS, where this data is retrieved for each collection from a single source on every enumeration. On Windows it would have to be assembled from multiple endpoints that aren't connected with one another.

I could make a simplified implementation if it sounds like a good idea to you.

> But to "fix" it right, we would have to introduce a breaking API change Or, we could just introduce a separate structure called something in the lines of `hid_device_collection` or `hid_top_level_device` that represents the top-level collection (a single physical device) ~~and can contain multiple `hid_device_info`'s~~. Then we introduce a function `hid_enumerate_collections()` that makes them. Problem solved. The structure would be basically a copy of `hid_device_info` with no usage_page and on Windows it's path field would be empty. On other systems it would be able to be opened by path, if necessary. Might interfere with the current hotplug implementation, though. On Windows each of them gets a separate event and there isn't much we can do. UPD: `hid_free_collection` would also be needed. UPD2: found a solution on how to merge them on Windows, but it might degrade the performance. UPD3: if we **really** care about performance, we can avoid writing the `hid_device_info`'s into the collection structure and instead have a separate function `hid_enumerate_collection_devices()` that retrieves all `hid_device_info`'s for one on request. This will save some time on Linux and on MacOS, where this data is retrieved for each collection from a single source on every enumeration. On Windows it would have to be assembled from multiple endpoints that aren't connected with one another. I could make a simplified implementation if it sounds like a good idea to you.
Youw commented 2024-03-26 05:36:17 -05:00 (Migrated from github.com)

a solution on how to merge them on Windows

If you imply having a single "virtual" device on HIDAPI level that would agregate all top level collections as reported by WinAPI - I'm against that idea.
That would complicate the backend implementation.

I'd be happier to see a hid_device_info with a list of available collections (usaga/usage_page pairs) where on most systems there would be a list of available pairs, and on Windows there would be multiple devices with a list contain a single element.

I'm more into having as simpler wrapper/implementation over what OS provides as possible.

> a solution on how to merge them on Windows If you imply having a single "virtual" device on HIDAPI level that would agregate all top level collections as reported by WinAPI - I'm against that idea. That would complicate the backend implementation. I'd be happier to see a hid_device_info with a list of available collections (usaga/usage_page pairs) where on most systems there would be a list of available pairs, and on Windows there would be multiple devices with a list contain a single element. I'm more into having as simpler wrapper/implementation over what OS provides as possible.
JayFoxRox commented 2025-08-02 05:07:12 -05:00 (Migrated from github.com)

I'm more into having as simpler wrapper/implementation over what OS provides as possible. [...]
I'd be happier to see a hid_device_info with a list of available collections (usaga/usage_page pairs) where on most systems there would be a list of available pairs, and on Windows there would be multiple devices with a list contain a single element.

I'm not sure this is a good idea.
I'd expect hidapi to abstract platform specific details so the applications using hidapi become multi-platform (ignoring smaller quirks) - isn't that the whole point of it?

I don't think it'd be wise to expect the application to handle more than one API behaviour (depending on backend).
With such API design I don't really see the benefit of using hidapi over just using the native functions in each application (or using another hid library), because the burden of "fixing" the interface behaviour would have to be part of the application anyway (which is probably more work than interfacing with the platforms hid interface).
By using native functions over hidapi you'd at least be able to know the quirks at time of writing, whereas with hidapi you'd have to speculatively fix all possible behaviour quirks of each backend - hidapi would be useless.

The existing API and platform specific behaviour appears to already cause issues which breaks cross-platform support.
OpenRGB does hid_enumerate and calls a detector function for each device, trying to recombine different usage pages / usages into the same device again.
That code was written for some platform where each report in the top-level collection is returned as separate devices, but for me (on Linux) I only seem to receive the report of the top-level collection - so it doesn't work depending on the backend.

Likewise, I was also surprised that OpenRGB has to copy internal hidapi functions to parse the report descriptors. I understand that hidapi hasn't reach v1 yet, but if it doesn't actually expose functions to work with found hid devices and wouldn't even abstract/fix platform specific behaviour, then I'm not sure why anyone should consider hidapi - the application seems to have to do all the work anyway and hidapi merely acts as reference code.

> I'm more into having as simpler wrapper/implementation over what OS provides as possible. [...] > I'd be happier to see a hid_device_info with a list of available collections (usaga/usage_page pairs) where on most systems there would be a list of available pairs, and on Windows there would be multiple devices with a list contain a single element. I'm not sure this is a good idea. I'd expect hidapi to abstract platform specific details so the applications using hidapi become multi-platform (ignoring smaller quirks) - isn't that the whole point of it? I don't think it'd be wise to expect the application to handle more than one API behaviour (depending on backend). With such API design I don't really see the benefit of using hidapi over just using the native functions in each application (or using another hid library), because the burden of "fixing" the interface behaviour would have to be part of the application anyway (which is probably more work than interfacing with the platforms hid interface). By using native functions over hidapi you'd at least be able to know the quirks at time of writing, whereas with hidapi you'd have to speculatively fix all possible behaviour quirks of each backend - hidapi would be useless. The existing API and platform specific behaviour appears to already cause issues which breaks cross-platform support. OpenRGB does `hid_enumerate` and calls a detector function for each device, [trying to recombine different usage pages / usages into the same device again](https://gitlab.com/CalcProgrammer1/OpenRGB/-/merge_requests/2877/diffs#9bcf09e63d6e7ae45321d73200ff0f41380aefe6_0_22). That code was written for some platform where each report *in* the top-level collection is returned as separate devices, but for me (on Linux) I only seem to receive the report *of the* top-level collection - so it doesn't work depending on the backend. Likewise, I was also surprised that [OpenRGB has to copy internal hidapi functions to parse the report descriptors](https://gitlab.com/CalcProgrammer1/OpenRGB/-/merge_requests/2877/diffs#diff-content-242e0bd7e405cbdaded0595d37dc90aface6a188). I understand that hidapi hasn't reach v1 yet, but if it doesn't actually expose functions to work with found hid devices *and* wouldn't even abstract/fix platform specific behaviour, then I'm not sure why anyone should consider hidapi - the application seems to have to do all the work anyway and hidapi merely acts as reference code.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-libusb/hidapi#453
No description provided.