Coder Social home page Coder Social logo

libratbag / libratbag Goto Github PK

View Code? Open in Web Editor NEW
2.0K 35.0 247.0 7.54 MB

A DBus daemon to configure input devices, mainly high-end and gaming mice

License: MIT License

Shell 1.30% C 84.04% Meson 1.52% Roff 0.49% Python 12.41% SWIG 0.25%
hacktoberfest

libratbag's People

Contributors

akstrfn avatar alcomposer avatar amfern avatar atosser avatar bentiss avatar cvuchener avatar enkore avatar ffy00 avatar hexchain avatar hjdskes avatar isantop avatar joshstrobl avatar kepstin avatar ksv1986 avatar kyokenn avatar lubasowo0 avatar lyude avatar maxice8 avatar mtayllan avatar perigoso avatar phomes avatar r3pek avatar rhermes avatar skitt avatar staticssleever668 avatar stephanlachnit avatar t-8ch avatar themarix avatar whot avatar yaneti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libratbag's Issues

Allow using ratbag-command without root

libratbag just needs access to an appropriate hidraw device, right?

If so, one could make an udev rule that adds the uaccess tag to the right hidraw device, which would make systemd-logind give access to the device to whatever user is currently logged in locally (like it does with soundcard, etc.).

I wrote a little quick rule to do this with my G300S, but I'm matching the USB ID directly:

SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c246", TAG+="uaccess"

ratbag-command seems to work without root with this rule.

I think it'd be better if it used the hwdb somehow, instead of matching one particular mouse, but I have no idea how to use hwdb.

Setting DPI for the G500s triggers assertion

I have the Logitech G500s and running the dpi set command causes an assertion error.

