device: use full live name for direct-USB codename

When a receiver-paired mouse/keyboard is plugged in directly over USB,
it has no receiver to supply a codename. If it also lacks the
DEVICE_FRIENDLY_NAME feature (0x0007), the codename property fell back
to name.split(" ")[0] — truncating a good name like "G502 X PLUS" to
"G502" at the first space.

Use the full live device name instead, only dropping a leading
"Logitech" word. The live name is always accurate to the current
connection — unlike a persisted copy, which can go stale for devices
that report mode-variant names (e.g. a headset's "- Wireless Mode" vs
"- Wired Mode"). This matches what the centurion branch already does.
This commit is contained in:
Ken Sanislo 2026-05-15 21:45:04 -07:00 committed by Peter F. Patel-Schneider
parent badce9bb07
commit a5d12f9039
2 changed files with 24 additions and 4 deletions

View File

@ -252,11 +252,14 @@ class Device:
if not self.centurion:
self._codename = _hidpp20.get_friendly_name(self)
if not self._codename and self.name:
if self.centurion:
self._codename = self.name
# Use the full live name; only drop a leading "Logitech".
# Truncating at the first space mangled good names like
# "G502 X PLUS" (direct USB connection, no friendly name).
names = self.name.split(" ")
if not self.centurion and len(names) > 1 and names[0] == "Logitech":
self._codename = " ".join(names[1:])
else:
names = self.name.split(" ")
self._codename = names[1 if len(names) > 1 and names[0] == "Logitech" else 0]
self._codename = self.name
if not self._codename and self.receiver:
codename = self.receiver.device_codename(self.number)
if codename:

View File

@ -130,6 +130,23 @@ def test_device_name(device_info, responses, expected_codename, expected_name, e
assert test_device.kind == expected_kind
def test_codename_uses_full_name():
"""A direct-connected HID++ 2.0 device with no friendly name uses its full
live name as the codename instead of truncating it at the first space."""
test_device = device.create_device(LowLevelInterfaceFake(fake_hidpp.r_empty), di_CCCC)
test_device._protocol = 2.0
test_device.online = True
test_device._codename = None
test_device._name = "G502 X PLUS"
assert test_device.codename == "G502 X PLUS"
# a leading "Logitech" is still dropped
test_device._codename = None
test_device._name = "Logitech MX Master 3"
assert test_device.codename == "MX Master 3"
@pytest.mark.parametrize(
"device_info, responses, handle, _name, _codename, number, protocol, registers",
zip(