Closed andrfgs closed 3 years ago
Write fails with -1 and Read returns just 7 bytes and crashes the device
Does BUFFER_SIZE include an extra byte for the report ID?
Yes, I also tried a very large BUFFER_SIZE. If I use a larger BUFFER_SIZE it will only use the bytes required +1 right?
The length should be 154. I gave BUFFER_SIZE a size of 155, 200, 1024 and all fail.
If I use a larger BUFFER_SIZE it will only use the bytes required +1 right?
For a read, yes... writes I'm not sure, but I think the extra data is sent,¹ which can cause the device to misbehave, or at the very least refuse it.
From what you're describing, the correct alternative would be:
#define BUFFER_SIZE 155
/* ... */
unsigned char buf[BUFFER_SIZE];
int r = -1;
buf[0] = 4;
r = hid_get_feature_report(dev, buf, BUFFER_SIZE);
What additional information does hid_error(dev)
return in this case (assuming r < 0
)?
¹ Taking the examples you showed above literally, you could have sent random data (depending on whether the compiler saved you or not with the uninitialized buffer). But I'm guessing the real code ensured sensible buffer contents for the writes.
It reports (null)
I tried using the hidraw example from the linux source and it also fails. I'm guessing this is a problem with Linux not liking my mouse?
I'm sorry, your first post already included this ("Broken pipe").
I'm guessing this is a problem with Linux not liking my mouse?
It's possible... Related to this, are there any special drivers or quirks for this device in the kernel?
Another possibility is that the device requires some specific write(s) before you can request a feature report from it.
The Broken pipe
comes from ioctl not the hidapi library. The hid_error() is not reporting anything.
This is a T7 Gaming Mouse (which is a cheap Chinese unit with a very shady manufacturer Sinowealth
). This repository has a custom driver using a C# library on Windows. I ran it and it works on Windows, but that library makes use of Windows' own proprietary hid library through native calls.
To the best of my knowledge, the program makes no other writes prior to reading the features.
As I said, this also happened in the hidraw example above, so maybe it's a problem in hidraw itself not recognising the device properly.
One more thing, do I need to initialise the other positions of the buffer for getting the feature report? Cause from what the library says, I should just set the report id part. Still I also attempted memsetting the buffer full of 0's still to no avail.
Can someone help me with this problem? I'd like to know if the following C code:
unsigned char buf[BUFFER_SIZE];
int r = -1;
buf[0] = 4;
r = hid_get_feature_report(dev, buf, BUFFER_SIZE);
Is similar or not to the C# equivalent in this repository (lines 26-32):
byte[] data = new byte[mFeatureLen];
bool success = false;
success = mDevice.ReadFeatureData(out data, 4);
The C# uses HidLibrary, which calls a native Windows method:
NativeMethods.HidD_GetFeature(hidHandle, buffer, buffer.Length);
By knowing this I can determine if the problem lies in my usage of the library or in an internal ioctl problem with my hardware.
What does your HID Report Descriptor look like?
I can't get the report descriptor form the hidapi library.
This is the result of running the hidraw example (which also fails to get the feature report). I basically used the code from the example and replaced the path with /dev/hidraw0
:
Report Descriptor Size: 71
Report Descriptor:
5 1 9 2 a1 1 9 1 a1 0 5 9 19 1 29 5 15 0 25 1 75 1 95 5 81 2 95 3 81 1 5 1 9 30 9 31 16 0 80 26 ff 7f 75 10 95 2 81 6 9 38 15 80 25 7f 75 8 95 1 81 6 5 c a 38 2 95 1 81 6 c0 c0
By the way, I switched to libusb and whenever the program ends, the mouse stops working and I have to replug it again. This doesn't happen with hidraw.
First, if this is on Linux, are you running your code as root
or have set up udev rules for it?
From that report descriptor data, parsed by https://eleccelerator.com/usbdescreqparser/ , your device looks like a kind of mouse? Generally you cannot access keyboards and mice because the OS grabs them. In order to read them, you generally have to uninstall/deregister the OS's keyboard/mouse driver so you can own the mouse.
(Sorry I came onto this issue without seeing the initial issue, you state it's a mouse and it looks like you're trying to read the position reports)
I am running the code as root yes, I tried to use it in user mode first but it would complain about permissions. I understand the OS may grab control over Mice and Keyboards but here's the thing: I'm on a MSI laptop, I can use (https://github.com/Gibtnix/MSIKLM) just fine, which is a program that changes my keyboard's color and uses this exact library. So I thought this should work for all devices.
It does make sense the OS grabs control of the hardware, but then it doesn't make much sense that Linux only does it for some of the hardware, not all.
Is there any way of deregistering the mouse and reregister when I'm done through hidapi or libusb? Or am I really gonna need to write a Linux driver module? By the way, I suppose Windows doesn't have this restriction?
On Windows, the restrictions are even more strict. But a physical keyboard may report more than one logical HID device, one of which may be special led controlling device (which is not a keyboard) and the restrictions won't apply. Can you confirm is that could be the case or not?
This is the result of lsusb
> lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 0bda:0129 Realtek Semiconductor Corp. RTS5129 Card Reader Controller
Bus 001 Device 002: ID 258a:1007 SINOWEALTH Game Mouse
Bus 001 Device 006: ID 8087:0aaa Intel Corp.
Bus 001 Device 005: ID 5986:211b Acer, Inc HD Webcam
Bus 001 Device 004: ID 1770:ff00 MSI EPF USB MSI EPF USB
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
I can use hidapi on the keyboard, using that msiklm program. The msiklm opens the device using:
hid_device* dev = NULL;
if (hid_init() == 0)
dev = hid_open(0x1770, 0xff00, 0);
And it sets the colors using:
hid_send_feature_report(dev, buffer, 8);
So in short, I don't think the keyboard uses a custom device for the colors, but I may be wrong.
EDIT: NOTE, THIS CODE IS FOR THE KEYBOARD DEVICE, THE DEVICE I WANT TO WORK WITH HIDAPI IS THE MOUSE NOT THE KEYBOARD. THIS WAS JUST TO SHOW HOW THE KEYBOARD WORKED.
Como vai.
I am having the same issues with hidapi on ubuntu. my program just doesn't seem to run...just error out.
What about usage/usage_page pairs? Can you check the usage/usage_page of the devices you're opening on Windows and Linux? P.S.: in order to do that, you need to hid_enumerate all devices and check corresponding fields of device_info before opening the device.
@andrfgs
The code that showed as a reference also deals with two devices (in that case the usage/usage page are the same, but the lengths are not):
public T7Mouse()
{
mDevice = new T7Device(0x480);
mGeneral = new T7Device(0x9A);
// ...
—T7 Wired Gaming Mouse/T7/T7Mouse.cs#L30-L33
public T7Device(short featureLen)
{
mFeatureLen = featureLen;
mDevice = HidDevices.Enumerate(0x258A, 0x1007).ToList().Find((f) =>
{
return (ushort)f.Capabilities.UsagePage == 0xff00 && f.Capabilities.Usage == 1
&& f.Capabilities.FeatureReportByteLength == featureLen;
});
}
—T7 Wired Gaming Mouse/T7/T7Device.cs#L16-L23
P.S. I'm not sure how Random06457's library can work with your mouse, since the vendor/product IDs don't appear to match (I'm guessing they are the parameters of HidDevices.Enumerate
), and according to the lsusb output you posted later, neither does the HID descriptor: different usage, usage page and report sizes.
@jonasmalacofilho
The first code block is not the vendor ID, that's the length of the internal buffer. I know that value is in a confusing format but the code that opens the device is this one mDevice = HidDevices.Enumerate(0x258A, 0x1007)
in the second block.
@Youw In Linux, I tried hidapi enumerate with this code
struct hid_device_info* cur = hid_enumerate(0x258A, 0x1007);
while (cur != NULL)
{
wprintf(L"%S, %d:%d, %S\n", cur->product_string, cur->vendor_id, cur->product_id, cur->serial_number);
cur = cur->next;
}
Which prints:
Game Mouse, 9610:4103, (null)
Game Mouse, 9610:4103, (null)
Why is the serial number null? I ran this with sudo.
@andrfgs
The first code block is not the vendor ID
I didn't claim that it was.
What I pointed out is that the vendor/product ID (parameters to HidDevices.Enumerate
) don't match the lsusb
output you posted. Neither does HID usage, usage page or any of the two report sizes.
The serial number is a USB string descriptor, but it isn't required (according to the USB specification).
OK, perhaps I didn't explain myself properly. The device in question is:
Bus 001 Device 002: ID 258a:1007 SINOWEALTH Game Mouse
The code I showed above:
hid_device* dev = NULL;
if (hid_init() == 0)
dev = hid_open(0x1770, 0xff00, 0);
was to show the Keyboard worked in hidapi but not the mouse. I just showed it because someone asked me about it. And also to try to find why one works and the other doesn't. Perhaps I should've been more explicit about it.
The mouse vendor id is 0x258A
and the product id is 0x1007
The REAL CODE I'm trying to use is this:
hid_device* dev = NULL;
if (hid_init() == 0)
dev = hid_open(0x258A, 0x1007, 0);
By the way, hid_enumerate
is reporting the same numbers (in decimal), but when I try to:
struct hid_device_info* cur = hid_enumerate(0x258A, 0x1007);
while (cur != NULL)
{
wprintf(L"%S, %S, %d:%d, %S\n", cur->manufacturer_string, cur->product_string, cur->vendor_id, cur->product_id, cur->serial_number);
cur = cur->next;
}
dev = hid_open(cur->vendor_id, cur->product_id, NULL);
unsigned char buf[BUFFER_SIZE];
memset(&buf, 0x0, BUFFER_SIZE);
int r = -1;
buf[0] = 4;
r = hid_get_feature_report(dev, buf, BUFFER_SIZE);
wprintf(L"Read a total of %d bytes\n", r);
It results in a Segmentation Fault. Am I using enumerate wrong?
EDIT: Nevermind, this was a stupid mistake, I was trying to access cur which is NULL after the iterations. Here is the fixed code:
struct hid_device_info* cur = hid_enumerate(0x258A, 0x1007);
struct hid_device_info* devs[10];
int i = 0;
while (cur != NULL)
{
wprintf(L"%S, %S, %d:%d, %S\n", cur->manufacturer_string, cur->product_string, cur->vendor_id, cur->product_id, cur->serial_number);
devs[i++] = cur;
cur = cur->next;
}
dev = hid_open(devs[0]->vendor_id, devs[0]->product_id, NULL);
unsigned char buf[BUFFER_SIZE];
memset(&buf, 0x0, BUFFER_SIZE);
int r = -1;
buf[0] = 4;
r = hid_get_feature_report(dev, buf, BUFFER_SIZE);
wprintf(L"Read a total of %d bytes\n", r);
The opening works but hid_get_feature_report
aborts with
T7GammingMouseTest: io.c:2146: handle_events: Assertion `ctx->pollfds_cnt >= internal_nfds' failed.
EDIT2: The same happens if I use devs[1]
I suppose it is surprising that you posted the lsusb -v
output for a device other than the mouse, especially when the HID descriptor was being discussed. But you did mention the keyboard (earlier) in that comment, so... mea culpa.
Which prints:
Game Mouse, 9610:4103, (null) Game Mouse, 9610:4103, (null)
The next step would be to check which of those accepts the report you're trying to send.
As far as I know, on Linux each HID interface is mapped to a single HID device, unlike in Windows and/or Mac, where each usage/usage page pair becomes a separate "logical HID". (I could be wrong here, someone please correct me if necessary).
This difference could also explain why the HID descriptor you posted doesn't appear to match Random06457's code; the second interface would have a different descriptor that would more closely match that code.
(The sudo lsusb -v
output for the mouse would confirm if there are indeed two interfaces).
Regardless, if I had to guess, the HID device you're interested in is probably the second one that hid_enumerate
returns, since the first one isn't working ; )
Also, you still have to add one byte to your buffer size to account for the report ID in offset 0. You probably didn't forget this, but is worth mentioning since you aren't always showing what BUFFER_SIZE
you're using.
The opening works but hid_get_feature_report aborts with
T7GammingMouseTest: io.c:2146: handle_events: Assertion `ctx->pollfds_cnt >= internal_nfds' failed.
Not sure what this assertion means, but this tells me that you're linking against libhidapi-libusb.so
. From your mention to hidraw right at the beginning, it appeared you intended to link against libhidapi-hidraw.so
.
Sorry for not showing BUFFER_SIZE, right now I have
#define BUFFER_SIZE 1024
The necessary size should be 154
but I had a large value just to be sure it wasn't a size problem. I changed to libusb to check if that was the problem. I was also advised to avoid hidraw for gaming mice and keyboards, so I might end up using libusb. But right now I just want one of them to work.
When using hidraw, this doesn't show that error, finishes successfully but still the feature read doesn't work.
By the way, enumerate was failing because I was accessing cur
which is null after the iteration, sorry, my stupid mistake. Still, enumerate reports 2 devices with the exact same vendor and product ID's and the serial number is null in both. So nothing is there to distinguish them.
It's this (null)
serial number reported by hidapi that concerns me. It reports nicely the keyboard, but the mouse is just null. I fear this might be due to the mouse being made by a shady Chinese manufacturer who didn't properly regard USB standards.
Here's a report of all devices found by hid_enumerate
:
struct hid_device_info* cur = hid_enumerate(0, 0);
int i = 0;
while (cur != NULL)
{
wprintf(L"%S, %S, %d:%d, Serial Number: %S, Path: %s\n", cur->manufacturer_string, cur->product_string, cur->vendor_id, cur->product_id, cur->serial_number, cur->path);
cur = cur->next;
}
Output:
SINOWEALTH, Game Mouse, 9610:4103, Serial Number: (null), Path: 0001:0014:00
SINOWEALTH, Game Mouse, 9610:4103, Serial Number: (null), Path: 0001:0014:01
MSI EPF USB, MSI EPF USB, 6000:65280, Serial Number: MSI EPF USB, Path: 0001:0004:00
So the mouse shows two devices but the serial number is null in both, but the path clearly indicates they are different.
OK, I used hidviz and the mouse has 2 interfaces, the first acts as the mouse and the second acts as a keyboard. Using that program, the program reads nicely all the mouse input, so I now know that Linux recognises everything properly.
This is the parsed descriptor for the Mouse Keyboard interface:
Usage Page (Generic Desktop)
Usage (Keyboard)
Collection (Application)
Report ID (1)
Usage Page (Keyboard/Keypad)
Usage Minimum (Keyboard LeftControl)
Usage Maximum (Keyboard Right GUI)
Logical minimum (0)
Logical maximum (1)
Report size (1)
Report count (8)
Item
Report count (6)
Report size (8)
Logical minimum (0)
Logical maximum (255)
Usage Page (Keyboard/Keypad)
Usage Minimum (Unknown {7:0))
Usage Maximum (Unknown {7:ff))
Item
End Collection
Usage Page (Consumer)
Usage (Consumer Control)
Collection (Application)
Report ID (2)
Logical maximum (1)
Logical minimum (0)
Report size (1)
Usage (Scan Next Track)
Usage (Scan Previous Track)
Usage (Stop)
Usage (Play/Pause)
Usage (Mute)
Usage (Daily)
Usage (Volume Increment)
Usage (Volume Decrement)
Report count (8)
Item
Usage (AL Consumer Control Configuration)
Usage (AL Local Machine Browser)
Usage (AL Spreadsheet)
Usage (AL Presentation App)
Usage (AL Email Reader)
Usage (AL Calculator)
Usage (Unknown {c:2a8))
Usage (AL Word Processor)
Report count (8)
Item
Usage (AC Normal View)
Usage (AC Scroll Up)
Usage (AC Scroll Down)
Usage (AC Scroll)
Usage (AC Pan Left)
Usage (AC Pan Right)
Usage (AC Tile Horizontally)
Usage (Keyboard Form Factor)
Report count (8)
Item
End Collection
Usage Page (Vendor-defined)
Usage (Vendor-defined {ff00:1))
Collection (Application)
Report ID (4)
Logical minimum (0)
Logical maximum (255)
Usage (Vendor-defined {ff00:0))
Report size (8)
Report count (153)
Item
End Collection
Usage Page (Vendor-defined)
Usage (Vendor-defined {ff00:1))
Collection (Application)
Report ID (6)
Logical minimum (0)
Logical maximum (255)
Usage (Vendor-defined {ff00:0))
Report size (8)
Report count (1151)
Item
End Collection
Usage Page (Vendor-defined)
Usage (Vendor-defined {ff00:1))
Collection (Application)
Report ID (5)
Logical minimum (0)
Logical maximum (255)
Usage (Vendor-defined {ff00:0))
Report count (5)
Report size (8)
Item
End Collection
So there is some hope.
You're right, a larger buffer should do no harm.
I was also advised to avoid hidraw for gaming mice and keyboards
This may be open to some debate then.
I normally view hidraw as having a few advantages over libusb, like avoiding unbinding the kernel driver. This can be particularly useful if you want your mouse to keep working while you customize it.
I think libusb should only be preferred if you need something not supported by hidraw (for example, getting an input report), or if you have reason to want to temporarily block the kernel driver. But I'm by no means an export in HID devices...
Still, enumerate reports 2 devices with the exact same vendor and product IDs and the serial number is null in both. So nothing is there to distinguish them.
You should be able to distinguish the two interfaces with cur->interface_number
.
It's this (null) serial number reported by hidapi that concerns me. [...] didn't properly regard USB standards.
As I mentioned before, a serial number is not required by the USB specification. Don't worry. Also, if present, it would still be the same for both interfaces (as it's a USB device, not interface, descriptor).
(from your edit to a previous comment)
dev = hid_open(devs[0]->vendor_id, devs[0]->product_id, NULL);
Note that you need to use hid_open_path(cur->path)
to open a specific device or interface.
hid_open
will simply always open the first device/interface that matches the USB vendor and product IDs.
I tried to hid_open_path
for the last interface.
struct hid_device_info* cur = hid_enumerate(0x258A, 0x1007);
struct hid_device_info* devs[10]; // Assumes up to 10 interfaces, I'll change later but for now it works
int i = 0;
while (cur != NULL)
{
wprintf(L"%S, %S, %d:%d, %S\n", cur->manufacturer_string, cur->product_string, cur->vendor_id, cur->product_id, cur->serial_number);
devs[i++] = cur;
cur = cur->next;
}
dev = hid_open_path(devs[1]->path);
unsigned char buf[BUFFER_SIZE];
memset(&buf, 0x0, BUFFER_SIZE);
int r = -1;
buf[0] = 4;
r = hid_get_feature_report(dev, buf, BUFFER_SIZE);
wprintf(L"Read a total of %d bytes\n", r);
It still fails with:
T7GammingMouseTest: io.c:2146: handle_events: Assertion `ctx->pollfds_cnt >= internal_nfds' failed.
Aborted
Again, no idea what that assertion means, you'd need to check the corresponding libusb source code (well, actually, the one that matches the particular version of libusb your libhidapi-libusb is linked against).
How about trying with libhidapi-hidraw?
Using hidraw terminates without error but still doesn't read any bytes from the feature report.
Ok this clearly seems like it's a libhidapi bug. I used hidviz and 2 devices are detected: a mice and a keyboard (the macro part). So it's libhidapi not recognizing my device?
Doing:
struct hid_device_info* enum_result = hid_enumerate(0x258A, 0x1007);
struct hid_device_info* cur = enum_result;
while (cur != NULL) {
wprintf(L"%S, %S, %#04x:%#04x, Serial Number: %S, Path: %s, Usage Page: %d, Usage: %d\n", cur->manufacturer_string, cur->product_string, cur->vendor_id, cur->product_id, cur->serial_number, cur->path, cur->usage_page, cur->usage);
cur = cur->next;
}
Prints:
SINOWEALTH, Game Mouse, 0x258a:0x1007, Serial Number: (null), Path: 0001:0002:00, Usage Page: 0, Usage: 0
SINOWEALTH, Game Mouse, 0x258a:0x1007, Serial Number: (null), Path: 0001:0002:01, Usage Page: 0, Usage: 0
Which doesn't seem right.
hidapi
never claimed to support Mouses/Keyboards
I used hidviz and 2 devices are detected: a mice and a keyboard
hidapi
does detect those too. What extra functionality over those devices hidviz
gives you?
Nevermind, what in the Windows C# library appears as Usage
, in hidapi
, it appears as Interface
. So, sorry it is displaying correctly (though I find quite strange hidapi
lists both interfaces as 0
, when they should clearly by different as one is a mouse and the other is a keyboard). The thing is, why does sending a feature report in hidapi
on Linux fail, when the supposedly equivalent code works on Windows? So let's forget about hidviz
, I just thought it could be an alternative since I can't get it to work with hidapi
And what do you mean by:
hidapi never claimed to support Mouses/Keyboards
Isn't hidapi
a library for USB HID devices? Aren't keyboards and mice HID devices after all? Is there something I'm not getting here? I first thought this was all failing due to my own error, but I've ran out of any options I could try. Perhaps I did miss something, but I can't really find anything I am doing wrong.
And if hidapi
is not the most adequate library for USB Gaming devices, is there any alternative? I tried to google some alternatives but I can't find anything other than hidapi
and hidraw
.
A general statement: hidapi is a library, designed to communicate with a general HID devices, as per general HID specification. hidapi never tried to fully implement HID specification itself (well, libusb kind of does it, but only the case for USB HID devices, and it is only one of possible backends), but rather tried to use OS-specific API (hidraw/WinAPI/macOS Cocoa) to access HID devices, so user can rely on (presumably well-supported) OS-based implementation, but with ability to use simple cross-platform API. (I'm starting to thing, that we need such explicit statement in our README, if it is not already there). So far, hidapi does this exact job pretty much well.
Next, HID Mouse and Keyboards: those are only a small subset of possible HID devices. And those devices are special, as they are involved in OS-enforced security. Imagine:
Because of that, Windows/macOS doesn't allow opening Mouse/Keyboard as a general HID devices for read/write. In Linux world it may be a bit different sometime, but is doesn't change the fact, that Mouse/Keyboards are special devices, and they are threated specially by the OS. Essentially, your Mouse device is already claimed by the OS, and hidapi is always a second application that tries to access this device, and it may not be able to, as it is already locked.
When user needs to access some Mouse/Keyboard-specific devices/functionality (like be notified of input events, or so), there is several better options than hidapi, e.g.: OS-specific API for Mouse/Keyboard event - its API explicitly includes all security notes, or other libraries, like Qt, where QWidget::mouseEvent allows you to be notified of Mouse events for a specific widget.
More to your problem: On Windows, the C# library you're using, opens HID device without read-write permission: https://github.com/mikeobrien/HidLibrary/blob/28ead501d4b8097549d9c41b9cdf58cbce8918be/src/HidLibrary/HidDevice.cs#L232 So does hidapi: https://github.com/libusb/hidapi/blob/cdc473dfe43f6432dda7ad53d7656b8ae8ff968b/windows/hid.c#L598 on Windows, as a fallback, because Windows/WinAPI allows it. That is a Windows specific corner case.
libusb backend doesn't give an option to open a device in any mode than read-write, which likely isn't possible for Mouse, unless you open it as root, detach kernel driver, and claim the entire device only for yourself: in such case it won't be usable as mouse anymore but hidapi surely will have full access to the device.
with hidraw backend, you may try to play with device open permissions here: https://github.com/libusb/hidapi/blob/cdc473dfe43f6432dda7ad53d7656b8ae8ff968b/linux/hid.c#L652 as the default (and required to have all the functionality) is read-write. If you can suggest a motivated fallback as a PR - please go ahead make one.
And the last, but not the least: hidapi is an Open Source project developed and supported on enthusiasm and free will. Anyone can use this project under one of several possible licenses, none of which gives you any guarantee about any of the functionality, including the documented one. Basically this means, that community (including me) would try to help you as much as we can, out of good will, but don't make any expectation that someone would solve a problem you have, for you, unless you help yourself solving it.
Thank you for the reply. I was hoping my issue was something that was easy to solve but someone who lacks much of the knowledge about USB and the whole HID subject was simply missing.
Nevertheless, I found a library that actually implements the stuff for my mouse (https://github.com/libratbag/libratbag/blob/master/src/driver-sinowealth.c). That library uses hidraw
. I still need to r
I still can't understand why some things such as https://github.com/Gibtnix/MSIKLM, which is a keyboard color manager for the MSI Steel Series keyboard that uses this exact library, works flawlessly, and my code fails. My code is probably failing due to lack of knowledge, but I really can't see what is wrong. I guess I must read more on the entire USB protocol. I really wish I could fix this myself, but I am seriously running out of ideas to try. I don't think there are much more ways of using hidapi
that I didn't try, as the api is extremely simple and compact.
Still, thank you for all the input and time spent trying to help. Might I ask you where do developers that contribute to libusb got their knowledge from? Is there any specific literature that I should read asides from the USB HID protocol documentation?
I still can't understand why some things such as https://github.com/Gibtnix/MSIKLM, which is a keyboard color manager for the MSI Steel Series keyboard that uses this exact library, works flawlessly
If I had to guess - maybe those keyboards define 2 separate HID devices: one for keyboard (that has restricted access, enforced by OS), and another one for lights controls, that can be opened by hidapi with no issues.
Nevertheless, I found a library that actually implements the stuff for my mouse (https://github.com/libratbag/libratbag/blob/master/src/driver-sinowealth.c). That library uses hidraw
It uses hidraw in a bit different way than hidapi does. The library quite sophisticated I must say, well written for its specific purpose.
Might I ask you where do developers that contribute to libusb got their knowledge from? Is there any specific literature that I should read asides from the USB HID protocol documentation?
Your question reminds me a story:
- Professor, you and you colleagues are so smart, what books do you read to gain your knowledge from?
- We don't read books, we write them.
Well, there is USB Specification / HID Specification documents (those are difficult to read, if you unexperienced to read such documents). There is OS-specific documentation, e.g. for WinAPI/HID, which could give you some idea of what is under the hood. And, of course, years of trials and errors.
After some reading and a lot of trial and error, I finally managed to succeed. Apparently, the issue is that BUFFER_SIZE
needs to be exactly 154
bytes, no more no less, (the expected size is 153
plus the report id).
This mouse acts as 2 devices (a keyboard and a mouse), the keyboard is the interface that I was concerned with. I actually managed to successfully get a feature report first using the raw hidraw
code but this library also works using the hidraw
backend.
Now it's more reverse engineering of the protocol to get more features working and structuring the program I want to use to control the mouse.
Perfect, you've figured it out!
Try if https://github.com/libusb/hidapi/commit/fb4135c7a87e87fb9f3f2fb95c3389677eb35ac9 (latest commit to master) does any better for you (it should allow you to pass smaller buffers).
I'm using hidapi on Linux through the hidraw backend to read a Gaming Mouse (I also tried with the other backend but it also doesn't work).
I want to read the device's feature data (pretty much like the
ReadFeatureData(out byte[] data, byte reportId = 0)
from this library).The only problem is, I can't. The API only returns errors upon any write/get_report. I tried the following:
Now this should work because it works on Windows using that C# library, but it doesn't work with this library. I tried both the hidraw and libusb (libusb is run as sudo) and both fail. How can I read this device's feature data without it crashing?
The C# code (using the aforementioned library) I am trying to port to C is:
This code works on Windows and returns the array properly.