$ sudo tools/ratbag-command dpi set 800 /dev/input/event5
ratbag-command: libratbag.c:925: ratbag_resolution_set_dpi: Assertion `profile->device->driver->write_resolution_dpi' failed.

Add an API to switch between resolutions

Currently, libratbag only allows to change the value of a resolution within a profile. When the profile supports several resolutions that can be toggled, libratbag doesn't export the required API to change between those resolutions.

LED debugging seems buggy

in hidpp10.c, coverity complains that the 0x2 has no effect on the operation and always results in false.
Looks like we're mixing datatypes here, led is a boolean array but the hidpp10 backend wants 0x1 and 0x2 for off/on (iirc). @bentiss, most of the git blame is on you, so maybe you remember how this was supposed to work.

1526 hidpp_log_raw(&dev->base,
1527 "LED status: 1:%s 2:%s 3:%s 4:%s\n",
1528 (profile->dpi_modes[i].led[0] & 0x2) ? "on" : "off",
1529 (profile->dpi_modes[i].led[1] & 0x2) ? "on" : "off",
1530 (profile->dpi_modes[i].led[2] & 0x2) ? "on" : "off",
1531 (profile->dpi_modes[i].led[3] & 0x2) ? "on" : "off");

G302 (HID++2.0) shows strange resolution options

The G302 shows:
ratbag raw: sensor 0: current dpi: 1596 (default: 0) min: 252 max: 4032 steps: 84 ratbag debug: device is at 1596 dpi (variable between 252 and 4032).

While LGS has 48 steps from 240 - 4000.

Is this common for the mice using HID++2.0? Which range should I use for the hwdb entry?

Add Saitek R.A.T mice

Hi,
I may do this myself when I find some time to do so, but I completely reverse-engineered the USB protocol for these gaming mice (see https://github.com/MayeulC/Saitek as well as the associated wiki for code and documentation), so it should be quite easily feasible by someone else too.
I am just letting you know ;)

[hidpp10] Profile switching and pages

There are several points of which I am unsure about profiles. I think there is need for a discussion on this.

In the code, I have seen you use three profiles for the G500s. But I have only seen LGS use two: the temporary one in page 0 and a permanent one in the memory (page 2 for my G500 and I think my G500s use this one too). Actually you can write as many profiles as you can fit in memory, but they can only be switched from the driver, so it is not really useful.

The CMD_PROFILE command (0x0F), is one of the command I have documented that I least understand. It did not always behave like I intended in ways I did not manage to reproduce. I must be missing something.
But I know never found a way to get from where in the memory the current profile. I don't know how hidpp10_get_current_profile could be implemented.

About the page for the default permanent profile: I mainly tested the commands on my G500 and I quite sure it is on page 2, but I am less certain about the G500s, I will redo some tests. Or maybe there is something else that determine the location of the default profile.

Specify which actions are possible on a button per device

The G900 introduced a new special usage RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL (the one we already have in the G700(s)). This usage is only valid for wireless mice, but the current libratbag implementation does not allow us to tell which device support which special action.

We should export this capabilities to the caller so it knows which special/key/macro it can use.

(we might close this as NOT_A_BUG but we need to keep it in mind for hid++ given that we are somewhat generic for Logitech devices)

man pages use the wrong hyphens

Triggered by a47f506 which replaced the - in the man page with -
I think it's the wrong thing to do tbh. Can't see a difference in the man page but when converting to PDF, it puts a minus sign in, instead of a hyphen. Looks wrong tbh and http://man7.org/linux/man-pages/man7/groff_char.7.html says

the ISO latin1 ‘Hyphen, Minus Sign’ (code 45) prints as a hyphen; a minus sign can be obtained with ‘-’.

Given the double meaning of "-" on the terminal, "minus minus help" or "dash dash help", we shouldn't be using the explicit minus sign. Definitely not on concatenated words like ratbag-command which is now rendered as "ratbag minus command"

cc @skitt, any comments?

Dependencies

It'd be nice if there was a complete list of dependencies somewhere so I can avoid the whole build-getError-installDependency-repeat loop to find them all, especially when it complains about things like check for which it's not clear what I actually need to install...

G300s: "No supported devices found"

Hi,
these are the steps I have done:
1)
I installed libratbag from this corp:
https://copr.fedorainfracloud.org/coprs/bentiss/libratbag/
2)
Then I make sure the systemd service is enabled:
[valerio@valerio-casa ~]$ sudo systemctl status ratbagd.service
● ratbagd.service - Daemon to introspect and modify configurable mice
Loaded: loaded (/usr/lib/systemd/system/ratbagd.service; disabled; vendor preset: disabled
Active: active (running) since mar 2016-09-06 18:21:48 CEST; 2s ago
Main PID: 3284 (ratbagd)
Tasks: 1 (limit: 512)
CGroup: /system.slice/ratbagd.service
└─3284 /usr/bin/ratbagd

set 06 18:21:48 valerio-casa systemd[1]: Starting Daemon to introspect and modify configurabl
set 06 18:21:48 valerio-casa systemd[1]: Started Daemon to introspect and modify configurable
3)
Then I anplug-replug the mouse (it is a G300s).
[valerio@valerio-casa ~]$ xinput --list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ Logitech USB Keyboard id=9 [slave pointer (2)]
⎜ ↳ Logitech G300s Optical Gaming Mouse id=11 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Power Button id=7 [slave keyboard (3)]
↳ Logitech USB Keyboard id=8 [slave keyboard (3)]
↳ Logitech USB Keyboard id=12 [slave keyboard (3)]
↳ Logitech G300s Optical Gaming Mouse id=10 [slave keyboard (3)]

run the command: ratbag-command list
[valerio@valerio-casa ~]$ sudo ratbag-command list
[sudo] password for valerio:
No supported devices found

What I'm missed or what is wrong with the steps I have done?

Regards,
Valerio

[hidpp10] Memory offset size

In CMD_READ_MEMORY, you use a 16 bits offset. I am not sure what the real size offset but I don't think it makes sense. Since pages are 512 byte long, the maximum offset is 0xFF. And if you look at the parameters for the memory op command (0xA0), there is no room to have the two offsets be 16 bits with the same endianness.

Here is a test with offset 0x100 on my G500:

$ xxd -r -p <<< "10 00 83 A2 02 00 00" | src/send-raw-request /dev/hidraw1 | xxd -g 1
00000000: 11 00 83 a2 ff 00 00 80 00 11 00 11 22 11 00 22  ............".."
00000010: 00 22 22 12                                      ."".
$ xxd -r -p <<< "10 00 83 A2 02 00 01" | src/send-raw-request /dev/hidraw1 | xxd -g 1
00000000: 11 00 83 a2 ff 00 00 80 00 11 00 11 22 11 00 22  ............".."
00000010: 00 22 22 12                                      ."".
$ xxd -r -p <<< "10 00 83 A2 03 00 00" | src/send-raw-request /dev/hidraw1 | xxd -g 1
00000000: 11 00 83 a2 00 ff 00 80 00 09 00 09 22 11 00 22  ............".."
00000010: 00 22 22 1

It looks like the third byte is ignored.

Wrong button mapping for Logitech G500s

I played around with piper and noticed that some button mappings are wrong.

As you can see in the picture Button 6 and 7 are mapped as Wheel Left and Right and Button 8 and 9 for the Resolution Control. But these mappings are actually the other way round. Also shouldn't the arrows of Button 8 and 9 point left and right?

bildschirmfoto von 2016-03-10 18-38-24

LED "rate" parameter shouldn't be expressed in Hz

ratbag_led_get_effect_rate() says: The LED rate in Hz, can be 100 - 20000.

100Hz is something the eye doesn't distinguish, so 20000 is insanely more insane :)

I think the intend was to express the period in ms of the effect, not in Hz.

(opening an issue given it's public API).

Reported by @cvuchener

MX Master thumb/gesture button support

I have a Logitech MX Master. By default, the thumb button (Button 5) acts as a "gesture" button, grabbing all mouse movement events and deciding which action to take upon button release. For whatever reason, under Linux, this results in a press-release sequence of Ctrl+Alt+Tab if the mouse isn't moved before releasing, and no keys if the mouse is moved before releasing.

I ran ratbag-command info /dev/input/event0 initially, which read/wrote the following data (as reported by strace):

strace
open("/dev/hidraw1", O_RDWR)            = 3
ioctl(3, HIDIOCGRAWINFO, 0x7ffe6d093480) = 0
ioctl(3, HIDIOCGRDESCSIZE or HIDIOCGVERSION, 0x7ffe6d09240c) = 0
ioctl(3, HIDIOCGRDESC, 0x7ffe6d092410)  = 0
ioctl(3, HIDIOCGRDESCSIZE or HIDIOCGVERSION, 0x7ffe6d09240c) = 0
ioctl(3, HIDIOCGRDESC, 0x7ffe6d092410)  = 0
write(3, "\21\377\0\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\30\4\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\10\36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\3\0\2\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\35K\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\6`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\24\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\33\4\0\3\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\"\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\v\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30!\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30!!\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30e\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\301\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\23`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0300`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\220`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\23\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\221`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\24\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\241`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\25\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\300`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\26\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\35\363`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\36\0@\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\36\260`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\31\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\3`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30a`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\33\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\220\0`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\222\0`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\222@`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\2\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\35K\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\6\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\6\0102\24\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\7`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\24\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\10\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\33\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\t\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\10\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0P\0008\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0Q\0009\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0R\0:1\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0S\0<1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0V\0>1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\303\0\2511\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\304\0\2351\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\327\0\264\240\0\4\0\3\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\"\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\n\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\10\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\30\0\1\220\340\310\6@\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n(\0\3\350\3\350\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\v\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10!\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10!!\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10e\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\301\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\23\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\20`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0300\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\21`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\220\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\22`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\221\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\23`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\241\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\24`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\25`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\35\363\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\26`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\27@\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\36\260\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\30`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\31`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30a\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\32`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\220\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\33`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\34`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\222@\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\35`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\10\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\30\0\1\220\340\310\6@\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n(\0\3\350\3\350\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\10\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0P\0008\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0Q\0009\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0R\0:1\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0S\0<1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0V\0>1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\303\0\2511\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\304\0\2351\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\327\0\264\240\0\4\0\3\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20

