Repository: pwr-Solaar/Solaar

Issue:
Add G512 keyboard and G402 mouse
**Information**
I am on a clean arch install and installed solaar, but it fails to either of my devices (A g512 Keyboard and a g402 mouse).
- Solaar version: `solaar 1.1.1` 
- Distribution: Arch Linux
- Kernel version: `Linux 5.15.11-arch2-1 x86_64 GNU/Linux`
- Output of `solaar show`:

<details>

```
solaar: error: Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/solaar/cli/__init__.py", line 200, in run
    raise Exception('No devices found')
Exception: No devices found

```
</details>

**Describe the bug**
I have the following devices connected, 
```
$ lsusb | grep Logitech
Bus 001 Device 008: ID 046d:c33c Logitech, Inc. G512 RGB MECHANICAL GAMING KEYBOARD
Bus 001 Device 010: ID 046d:c07e Logitech, Inc. G402 Gaming Mouse
```

But solaar still throws an error that no devices were found. I installed solaar via `yay` and am unsure if there are extra requirements






Discussion:
I would expect these devices to work, but maybe they use a different USB interface ID than Solaar expects.  

But first, check whether permissions have been set up correctly by running `ls -l /dev/hidraw*`.  You should see a `+` after the permisisons bits in at least two of the lines.  If not, the udev rule is not working correctly.

If that is not the problem, run `solaar -dd show` and post the output.

Resolving patch:
diff --git a/lib/logitech_receiver/descriptors.py b/lib/logitech_receiver/descriptors.py
--- a/lib/logitech_receiver/descriptors.py
+++ b/lib/logitech_receiver/descriptors.py
@@ -191,115 +191,19 @@ def get_btid(btid):
 # devices may only have register-based settings; HID++ 2.0 devices may only have
 # feature-based settings.
 
-# Keyboards
+# Devices are organized by kind
+# Within kind devices are sorted by wpid, then by usbid, then by btid, with missing values sorted later
 
-_D('Wireless Keyboard K230', protocol=2.0, wpid='400D')
-_D('Wireless Keyboard K270(unifying)', protocol=2.0, wpid='4003')
-_D(
-    'Wireless Keyboard MK270',
-    protocol=2.0,
-    wpid='4023',
-    settings=[_FS.fn_swap()],
-)
-_D(
-    'Wireless Keyboard K270',
-    protocol=1.0,
-    registers=(_R.battery_status, ),
-)
-_D(
-    'Wireless Keyboard MK300',
-    protocol=1.0,
-    wpid='0068',
-    registers=(_R.battery_status, ),
-)
+# Keyboards
 
