Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hid_enumerate() gives unexpected device instances #155

Closed
devspectre opened this issue Apr 1, 2020 · 14 comments
Closed

hid_enumerate() gives unexpected device instances #155

devspectre opened this issue Apr 1, 2020 · 14 comments
Labels
macOS Related to macOS backend

Comments

@devspectre
Copy link

devspectre commented Apr 1, 2020

hid_enumerate() works well on Windows and was able to find the correct port by dev->product_string.
However, on Mac, hid_enumerate() gives three instances of hid_device_info and they all include same product_string and none of them are what I expected.
This is the code.

struct hid_device_info *devs, *cur_dev;
    devs = hid_enumerate(0x0, 0x0);
    cur_dev = devs;
    while (cur_dev) {
        struct hid_device_info *dev = cur_dev;
        cur_dev = cur_dev->next;

        if (dev->vendor_id != VID || dev->product_id != PID) {
            continue;
        }
        if (szPath && szPath[0] != 0x00) {
            // only check for the existence of device
            if (strcmp(dev->path, szPath) == 0) {
                ret = true;
                break;
            }
        } else {
            if (std::wstring(dev->product_string) == L"transport") {
                ret = true;
                if (szPath && size > 0) {
                    // save path
                    strncpy(szPath, dev->path, size);
                    break;
                }
            }
        }
    }

I debugged the app and found that string "transport" in dev->path as a substring in it.

Of course, windows code is a little bit different but logic is same as this.
I'd like to know what the problem is and how I can solve this.

@Youw
Copy link
Member

Youw commented Apr 1, 2020

  • product_string is not made up by hidapi - it is provided as is from the OS
  • product_string isn't guaranteed to be a unique device identifier by HID design; more than that - it may be localised, so different when system/locale preferences are changed
  • if your (USB) device has a few HID sub-devices, and you need to find a specific one, you probably want to find the device by VID+PID+usage+usage_page ; in rare cases, you may also use interface_number; product_string manufacturer_string are intended for user/logs, not for device identification

dev->path is a separate story - it is system/implementation specific, and only guaranteed to be unique for each device in the system, nothing more

@devspectre
Copy link
Author

Thank you for your answer.
It makes sense.
That string "transport" means that instance is the one we have to deal with to write/read to/from the HID device.
On windows, HID device gives 9 instances of hid_device_info and their product_strings are "XXX mouse", "XXX keyboard", "XXX multitouch", "XXX transport", ...
So I just need to get instance with product_string of "XXX transport" and deal with it.
On mac, I get three instances of hid_device_info from hid_enumerate().
And their product_strings are all equal.
How can I get correct instance for device I/O on mac?
Any idea?
Thanks in advance.

@todbot
Copy link
Contributor

todbot commented Apr 1, 2020

As @Youw mentioned, you need to filter by "usage" and "usage_page" in addition to "vendor_id" and "product_id". You probably should not rely on filtering by strings.

@devspectre
Copy link
Author

Thanks, @todbot !
I will try that

@devspectre
Copy link
Author

@todbot , @Youw, could you please let me know the meanings of usage_page and usage as well as interface_number and what they are intended to be used for?

@todbot
Copy link
Contributor

todbot commented Apr 6, 2020

HID usage and usage_pages settings in the HID report descriptor and are used to describe to the OS what kind of HID device it is. Common usages (like mouse, keyboard) will be seen by the OS and owned by them. You can get a list of common usages by looking at this PDF: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
A single HID device can have multiple usages. An example could be a device that is both a mouse and a keyboard. It could choose to show up as two devices (distinct VID/PID), or as a composite device where both devices are HID (thus interface_number would be different), or as a single device with multiple usages described in the HID report descriptor.

@Youw Youw added the macOS Related to macOS backend label Apr 6, 2020
@Youw Youw changed the title hid_enumerate() gives unexpected device instances label:macOS hid_enumerate() gives unexpected device instances Apr 6, 2020
z3ntu added a commit to z3ntu/hidapi that referenced this issue Apr 14, 2020
This reverts commit ca1a2d6.

Currently breaks razer_test, see libusb#155
@z3ntu
Copy link
Collaborator

z3ntu commented Apr 14, 2020

I also discovered today that this breaks my application on macOS. I'm currently checking for vendor_id, product_id and interface_number which worked fine until now but now I'm getting multiple matches with this combo which breaks things. And I'm guessing other applications will break as well because of this. (#139 will also cause this when it's merged)

@Youw
Copy link
Member

Youw commented Apr 15, 2020

I'm currently checking for vendor_id, product_id and interface_number which worked fine until now

I suspect you haven't used your application on Windows?

@z3ntu
Copy link
Collaborator

z3ntu commented Apr 15, 2020

I actually did run it on Windows a couple of times before (limited testing but still) and never saw an issue like that.

@Youw
Copy link
Member

Youw commented Apr 16, 2020

Windows always separates different usage/usage_page into a different logical devices
more than that - it enforces checks, so you could use only specific reports on a corresponding logical devices

would you be able to share a list of enumerated devices on Windows and macOS (with order preserved)?
maybe the order of devices is different, we might try to mimic device order on macOS in the same way as it is on Windows

in that case it would allow us to have same behavior on Windows and macOS AND don't break your (and others) application

@devspectre
Copy link
Author

Thank you all of you. I think my problem is solved.
:)

@Youw
Copy link
Member

Youw commented Apr 27, 2020

Care to share what was the solution?)

@devspectre
Copy link
Author

devspectre commented Apr 28, 2020

usage_page and usage along with vendor_id and product_id, combination of those values can be identifier.
We are still in process of testing with massive instances of devices.
Then it might be clear.

@z3ntu
Copy link
Collaborator

z3ntu commented Jan 7, 2021

Just for completeness, the fix in my software is this:

-        if (cur_dev->interface_number != 0) {
+        if (cur_dev->usage_page != 0x1 || cur_dev->usage != 0x80) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
macOS Related to macOS backend
Projects
None yet
Development

No branches or pull requests

4 participants