and gave the output:

Device 'Logitech MX Master'
Capabilities: res btn-key
Number of buttons: 8
Profiles supported: 1
  Profile 0 (active)
    Resolutions:
      0: 1000dpi @ 0Hz (active)
    Button: 0 type left is mapped to 'button 1'
    Button: 1 type right is mapped to 'button 2'
    Button: 2 type middle is mapped to 'button 3'
    Button: 3 type side (backward) is mapped to 'button 4'
    Button: 4 type extra (forward) is mapped to 'button 5'
    Button: 5 type unknown is mapped to 'none'
    Button: 6 type wheel ratchet mode switch is mapped to 'UNKNOWN'
    Button: 7 type unknown is mapped to 'none'

Then I ran ratbag-command button 5 action set button 1, which returned 0.

Afterward, the thumb button doesn't do anything at all (neither interferes with mouse movement reporting like previously, nor emits any events as shown by libinput-debug-events upon press or release). I can't find any configuration that results in the thumb button actually performing user-assigned actions.

The output of running info again shows button 5 as being mapped to 'button 1'; the data from the mouse, as per strace, is below:

strace
open("/dev/hidraw1", O_RDWR)            = 3
ioctl(3, HIDIOCGRAWINFO, 0x7ffee833ab60) = 0
ioctl(3, HIDIOCGRDESCSIZE or HIDIOCGVERSION, 0x7ffee8339aec) = 0
ioctl(3, HIDIOCGRDESC, 0x7ffee8339af0)  = 0
ioctl(3, HIDIOCGRDESCSIZE or HIDIOCGVERSION, 0x7ffee8339aec) = 0
ioctl(3, HIDIOCGRDESC, 0x7ffee8339af0)  = 0
write(3, "\21\377\0\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 0 (Timeout)
read(3, "\21\1\0\30\4\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\10\36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\3\0\2\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\35K\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\6`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\24\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\33\4\0\3\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\"\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\v\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30!\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30!!\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30e\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0\301\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\23`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\0300`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\220`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\23\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\221`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\24\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\241`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\25\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\300`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\26\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\35\363`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\36\0@\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\36\260`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\31\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30\3`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\30a`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\33\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\220\0`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\222\0`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\1\30\35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\1\30\222@`\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\2\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\35K\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\6\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\6\0102\24\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\7`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\24\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\10\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\33\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\t\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\10\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0P\0008\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0Q\0009\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0R\0:1\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0S\0<1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0V\0>1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\303\0\2511\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\303\1\0P\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\304\0\2351\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\327\0\264\240\0\4\0\3\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\"\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\n\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\10\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\30\0\1\220\340\310\6@\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n(\0\3\350\3\350\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\v\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10!\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10!!\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10e\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0\301\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\23\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\20`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\0300\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\21`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\220\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\22`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\221\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\23`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\241\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\24`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\25`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\35\363\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\26`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\27@\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\36\260\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\30`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\31`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\30a\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\32`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\220\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\33`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\34`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\0\10\222@\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\0\10\35`\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\10\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n\30\0\1\220\340\310\6@\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\n(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\n(\0\3\350\3\350\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\10\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0P\0008\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0P\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0Q\0009\1\0\1\1\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0R\0:1\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0R\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\2\300\377\0\0", 20)     = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0S\0<1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\fp\376\0\0", 20)        = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0S\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\25`\375\0\0", 20)       = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0V\0>1\0\2\3\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\16\360\375\0\0", 20)    = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0V\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\4\360\376\0\0", 20)     = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\303\0\2511\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\363\37\0\0\0", 20)      = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\303\1\0P\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\357\177\0\0\0", 20)     = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\304\0\2351\0\3\7\1\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\364/\0\0\0", 20)        = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\304\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t\30\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\2\0\0\374\37\0\0\0", 20)      = 8
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t\30\0\327\0\264\240\0\4\0\3\0\0\0\0\0\0\0", 20) = 20
write(3, "\21\377\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
poll([{fd=3, events=POLLIN}], 1, 1000)  = 1 ([{fd=3, revents=POLLIN}])
read(3, "\21\1\t(\0\327\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20

I also seem unable to get the output back to what it was originally; is there any way to clear button actions or assign "none"? I don't know whether it's reasonable to expect this to reset the thumb behavior to what it does by default, but it's a reasonable configuration someone might want even if not.

In addition, I have no idea what button 7 as reported by ratbag-command info might be, and it would be nice to rename the "UNKNOWN" default action of the wheel-ratchet-mode-switch button to something like "toggle ratchet".

make install places hwdb files into lib64

make install places the following files:

$DESTDIR/usr/lib64/udev/hwdb.d/70-libratbag-mouse.hwdb
$DESTDIR/usr/lib64/udev/rules.d/70-libratbag-mouse.rules

This is incorrect and is a regression introduced by

$ git blame configure.ac
c12cb66 (Peter Hutterer 2016-03-15 09:43:49 +1000 65) UDEV_BASE_DIR="$libdir/udev"

What it should have probably be: $prefix/lib/udev or $libexecdir/udev.

G700s wrong button count

G700s while connected by cable I get

$ sudo ratbag-command list
ratbag error:     USB error: Connection timed out (110)
write: No such file or directory
/dev/input/event8:      Logitech G700s Rechargeable Gaming Mouse
$ sudo ratbag-command --verbose=raw info /dev/input/event8
ratbag debug: Logitech USB Receiver is device '/dev/hidraw0'.
ratbag debug: Logitech USB Receiver is device '/dev/hidraw1'.
ratbag debug: report ID 01
ratbag debug: report ID 03
ratbag debug: report ID 04
ratbag debug: report ID 10
ratbag debug: report ID 11
ratbag raw: hidpp write: 11 ff 00 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ratbag raw: hidpp read:  10 ff 8f 00 18 01 00
ratbag debug:     HID++ error from the device (255): ERR_INVALID_SUBID (01)
ratbag debug: Logitech USB Receiver is device '/dev/hidraw0'.
ratbag debug: Logitech USB Receiver is device '/dev/hidraw1'.
ratbag debug: report ID 01
ratbag debug: report ID 03
ratbag debug: report ID 04
ratbag debug: report ID 10
ratbag debug: report ID 11
ratbag raw: Fetching individual features
ratbag raw:   expected_header:          ?? 00 81 01
ratbag raw:   expected_error_dev:       10 00 8f 81 01 00 00
ratbag raw: hidpp write: 10 00 81 01 00 00 00
ratbag raw: hidpp read:  10 00 8f 81 01 08 00
ratbag raw:     HID++ error from the device (0): ERR_UNKNOWN_DEVICE (08)
ratbag raw: Fetching HID++ notifications
ratbag raw:   expected_header:          ?? 00 81 00
ratbag raw:   expected_error_dev:       10 00 8f 81 00 00 00
ratbag raw: hidpp write: 10 00 81 00 00 00 00
ratbag raw: hidpp read:  10 00 8f 81 00 08 00
ratbag raw:     HID++ error from the device (0): ERR_UNKNOWN_DEVICE (08)
ratbag raw: Fetching current resolution
ratbag raw:   expected_header:          ?? 00 83 63
ratbag raw:   expected_error_dev:       10 00 8f 83 63 00 00
ratbag raw: hidpp write: 10 00 83 63 00 00 00
ratbag raw: hidpp read:  10 00 8f 83 63 08 00
ratbag raw:     HID++ error from the device (0): ERR_UNKNOWN_DEVICE (08)
ratbag raw: Fetching LED status
ratbag raw:   expected_header:          ?? 00 81 51
ratbag raw:   expected_error_dev:       10 00 8f 81 51 00 00
ratbag raw: hidpp write: 10 00 81 51 00 00 00
ratbag raw: hidpp read:  10 00 8f 81 51 08 00
ratbag raw:     HID++ error from the device (0): ERR_UNKNOWN_DEVICE (08)
ratbag raw: Fetching USB refresh rate
ratbag raw:   expected_header:          ?? 00 81 64
ratbag raw:   expected_error_dev:       10 00 8f 81 64 00 00
ratbag raw: hidpp write: 10 00 81 64 00 00 00
ratbag raw: hidpp read:  10 00 8f 81 64 08 00
ratbag raw:     HID++ error from the device (0): ERR_UNKNOWN_DEVICE (08)
ratbag raw: Fetching optical sensor settings
ratbag raw:   expected_header:          ?? 00 81 61
ratbag raw:   expected_error_dev:       10 00 8f 81 61 00 00
ratbag raw: hidpp write: 10 00 81 61 00 00 00
ratbag raw: hidpp read:  10 00 8f 81 61 08 00
ratbag raw:     HID++ error from the device (0): ERR_UNKNOWN_DEVICE (08)
ratbag raw: Fetching the profiles' directory
ratbag debug: no profile type given
ratbag raw: Fetching current profile
ratbag raw:   expected_header:          ?? 00 81 0f
ratbag raw:   expected_error_dev:       10 00 8f 81 0f 00 00
ratbag raw: hidpp write: 10 00 81 0f 00 00 00
ratbag raw: hidpp read:  10 00 8f 81 0f 08 00
ratbag raw:     HID++ error from the device (0): ERR_UNKNOWN_DEVICE (08)
ratbag debug: no profile type given
ratbag debug: no profile type given
ratbag raw: Fetching profile 0
ratbag debug: no profile type given
ratbag raw: Fetching profile 0
ratbag debug: no profile type given
ratbag debug: driver match found: Logitech HID++1.0
Device 'Logitech USB Receiver'
Capabilities:
Number of buttons: 3
Profiles supported: 1
  Profile 0 (enabled) (active)
    Resolutions:
      0: <disabled>
    Button: 0 type left is mapped to 'none'
    Button: 1 type middle is mapped to 'none'
    Button: 2 type right is mapped to 'none'

(connecting wireless gives exactly the same output as in issue #92)
Did I do something wrong?

Support for G700s?

Hi everyone, awesome work! I have a Logitech G700s mouse which currently seems to be unsupported. What would be required to add support for that device type?

error message when dealing with devices with multiple event nodes

reproducer here is the G500s, symptom is that this device has two event nodes and I'm getting a "no hidraw device found" on each ratbagd start. ratbag-command list lists both event nodes as supported and both show the same info. but: ratbag_open_hidraw_node() has a check so we don't open the same hidraw node twice for two devices. It returns -ENODEV which triggers the error message.

ratbag-command list papers over this because we close the first device before we look at the second one, thus never triggering that code path.

Please allow me to use the HID++ defines

I'm using a tiny subset of hid++ in the fwupd unifying updater plugin in fwupd: https://github.com/hughsie/fwupd/blob/master/plugins/unifying/unifying-dongle.c#L34

It would be really good to either have a file we can share, or include in either build. I'm happy just merging your file into mine, but a better solution might be to have a hidpp-constants.h in libratbag that I can copy into fwupd.

One prerequisite is that the HID++ constants need a HIDPP_ prefix to avoid things like ERR_BUSY conflicting with other things in fwupd.

Comments welcome, thanks.

The active resolution cannot be retrieved for the lowest resolution on the G500s

The active resolution can only be retrieved for the middle and upper DPIs for my G500s, when I have it set to the lowest (so there's only 1 LED on indicating the DPI setting) then it fails to report the active resolution.

So this is me polling the active resolution starting at the highest DPI (all 3 LED indicators are on on the mouse) and then decreasing 1 level before running the command again and then going back up:

 ~  Projects  libratbag  sudo tools/ratbag-command resolution active get /dev/input/event5
2
 ~  Projects  libratbag  sudo tools/ratbag-command resolution active get /dev/input/event5
1
 ~  Projects  libratbag  sudo tools/ratbag-command resolution active get /dev/input/event5
Error: Failed to retrieve the active resolution
 ~  Projects  libratbag  sudo tools/ratbag-command resolution active get /dev/input/event5
1
 ~  Projects  libratbag  sudo tools/ratbag-command resolution active get /dev/input/event5
2

I tried doing a little debugging, and it looks like the problem is pretty deep. If I use gdb to look at ratbag_profile_get_resolution(), the first profile has an is_active member of false. So actually retrieving the data from the mouse is incorrect it looks like.

HID++ 2.0 is missing the button types

Extract of the G900:
Profile 4
Resolutions:
0: 400dpi @ 1000Hz
1: 800dpi @ 1000Hz (default)
2: 1600dpi @ 1000Hz
3: 3200dpi @ 1000Hz
4:
Button: 0 type unknown is mapped to 'button 1'
Button: 1 type unknown is mapped to 'button 2'
Button: 2 type unknown is mapped to 'button 3'
Button: 3 type unknown is mapped to 'button 4'
Button: 4 type unknown is mapped to 'button 5'
Button: 5 type unknown is mapped to 'button 4'
Button: 6 type unknown is mapped to 'button 5'
Button: 7 type unknown is mapped to 'resolution down'
Button: 8 type unknown is mapped to 'resolution up'
Button: 9 type unknown is mapped to 'wheel left'
Button: 10 type unknown is mapped to 'wheel right'
Button: 11 type unknown is mapped to 'profile cycle up'

Type "unknown" should be filled properly

[hidpp10] What we need to know about devices

I am trying to make a list of things we cannot guess from the HID++ 1.0 protocol only.

Needed for correctly using the mouse protocol:

  • Format/scheme for 0x63: scheme 1 and scheme 2 use the same report type, but we can guess that scheme 3 is to be used if the others fail.
  • Format for the resolution (used by 0x63 or the profile) depending on the device it can be a list (G5, G9(?)) or conversion ratio (1/50 for G500s, G700s(?) or 17/400 for G500, G9x(?))
  • Profile format: currently I know of three different formats: G9 and G500/G500s/G9x and G700s
  • Maximum profile count

Some features are present/tolerated in the protocol but don't do anything. They won't prevent the driver from successfully communicating with the mouse, but the feature will appear broken to the user.

  • Supported special functions: mapping a invalid special function to a button won't break the profile but the button won't do anything.
  • G500(s) LEDs cannot change color despite the working feature (with both register command and profile)
  • The actual number of buttons: profiles may have more buttons than physically present.
  • Maybe other features that I don't understand enough to talk about (the "angle" thing in 0x63 and the values in 0x61, ...)

"Here, picture, picture, picture" error

[Hi,]

I have installed Piper (with Libratbag & Ratbagd) on Arch, but when I run Piper I am unable save device settings onto device (but I can change device settings & I can see the current loaded presets).

I am guessing the "Here, picture, picture, picture" is an error message, but I don't quite know where to trouble shoot from here.

Any help would be most appreciated, really love Libratbag! Great project!

Cheers,
Alex

Rely on libabigail to check ABI breakages

We are currently trying to provide stable ABI in libratbag by bumping the soname when needed and properly exporting the symbols. We are not guarantee to introduce any breakage unless we rely on ABI comparison between versions.

libaigail allows to run ABI checks between .so.

It would be interesting to add such comparison in the semaphore script.

libabigail provides a tool abidiff which compares 2 .so and returns a non null value in case of an ABI failure. The 2 .so need to be compiled with debug information (DWARF style, obtained by appending "-g" to the CPPFLAGS).

We should compare the ABI to the last tagged git entry and/or to the last soname bump.

(I propose we try to integrate libabigail in our continuous integration so we can have the same type of check in libinput, libevdev, etc... )

Add support in libratbag for a subset of gaming keyboards

[CC @whot @jwrdegoede @cvuchener @phomes @tolga9009 @mbuesch @skitt @ogay @xnlcasad -- add more people if you believe they are interested in]

After a long thinking, I am finally starting to believe we should probably envision the fact of supporting keyboards too. I know we shut down the idea multiple times, and that's why I'd like to have an open discussion about it.

I am thinking of gearing myself with a G910 from Logitech and a K70 RGB from Corsair to have at least 2 vendors. @gicmo has access to a Razer Blade (not sure from how long), so this would give us 3 vendors.

To start the discussion, I think we should first do a little state of the art and define what we want to support for keyboards. I personally don't want to open too much the thing, so I would say we should not support more than what we support in mice nowadays:

  • macros
  • profiles
  • LED (w or w/o RGB) support

Devices

The 3 keyboards I am looking at are rather similar (images are not hosted here, so they may drop):

G910 keyboard:

G910

K70 RGB keyboard:

K70 RGB

Razer Blade laptop:

Razer Blade

(note that each LED can be individually lit up, even if it's not shown here).

Functionalities

Macro keys

Most mechanical keyboards have macro keys available. We currently support macro in libratbag, and for Logitech devices, the protocol is the same. So it shouldn't be much of an issue to add macro keys.

Not all keys can be mapped on all keyboards, so we might export only 5 keys for a full keyboard. It looks like the K70 can remap any key, I haven't checked on the other vendor products.

(RGB) LED individual lighting

G910 zoom
Looking at this picture, it seems that we can individually light up each key.

This should be easily doable in libratbag because the LED are exported individually.

Note that the Razer Blade Pro 2017 has a specific lighting around the touchpad:
Razer Blade Pro 2017

(RGB) LED grouped effect

We can apply a global effect to the keyboard (color wave, star light, ripple, etc...)

Not sure how to handle this, but this is something to consider.

Profiles

I think those keyboards handle profiles, so should we.

Other features we do not want to support (to be discussed)

An external LCD as a touchpad

Razer Blade Pro 2014

Yeah, we probably don't want to go there.

Others?

Existing open source projects

Corsair

https://github.com/mattanger/ckb-next

UI

I really like the design of the UI :)

Roccat

https://sourceforge.net/projects/roccat/

UI

The UI is IMO less polished than ckb-next. Still, it's there and there is existing code for it.

Razer (razercfg)

https://github.com/mbuesch/razer

razercfg

Does it support keyboards?
Edit: from @mbuesch :

I originally designed the internal APIs and structures of razercfg with the idea in mind for keyboard support to be added, but I never added an actual driver backend for any keyboard.

Razer (razer-drivers)

https://terrycain.github.io/razer-drivers/

Support different UI, for instance:

https://github.com/lah7/polychromatic
PolyChromatic

https://github.com/GabMus/razerCommander
razerCommander

https://github.com/z3ntu/RazerGenie
RazerGenie

Keyleds

https://github.com/keyleds/keyleds

Demo
It supports both compiled plugins and scripted animations (in LUA) and can react to keypresses and desktop events such as current window changing title. It does not need root access.

Logitech (g810-led)

https://github.com/MatMoul/g810-led

CLI only

Others?

Feel free to add more link to other projects

Technical discussion

Should we support keyboards in libratbag or fork the project?

Regarding forking the project, I already been suggested libwasd as for the name :)

Forking would be cleaner. But OTOH, a lot of the boilerplate is already there in libratbag, so maybe forking is not so good.

Instead of forking, should we have a middle ground?

Like having in a low level library the drivers, the protocols, and the objects. And have 2 separate libraries libratbag and libcrazykeyboard (or any other name) that are just thin wrappers around the low level one to provide the differences we want in the API (key vs button for instance).

If we add keyboards in libratbag, what are the impacts?

Differentiating mice from keyboards

From a technical point of view, nothing in libratbag express that a device is a mouse.
We have capabilities, so we could describe a mouse or a keyboard by its capabilities.

The visual is shown through SVG, so we don't need to differentiate a LED on a mouse from one on a keyboard.

However, I have a feeling we want to have a different UI for keyboards than mice, so we might need a type telling keyboard/mouse/touchpad/trackball/etc...

ratbag-command

The CLI output is going to be interesting (106 macros to redefine, the same amount of LEDs), but given ratbag-command should not be used outside from developers (hmm...) we should be able to find a way.

Redefining capabilities

We should probably group capabilities by hundreds, as in libinput:

enum libratbag_capability {
   CAP_PROFILE = 100,
   CAP_PROFILE_SWITCHABLE,
   ....
   
   CAP_RESOLUTION = 200,
   CAP_RESOLUTION_SWITCHABLE,
   CAP_RESOLUTION_SET_DEFAULT,
   ...
   
   CAP_LED = 300,
   CAP_LED_EFFECTS,
   ...
};

This will break ABI, but we don't care yet. We can just bump the soname.

Do we need to have a daemon running for the animations?

We have ratbagd, yes, but do we need to have it running for the animations of the LEDs to be working? If so, then we should probably take this into account to some level (if ratbagd is running, what happens when ratbag-command is called?)

Are non-RGB and RGB LEDs handled the same way?

Not an issue for mice, but I have no ideas for the keyboards.

We should precisely define our targets

Currently libratbag doesn't export what type of devices it supports, and which common features we want to support. This is all describe in the API, but we should probably have some central place of saying: "we can support this and this feature from this keyboard, but the rest needs to be handled in a specific project".

Discussion

feel free to add comments and concerns

Automatically detect device index for Logitech wireless devices

After a further implementation in the kernel, I understood we don't really need to store in the hwdb the device index if the device is a wireless one using a wireless receiver.

The wireless receiver still answers on device address 0xff like most wired devices. We can detect if the device is a plain mouse or a wireless receiver by checking the register 0xB5 Pairing Information. I believe non-receivers will return an error if we try to address this register.
Then, poking at each possible device index (from 1 to 6) allows to know if a device is connected to the receiver. Once we figured out which device index is in use, we can restart the probe of the hidraw node with the wireless device index.

[hidpp20] Some devices have different sector size.

The G402 has bigger sectors/pages with 1024 bytes. But libratbag uses hard-coded HIDPP20_PAGE_SIZE of 256 bytes instead of the size from hidpp20_onboard_profiles_info. Thus writing the CRC at an invalid location.

Parameters for CMD_ONBOARD_PROFILES_MEMORY_READ and CMD_ONBOARD_PROFILES_MEMORY_ADDR_WRITE need fixing for supporting bigger sector. section is actually 16 bits and in big endian in bytes 2 and 3. And bytes 4 and 5 of CMD_ONBOARD_PROFILES_MEMORY_ADDR_WRITE is the data length as 16 bits big endian (currently hard-coded to 0x0100 = 256 bytes).

I cannot test the G402 myself, it is a supposed bug. I found this from dumps from @dslul. GSeriesDev/gseries-tools#3 (comment)

G700s wireless USB not fully functional

The G700s is reporting expected results when accessing the device over its wired USB connection.

However, when trying to access it over its wireless USB receiver I am not able to retrieve information on buttons beyond left, right, and middle click. This occurs when using both ratbag-command and ratbagctl.

Sample output:

vivid@2500k:~$ sudo ratbag-command list
/dev/input/event2:  Logitech G700s Rechargeable Gaming Mouse
/dev/input/event22: Logitech USB Receiver
/dev/input/event23: Logitech USB Receiver
/dev/input/event3:  Logitech G700s Rechargeable Gaming Mouse
vivid@2500k:~$ sudo ratbag-command button count /dev/input/event3
13
vivid@2500k:~$ sudo ratbag-command button count /dev/input/event23
3
vivid@2500k:~$ ratbagctl list-devices
event23:   Logitech USB Receiver           
event3:    Logitech G700s Rechargeable Gaming Mouse
vivid@2500k:~$ ratbagctl show-button event3 0 3
Button 3 on Profile 0 on event3 (Logitech G700s Rechargeable Gaming Mouse)
           Type: thumb
    Action Type: button
 Button Mapping: 4
vivid@2500k:~$ ratbagctl show-button event23 0 3
Invalid button index 3

Errors loading Logitech G502 in Arch Linux

Hello. I'm trying to load my Logitech G502 mouse into ratbag, however I am running across issues loading the device.

For starters, Piper doesn't recognise the mouse, and when I check the device with
sudo ratbag-command list, my shell returns:
“sudo ratbag-command list” terminated by signal SIGSEGV (Address boundary error).

systemctl-status of ratbagd.service returns the following:
● ratbagd.service - Daemon to introspect and modify configurable mice
Loaded: loaded (/usr/lib/systemd/system/ratbagd.service; enabled; vendor preset: disabled)
Active: failed (Result: core-dump) since Fri 2017-03-24 16:38:22 AEDT; 20min ago
Main PID: 1881 (code=dumped, signal=SEGV)
Mar 24 16:38:22 arch-desktop-26 systemd[1]: ratbagd.service: Unit entered failed state.
Mar 24 16:38:22 arch-desktop-26 systemd[1]: ratbagd.service: Failed with result 'core-dump'.
Mar 24 16:38:22 arch-desktop-26 systemd[1]: ratbagd.service: Service hold-off time over, scheduling restart.
Mar 24 16:38:22 arch-desktop-26 systemd[1]: Stopped Daemon to introspect and modify configurable mice.
Mar 24 16:38:22 arch-desktop-26 systemd[1]: ratbagd.service: Start request repeated too quickly.
Mar 24 16:38:22 arch-desktop-26 systemd[1]: Failed to start Daemon to introspect and modify configurable mice.
Mar 24 16:38:22 arch-desktop-26 systemd[1]: ratbagd.service: Unit entered failed state.
Mar 24 16:38:22 arch-desktop-26 systemd[1]: ratbagd.service: Failed with result 'core-dump'.

sudo udevadm info /sys/class/input/eventX | grep RATBAG_DRIVER returns
Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.

Keep in mind, I installed via the AUR. I'm still not sure why the daemon is resulting in a core dump and a segmentation fault.

hidpp10: parse the profile list

It seems that page 1 consists of a list of 3-byte data. The list is terminated by two bytes of 0xFF.

Each 3 byte data is a description of a profile. The first byte is page number for the profile. I am not sure about the rest but byte 2 is always 0x00 here, and byte 3 is a number that seems unique per profile.

Here is a dump of the list from my G9 with all profiles enabled:
02 00 01
03 00 03
04 00 07
05 00 06
06 00 04
FF FF

When I disable a profile in LGS it is removed from the list in page 1.

Do we want to support enabling/disabling of profiles from libratbag?
Should ratbag-command show info for disabled profiles?

Make readme pretty and kill doxygen warning

As noted on issue #142:
/home/iliya/src/libratbag/README.md:135: warning: Unexpected html tag <img> found within <a href=...> context

The problem is that README.md is used for both the github front page, and for the docs.

I wonder if we couldn't have a simpler README.md without the doxygen tags (/*@mainpage, */), and have doxygen ignore for the semaphoreCI tag, and have a doxygen front page that just includes the content of README.md with proper doxygen marks.

This could easily be achieved by a script, but a proper doxygen include (if any) would be better.

Add a LED API

We also need an API to control the LED (because we need it).

From what I can gather from the various devices I encountered, some have very tunable LED (like the G303), others have basic functionalities (like the Etekcity). I think the common denominator is:

  • export, per profile, one LED object per LED on the device (Roccat Konw XTD has 4, G303 has 2 and pretty much the rest 1)
  • allow to change the LED color if possible (we need a capability for that)
  • allow to apply an effect on the color (or not -> only seen in the Roccat, maybe in the G303)
  • allow to turn to set the light effect:
    • on
    • off
    • hearbit
    • breathing
    • pulsing

We might not expose that many effects (breathing, heartbit, etc). The most important ones are IMO ON/OFF and the set_color so we can assign a color per profile.

Support for Func MS

Are there any interrest in the Func MS mouse series?

I managed to reverse-engineer most of the protocol for the Func MS-3, except for the macro mapping, before my mouse broke. If anyone is interested in support for the MS-2 or MS-3 I will buy a new and try porting my code.

I havn't read the whole HID++ 1/2 protocol, but it seems that it's possible to read and write individual actions and settings? For what I remember there is no way to read from a Func mouse and it is programmed with a whole profile at the time. If you want to chang the light color for profile1 you have to re-program all settings along with the newly changed color.

Export HID++ library

libratbag currently has its own HID++ handling code, which supports both the 1.0 and 2.0 versions.

We have similar code in UPower to query battery status and solar charging support:
http://cgit.freedesktop.org/upower/tree/src/linux/hidpp-device.h

And we would want to integrate unifying receiver support in GNOME directly, to allow pairing and unpairing devices:
https://bugzilla.gnome.org/show_bug.cgi?id=756574

To avoid adding external dependencies, the new library could be a cut'n'paste library, or a git submodule. The API needed would be:

  • enumerate
  • get sysfs path (to match with udev, eventually), whether device is a touchpad, keyboard, mouse, etc.
  • start pairing
  • unpair a device
  • get battery percentage, whether charging or not
  • when supported, the luminosity hitting the solar charger

Switch to meson as build system

The meson build system [1] is gaining a fair bit of traction, parts of GNOME are being switched over and we are currently discussing it for X.Org and Wayland. It'd remove automake, the big benefit is a great speedup in configure + build time (quick tests here are 20s vs 4s for a build from a fresh repo).

What's better though is that it's a lot more understandable, your average meson config makes a lot more sense than your average autotools setup.

I have a test branch that adds meson, if we're happy with this I think we should go ahead here.

[1] https://github.com/mesonbuild/meson/

Problems with forcing an active profile

For the Func mouses there is no option for reading the active profile on request. An event is given when a hardware button press cycles to the next profile, but that's it.

Currently ratbag-command doesn't accept a device with an unknown active profile. Working around this I have hardcoded profile 0 to be the active profile. As profile 0 always is the active one, I'm able to switch between profile 1 and 2, using ratbat-command profile active set 1|2, but never profile 0 as it is already active.

Would it be possible to change this, such that no profile has to be marked as active. In the case of not having an active profile it would be mandatory to specify a profile number with the command. In this case something along the lines of this would be the result:

$ ratbag-command dpi set 800
ratbag error: libratbag bug: Func Func MS-2 Gaming Mouse: missing profile id
$ ratbag-command profile 0 dpi set 800
Switched 'Func Func MS-2 Gaming Mouse' profile '0' dpi '800'

[hidpp10] G5: no event node for the configuration interface

The second interface of G5 that provide the vendor specific reports for HID++, does not have any input reports. Thus, the kernel does not create any input/event device and libratbag does not find the device.

Event devices:

$ ll /dev/input/by-id/
total 0
lrwxrwxrwx. 1 root root  9 17 sept. 09:47 usb-Chicony_Electronics_Co._Ltd_Chicony_USB_2.0_Camera-event-if00 -> ../event9
lrwxrwxrwx. 1 root root 10 17 sept. 12:07 usb-Logitech_G500_05554A4FA20018-event-mouse -> ../event13
lrwxrwxrwx. 1 root root 10 17 sept. 12:07 usb-Logitech_G500_05554A4FA20018-if01-event-kbd -> ../event14
lrwxrwxrwx. 1 root root  9 17 sept. 12:07 usb-Logitech_G500_05554A4FA20018-mouse -> ../mouse1
lrwxrwxrwx. 1 root root 10 17 sept. 12:07 usb-Logitech_USB_Gaming_Mouse-event-mouse -> ../event15
lrwxrwxrwx. 1 root root  9 17 sept. 12:07 usb-Logitech_USB_Gaming_Mouse-mouse -> ../mouse2

Logitech_USB_Gaming_Mouse is the G5, there is no event device for if01.

The report descriptor for the second interface:

06 00 FF        Usage Page (FF00 - Vendor)
09 01           Usage (0001 - Vendor)
A1 01           Collection (Application)
85 10             Report ID (16)
75 08             Report Size (8)
95 06             Report Count (6)
15 00             Logical Minimum (0)
26 FF 00          Logical Maximum (255)
09 01             Usage (0001 - Vendor)
81 00             Input ()
09 01             Usage (0001 - Vendor)
91 00             Output ()
C0              End Collection
06 00 FF        Usage Page (FF00 - Vendor)
09 02           Usage (0002 - Vendor)
A1 01           Collection (Application)
85 11             Report ID (17)
75 08             Report Size (8)
95 13             Report Count (19)
15 00             Logical Minimum (0)
26 FF 00          Logical Maximum (255)
09 02             Usage (0002 - Vendor)
81 00             Input ()
09 02             Usage (0002 - Vendor)
91 00             Output ()
C0              End Collection

Should we handle touchpads?

Side effect of 91eefb9 was that we now ignore ID_INPUT_TOUCHPAD devices in libratbag. The mouse and touchpad tags are mutually exclusive, so you only have either.

So the main question here now is: should we care about touchpad devices? Other than protocol testing there is little libratbag can do to the current generation of devices. It's useful for testing, but that's about it.

Keyboard support

Hi,

I'm the project maintainer of sidewinderd (https://github.com/tolga9009/sidewinderd) and watched this project for a while. It looks like we're trying to solve very similar problems and I wanted to ask, if there is interest in adding keyboard support.

Gaming mice and keyboards share alot of code (macros, profiles, LEDs) and this project seems to have everything important included.

Please let me know, whether there is interest, or not.

Cheers,
Tolga

USB sniffing

This is NOT an issue.

As there are no other discussion or forum options when it comes to Github, I hope you don't mind me asking questions here?

It has been a while since I last looked at the USB protocol when using a windows driver. Back then I used USBlyzer, very nice interface and easy to use. However, I'm once again limited to the 30 days trial which won't get me to the finish line. What are you using?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.