-_D(
-    'Wireless Keyboard MK320',
-    protocol=1.0,
-    wpid='200F',
-    registers=(_R.battery_status, ),
-)
-_D('Wireless Keyboard MK330')
-_D(
-    'Wireless Compact Keyboard K340',
-    protocol=1.0,
-    wpid='2007',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'Wireless Wave Keyboard K350',
-    protocol=1.0,
-    wpid='200A',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'Wireless Keyboard K360',
-    protocol=2.0,
-    wpid='4004',
-    settings=[_FS.fn_swap()],
-)
-_D(
-    'Wireless Keyboard K375s',
-    protocol=2.0,
-    wpid='4061',
-    settings=[_FS.k375s_fn_swap()],
-)
-_D(
-    'Wireless Touch Keyboard K400',
-    protocol=2.0,
-    wpid=('400E', '4024'),
-    settings=[_FS.fn_swap()],
-)
-_D(
-    'Wireless Touch Keyboard K400 Plus',
-    codename='K400 Plus',
-    protocol=2.0,
-    wpid='404D',
-    settings=[
-        _FS.new_fn_swap(),
-        _FS.reprogrammable_keys(),
-        _FS.disable_keyboard_keys(),
-        _FS.gesture2_gestures(),
-        _FS.gesture2_params(),
-    ],
-)
-_D(
-    'Wireless Keyboard K520',
-    protocol=1.0,
-    wpid='2011',
-    registers=(_R.battery_status, ),
-    settings=[
-        _RS.fn_swap(),
-    ],
-)
-_D(
-    'Number Pad N545',
-    protocol=1.0,
-    wpid='2006',
-    registers=(_R.battery_status, ),
-)
-_D('Wireless Keyboard MK550')
-_D(
-    'Wireless Keyboard MK700',
-    protocol=1.0,
-    wpid='2008',
-    registers=(_R.battery_status, ),
-    settings=[
-        _RS.fn_swap(),
-    ],
-)
-_D(
-    'Wireless Solar Keyboard K750',
-    protocol=2.0,
-    wpid='4002',
-    settings=[_FS.fn_swap()],
-)
-_D(
-    'Wireless Multi-Device Keyboard K780',
-    protocol=4.5,
-    wpid='405B',
-    settings=[_FS.new_fn_swap()],
-)
+_D('Wireless Keyboard S510', codename='S510', protocol=1.0, wpid='0056', registers=(_R.battery_status, ))
+_D('Wireless Keyboard EX100', codename='EX100', protocol=1.0, wpid='0065', registers=(_R.battery_status, ))
+_D('Wireless Keyboard MK300', protocol=1.0, wpid='0068', registers=(_R.battery_status, ))
+_D('Number Pad N545', protocol=1.0, wpid='2006', registers=(_R.battery_status, ))
+_D('Wireless Compact Keyboard K340', protocol=1.0, wpid='2007', registers=(_R.battery_status, ))
+_D('Wireless Keyboard MK700', protocol=1.0, wpid='2008', registers=(_R.battery_status, ), settings=[_RS.fn_swap()])
+_D('Wireless Wave Keyboard K350', protocol=1.0, wpid='200A', registers=(_R.battery_status, ))
+_D('Wireless Keyboard MK320', protocol=1.0, wpid='200F', registers=(_R.battery_status, ))
 _D(
     'Wireless Illuminated Keyboard K800',
     protocol=1.0,
@@ -313,105 +217,65 @@ def get_btid(btid):
         _RS.hand_detection(),
     ],
 )
-_D(
-    'Wireless Illuminated Keyboard K800 new',
-    codename='K800 new',
-    protocol=4.5,
-    wpid='406E',
-    settings=[_FS.fn_swap()],
-)
-_D(
-    'Illuminated Living-Room Keyboard K830',
-    protocol=2.0,
-    wpid='4032',
-    settings=[_FS.new_fn_swap()],
-)
+_D('Wireless Keyboard K520', protocol=1.0, wpid='2011', registers=(_R.battery_status, ), settings=[_RS.fn_swap()])
+_D('Wireless Solar Keyboard K750', protocol=2.0, wpid='4002', settings=[_FS.fn_swap()])
+_D('Wireless Keyboard K270 (unifying)', protocol=2.0, wpid='4003')
+_D('Wireless Keyboard K360', protocol=2.0, wpid='4004', settings=[_FS.fn_swap()])
+_D('Wireless Keyboard K230', protocol=2.0, wpid='400D')
+_D('Wireless Touch Keyboard K400', protocol=2.0, wpid=('400E', '4024'), settings=[_FS.fn_swap()])
+_D('Wireless Keyboard MK270', protocol=2.0, wpid='4023', settings=[_FS.fn_swap()])
+_D('Illuminated Living-Room Keyboard K830', protocol=2.0, wpid='4032', settings=[_FS.new_fn_swap()])
+_D('Wireless Touch Keyboard K400 Plus', codename='K400 Plus', protocol=2.0, wpid='404D')
+_D('Wireless Multi-Device Keyboard K780', protocol=4.5, wpid='405B', settings=[_FS.new_fn_swap()])
+_D('Wireless Keyboard K375s', protocol=2.0, wpid='4061', settings=[_FS.k375s_fn_swap()])
 _D('Craft Advanced Keyboard', codename='Craft', protocol=4.5, wpid='4066', btid=0xB350)
+_D('Wireless Illuminated Keyboard K800 new', codename='K800 new', protocol=4.5, wpid='406E', settings=[_FS.fn_swap()])
 _D('MX Keys Keyboard', codename='MX Keys', protocol=4.5, wpid='408A', btid=0xB35B)
-_D(
-    'Wireless Keyboard S510',
-    codename='S510',
-    protocol=1.0,
-    wpid='0056',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'Wireless Keyboard EX100',
-    codename='EX100',
-    protocol=1.0,
-    wpid='0065',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard',
-    codename='G915 TKL',
-    protocol=4.2,
-    wpid='408E',
-    usbid=0xC343,
-)
+_D('G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard', codename='G915 TKL', protocol=4.2, wpid='408E', usbid=0xC343)
+_D('G512 RGB Mechanical Gaming Keyboard', codename='G512', usbid=0xc33c, interface=1)
 
 # Mice
 
-_D('Wireless Mouse M150', protocol=2.0, wpid='4022')
-_D('Wireless Mouse M175', protocol=2.0, wpid='4008')
-_D(
-    'Wireless Mouse M185 new',
-    codename='M185n',
-    protocol=4.5,
-    wpid='4054',
-    settings=[
-        _FS.lowres_smooth_scroll(),
-        _FS.pointer_speed(),
-    ]
-)
-# Apparently Logitech uses wpid 4055 for three different mice
-# That's not so strange, as M185 is used on both Unifying-ready and non-Unifying-ready mice
+_D('LX5 Cordless Mouse', codename='LX5', protocol=1.0, wpid='0036', registers=(_R.battery_status, ))
+_D('Wireless Mouse EX100', codename='EX100m', protocol=1.0, wpid='003F', registers=(_R.battery_status, ))
+_D('Wireless Mouse M30', codename='M30', protocol=1.0, wpid='0085', registers=(_R.battery_status, ))
+_D('MX610 Laser Cordless Mouse', codename='MX610', protocol=1.0, wpid='1001', registers=(_R.battery_status, ))
+_D('G7 Cordless Laser Mouse', codename='G7', protocol=1.0, wpid='1002', registers=(_R.battery_status, ))
+_D('V400 Laser Cordless Mouse', codename='V400', protocol=1.0, wpid='1003', registers=(_R.battery_status, ))
+_D('MX610 Left-Handled Mouse', codename='MX610L', protocol=1.0, wpid='1004', registers=(_R.battery_status, ))
+_D('V450 Laser Cordless Mouse', codename='V450', protocol=1.0, wpid='1005', registers=(_R.battery_status, ))
 _D(
-    'Wireless Mouse M185/M235/M310',
-    codename='M185/M235/M310',
-    protocol=4.5,
-    wpid='4055',
-    settings=[
-        _FS.lowres_smooth_scroll(),
-        _FS.pointer_speed(),
-    ]
-)
-_D('Wireless Mouse M185', protocol=2.0, wpid='4038')
-_D('Wireless Mouse M187', protocol=2.0, wpid='4019')
-_D('Wireless Mouse M215', protocol=1.0, wpid='1020')
-_D(
-    'Wireless Mouse M305',
+    'VX Revolution',
+    codename='VX Revolution',
+    kind=_DK.mouse,
     protocol=1.0,
-    wpid='101F',
-    registers=(_R.battery_status, ),
-    settings=[
-        _RS.side_scroll(),
-    ],
+    wpid=('1006', '100D', '0612'),
+    registers=(_R.battery_charge, )
 )
+_D('MX Air', codename='MX Air', protocol=1.0, kind=_DK.mouse, wpid=('1007', '100E'), registers=(_R.battery_charge, ))
 _D(
-    'Wireless Mouse M310',
+    'MX Revolution',
+    codename='MX Revolution',
     protocol=1.0,
-    wpid='1024',
-    registers=(_R.battery_status, ),
+    kind=_DK.mouse,
+    wpid=('1008', '100C'),
+    registers=(_R.battery_charge, )
 )
-_D('Wireless Mouse M315')
-_D('Wireless Mouse M317')
-_D('Wireless Mouse M325', protocol=2.0, wpid='400A', settings=[
-    _FS.hi_res_scroll(),
-])
-_D('Wireless Mouse M345', protocol=2.0, wpid='4017')
+_D('MX620 Laser Cordless Mouse', codename='MX620', protocol=1.0, wpid=('100A', '1016'), registers=(_R.battery_charge, ))
 _D(
-    'Wireless Mouse M350',
+    'VX Nano Cordless Laser Mouse',
+    codename='VX Nano',
     protocol=1.0,
-    wpid='101C',
+    wpid=('100B', '100F'),
     registers=(_R.battery_charge, ),
+    settings=[_RS.smooth_scroll(), _RS.side_scroll()]
 )
-_D('Wireless Mouse Pebble M350', codename='Pebble', protocol=2.0, wpid='4080')
+_D('V450 Nano Cordless Laser Mouse', codename='V450 Nano', protocol=1.0, wpid='1011', registers=(_R.battery_charge, ))
 _D(
-    'Wireless Mouse M505',
-    codename='M505/B605',
+    'V550 Nano Cordless Laser Mouse',
+    codename='V550 Nano',
     protocol=1.0,
-    wpid='101D',
+    wpid='1013',
     registers=(_R.battery_charge, ),
     settings=[
         _RS.smooth_scroll(),
@@ -419,56 +283,17 @@ def get_btid(btid):
     ],
 )
 _D(
-    'Wireless Mouse M510',
-    protocol=1.0,
-    wpid='1025',
-    registers=(_R.battery_status, ),
-    settings=[
-        # _RS.smooth_scroll(),	# writing the bit to the register doesn't cause an error, but the bit doesn't turn on
-        _RS.side_scroll(),
-    ],
-)
-_D('Wireless Mouse M510', codename='M510v2', protocol=2.0, wpid='4051', settings=[
-    _FS.lowres_smooth_scroll(),
-])
-_D('Couch Mouse M515', protocol=2.0, wpid='4007')
-_D('Wireless Mouse M525', protocol=2.0, wpid='4013')
-_D(
-    'Multi Device Silent Mouse M585/M590',
-    codename='M585/M590',
-    protocol=4.5,
-    wpid='406B',
-    settings=[
-        _FS.lowres_smooth_scroll(),
-        _FS.pointer_speed(),
-    ],
-)
-_D('Touch Mouse M600', protocol=2.0, wpid='401A')
-_D(
-    'Marathon Mouse M705 (M-R0009)',
-    codename='M705 (M-R0009)',
+    'MX 1100 Cordless Laser Mouse',
+    codename='MX 1100',
     protocol=1.0,
-    wpid='101B',
+    kind=_DK.mouse,
+    wpid='1014',
     registers=(_R.battery_charge, ),
     settings=[
         _RS.smooth_scroll(),
         _RS.side_scroll(),
     ],
 )
-_D(
-    'Marathon Mouse M705 (M-R0073)',
-    codename='M705 (M-R0073)',
-    protocol=4.5,
-    wpid='406D',
-    settings=[
-        _FS.hires_smooth_invert(),
-        #        _FS.hires_smooth_resolution(),
-        _FS.pointer_speed(),
-    ]
-)
-_D('Zone Touch Mouse T400')
-_D('Touch Mouse T620', protocol=2.0)
-_D('Logitech Cube', kind=_DK.mouse, protocol=2.0)
 _D(
     'Anywhere Mouse MX',
     codename='Anywhere MX',
@@ -480,16 +305,6 @@ def get_btid(btid):
         _RS.side_scroll(),
     ],
 )
-_D(
-    'Anywhere Mouse MX 2',
-    codename='Anywhere MX 2',
-    protocol=4.5,
-    wpid='404A',
-    settings=[
-        _FS.hires_smooth_invert(),
-        #        _FS.hires_smooth_resolution(),
-    ],
-)
 _D(
     'Performance Mouse MX',
     codename='Performance MX',
@@ -505,43 +320,31 @@ def get_btid(btid):
         _RS.side_scroll(),
     ],
 )
-
 _D(
-    'Wireless Mouse MX Master',
-    codename='MX Master',
-    protocol=4.5,
-    wpid='4041',
-    btid=0xb012,
+    'Marathon Mouse M705 (M-R0009)',
+    codename='M705 (M-R0009)',
+    protocol=1.0,
+    wpid='101B',
+    registers=(_R.battery_charge, ),
     settings=[
-        _FS.hires_smooth_invert(),
-        #        _FS.hires_smooth_resolution(),
+        _RS.smooth_scroll(),
+        _RS.side_scroll(),
     ],
 )
-
+_D('Wireless Mouse M350', protocol=1.0, wpid='101C', registers=(_R.battery_charge, ))
 _D(
-    'Wireless Mouse MX Master 2S',
-    codename='MX Master 2S',
-    protocol=4.5,
-    wpid='4069',
-    btid=0xb019,
+    'Wireless Mouse M505',
+    codename='M505/B605',
+    protocol=1.0,
+    wpid='101D',
+    registers=(_R.battery_charge, ),
     settings=[
-        _FS.hires_smooth_invert(),
-        #        _FS.hires_smooth_resolution(),
-        _FS.gesture2_gestures(),
+        _RS.smooth_scroll(),
+        _RS.side_scroll(),
     ],
 )
-
-_D('MX Master 3 Wireless Mouse', codename='MX Master 3', protocol=4.5, wpid='4082', btid=0xb023)
-
-_D('MX Vertical Wireless Mouse', codename='MX Vertical', protocol=4.5, wpid='407B', btid=0xb020, usbid=0xc08a)
-
-_D(
-    'G7 Cordless Laser Mouse',
-    codename='G7',
-    protocol=1.0,
-    wpid='1002',
-    registers=(_R.battery_status, ),
-)
+_D('Wireless Mouse M305', protocol=1.0, wpid='101F', registers=(_R.battery_status, ), settings=[_RS.side_scroll()])
+_D('Wireless Mouse M215', protocol=1.0, wpid='1020')
 _D(
     'G700 Gaming Mouse',
     codename='G700',
@@ -558,6 +361,9 @@ def get_btid(btid):
         _RS.side_scroll(),
     ],
 )
+_D('Wireless Mouse M310', protocol=1.0, wpid='1024', registers=(_R.battery_status, ))
+_D('Wireless Mouse M510', protocol=1.0, wpid='1025', registers=(_R.battery_status, ), settings=[_RS.side_scroll()])
+_D('Fujitsu Sonic Mouse', codename='Sonic', protocol=1.0, wpid='1029')
 _D(
     'G700s Gaming Mouse',
     codename='G700s',
@@ -575,178 +381,94 @@ def get_btid(btid):
     ],
 )
 
-_D('G102 Lightsync Mouse', codename='G102', usbid=0xc092, interface=1)
-_D('G403 Gaming Mouse', codename='G403', usbid=0xc082)
-_D('G502 Hero Gaming Mouse', codename='G502 Hero', usbid=0xc08d)
-_D('G703 Lightspeed Gaming Mouse', codename='G703', usbid=0xc087)
-_D('G703 Hero Gaming Mouse', codename='G703 Hero', usbid=0xc090)
-_D('G900 Chaos Spectrum Gaming Mouse', codename='G900', usbid=0xc081)
-_D('G903 Lightspeed Gaming Mouse', codename='G903', usbid=0xc086)
-_D('G903 Hero Gaming Mouse', codename='G903 Hero', usbid=0xc091)
-_D('GPro Gaming Mouse', codename='GPro', usbid=0xc088)
-_D(
-    'PRO X Wireless',
-    kind='mouse',
-    codename='PRO X',
-    protocol=4.2,
-    wpid='4093',
-    usbid=0xc094,
-)
-
-_D('M500S Mouse', codename='M500S', usbid=0xc093, interface=1)
-
-_D(
-    'LX5 Cordless Mouse',
-    codename='LX5',
-    protocol=1.0,
-    wpid='0036',
-    registers=(_R.battery_status, ),
-)
+_D('Couch Mouse M515', protocol=2.0, wpid='4007')
+_D('Wireless Mouse M175', protocol=2.0, wpid='4008')
+_D('Wireless Mouse M325', protocol=2.0, wpid='400A', settings=[_FS.hi_res_scroll()])
+_D('Wireless Mouse M525', protocol=2.0, wpid='4013')
+_D('Wireless Mouse M345', protocol=2.0, wpid='4017')
+_D('Wireless Mouse M187', protocol=2.0, wpid='4019')
+_D('Touch Mouse M600', protocol=2.0, wpid='401A')
+_D('Wireless Mouse M150', protocol=2.0, wpid='4022')
+_D('Wireless Mouse M185', protocol=2.0, wpid='4038')
+_D('Wireless Mouse MX Master', codename='MX Master', protocol=4.5, wpid='4041', btid=0xb012)
+_D('Anywhere Mouse MX 2', codename='Anywhere MX 2', protocol=4.5, wpid='404A', settings=[_FS.hires_smooth_invert()])
+_D('Wireless Mouse M510', protocol=2.0, wpid='4051', codename='M510v2', settings=[_FS.lowres_smooth_scroll()])
 _D(
-    'Wireless Mouse M30',
-    codename='M30',
-    protocol=1.0,
-    wpid='0085',
-    registers=(_R.battery_status, ),
+    'Wireless Mouse M185 new',
+    codename='M185n',
+    protocol=4.5,
+    wpid='4054',
+    settings=[
+        _FS.lowres_smooth_scroll(),
+        _FS.pointer_speed(),
+    ]
 )
 _D(
-    'Wireless Mouse EX100',
-    codename='EX100m',
-    protocol=1.0,
-    wpid='003F',
-    registers=(_R.battery_status, ),
-    # settings=[ _RS.smooth_scroll(), ], # command accepted, but no change in whell action
+    'Wireless Mouse M185/M235/M310',
+    codename='M185/M235/M310',
+    protocol=4.5,
+    wpid='4055',
+    settings=[
+        _FS.lowres_smooth_scroll(),
+        _FS.pointer_speed(),
+    ]
 )
-
-# Trackballs
-
-_D('Wireless Trackball M570')
-
-# Touchpads
-
-_D('Wireless Rechargeable Touchpad T650', protocol=2.0, wpid='4101')
-_D('Wireless Touchpad', codename='Wireless Touch', protocol=2.0, wpid='4011')
-
-#
-# Classic Nano peripherals (that don't support the Unifying protocol).
-# A wpid is necessary to properly identify them.
-#
-
 _D(
-    'VX Nano Cordless Laser Mouse',
-    codename='VX Nano',
-    protocol=1.0,
-    wpid=('100B', '100F'),
-    registers=(_R.battery_charge, ),
+    'Wireless Mouse MX Master 2S',
+    codename='MX Master 2S',
+    protocol=4.5,
+    wpid='4069',
+    btid=0xb019,
     settings=[
-        _RS.smooth_scroll(),
-        _RS.side_scroll(),
+        _FS.hires_smooth_invert(),
+        _FS.gesture2_gestures(),
     ],
 )
 _D(
-    'V450 Nano Cordless Laser Mouse',
-    codename='V450 Nano',
-    protocol=1.0,
-    wpid='1011',
-    registers=(_R.battery_charge, ),
-)
-_D(
-    'V550 Nano Cordless Laser Mouse',
-    codename='V550 Nano',
-    protocol=1.0,
-    wpid='1013',
-    registers=(_R.battery_charge, ),
+    'Multi Device Silent Mouse M585/M590',
+    codename='M585/M590',
+    protocol=4.5,
+    wpid='406B',
     settings=[
-        _RS.smooth_scroll(),
-        _RS.side_scroll(),
+        _FS.lowres_smooth_scroll(),
+        _FS.pointer_speed(),
     ],
 )
-
-# Mini receiver mice
-
-_D(
-    'MX610 Laser Cordless Mouse',
-    codename='MX610',
-    protocol=1.0,
-    wpid='1001',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'MX620 Laser Cordless Mouse',
-    codename='MX620',
-    protocol=1.0,
-    wpid=('100A', '1016'),
-    registers=(_R.battery_charge, ),
-)
-_D(
-    'MX610 Left-Handled Mouse',
-    codename='MX610L',
-    protocol=1.0,
-    wpid='1004',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'V400 Laser Cordless Mouse',
-    codename='V400',
-    protocol=1.0,
-    wpid='1003',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'V450 Laser Cordless Mouse',
-    codename='V450',
-    protocol=1.0,
-    wpid='1005',
-    registers=(_R.battery_status, ),
-)
-_D(
-    'VX Revolution',
-    codename='VX Revolution',
-    kind=_DK.mouse,
-    protocol=1.0,
-    wpid=('1006', '100D', '0612'),  # WPID 0612 from Issue #921
-    registers=(_R.battery_charge, ),
-)
 _D(
-    'MX Air',
-    codename='MX Air',
-    protocol=1.0,
-    kind=_DK.mouse,
-    wpid=('1007', '100E'),
-    registers=(_R.battery_charge, ),
-)
-_D(
-    'MX Revolution',
-    codename='MX Revolution',
-    protocol=1.0,
-    kind=_DK.mouse,
-    wpid=('1008', '100C'),
-    registers=(_R.battery_charge, ),
-)
-_D(
-    'MX 1100 Cordless Laser Mouse',
-    codename='MX 1100',
-    protocol=1.0,
-    kind=_DK.mouse,
-    wpid='1014',
-    registers=(_R.battery_charge, ),
+    'Marathon Mouse M705 (M-R0073)',
+    codename='M705 (M-R0073)',
+    protocol=4.5,
+    wpid='406D',
     settings=[
-        _RS.smooth_scroll(),
-        _RS.side_scroll(),
-    ],
+        _FS.hires_smooth_invert(),
+        _FS.pointer_speed(),
+    ]
 )
+_D('MX Vertical Wireless Mouse', codename='MX Vertical', protocol=4.5, wpid='407B', btid=0xb020, usbid=0xc08a)
+_D('Wireless Mouse Pebble M350', protocol=2.0, wpid='4080', codename='Pebble')
+_D('MX Master 3 Wireless Mouse', codename='MX Master 3', protocol=4.5, wpid='4082', btid=0xb023)
+_D('PRO X Wireless', kind='mouse', codename='PRO X', wpid='4093', usbid=0xc094)
+_D('G402 Gaming Mouse', codename='G402', usbid=0xc07e, interface=1)
+_D('G900 Chaos Spectrum Gaming Mouse', codename='G900', usbid=0xc081)
+_D('G403 Gaming Mouse', codename='G403', usbid=0xc082)
+_D('G903 Lightspeed Gaming Mouse', codename='G903', usbid=0xc086)
+_D('G703 Lightspeed Gaming Mouse', codename='G703', usbid=0xc087)
+_D('GPro Gaming Mouse', codename='GPro', usbid=0xc088)
+_D('G502 Hero Gaming Mouse', codename='G502 Hero', usbid=0xc08d)
+_D('G703 Hero Gaming Mouse', codename='G703 Hero', usbid=0xc090)
+_D('G903 Hero Gaming Mouse', codename='G903 Hero', usbid=0xc091)
+_D('G102 Lightsync Mouse', codename='G102', usbid=0xc092, interface=1)
+_D('M500S Mouse', codename='M500S', usbid=0xc093, interface=1)
 
-# Some exotics...
+# Trackballs
 
-_D('Fujitsu Sonic Mouse', codename='Sonic', protocol=1.0, wpid='1029')
+_D('Wireless Trackball M570')
+
+# Touchpads
+
+_D('Wireless Touchpad', codename='Wireless Touch', protocol=2.0, wpid='4011')
+_D('Wireless Rechargeable Touchpad T650', protocol=2.0, wpid='4101')
 
 # Headset
 
-_D(
-    'Logitech PRO X Wireless Gaming Headset',
-    codename='PRO Wireless Headset',
-    protocol=2.0,
-    interface=3,
-    kind=_DK.headset,
-    usbid=0x0aba
-)
+_D('Logitech PRO X Wireless Gaming Headset', codename='PRO Headset', protocol=2.0, interface=3, kind=_DK.headset, usbid=0x0aba)


Test patch: