Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions inputremapper/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,10 @@ def run(self):
# device breaks autoloading. Sorting fixes it.
# With sorting, mouse1 always gets group.key "Mouse", and mouse2 always
# "Mouse 2" (Unless only mouse2 is plugged in, then it gets "Mouse")
devices = []
for path in sorted(evdev.list_devices()):
try:
device = evdev.InputDevice(path)
devices.append(evdev.InputDevice(path))
except Exception as error:
# Observed exceptions in journalctl:
# - "SystemError: <built-in function ioctl_EVIOCGVERSION> returned NULL
Expand All @@ -391,8 +392,14 @@ def run(self):
error.__class__.__name__,
str(error),
)
continue

# Sorting the devices by unique_key (which includes product/vendor/physical port topology)
# is extremely important if two identical devices are connected. Without sorting, the order
# depends on the order of plugging devices in, causing active injections to swap keys
# or break autoloading. Tying the order deterministically to physical ports/IDs fixes this.
devices.sort(key=get_unique_key)

for device in devices:
if device.name == "Power Button":
continue

Expand Down Expand Up @@ -429,16 +436,17 @@ def run(self):
'Found %s "%s" at "%s", hash "%s", key "%s"',
device_type.value,
device.name,
path,
device.path,
get_device_hash(device),
key,
)

grouped[key].append((device.name, path, device_type))
grouped[key].append((device.name, device.path, device_type))

# now write down all the paths of that group
result = []
used_keys = set()

for group in grouped.values():
names = [entry[0] for entry in group]
devs = [entry[1] for entry in group]
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def f(groups):
self.message_broker.subscribe(MessageType.groups, f)
self.message_broker.signal(MessageType.init)
self.assertEqual(
["Foo Device", "Foo Device 2", "Bar Device", "gamepad", "Qux/[Device]?"],
["Foo Device", "Foo Device 2", "Bar Device", "Qux/[Device]?", "gamepad"],
list(calls[-1].groups.keys()),
)

Expand Down
20 changes: 10 additions & 10 deletions tests/unit/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
_Group,
is_inputremapper_device,
)
from tests.lib.fixtures import fixtures, keyboard_keys, Fixture
from tests.lib.fixtures import fixtures, keyboard_keys
from tests.lib.test_setup import test_setup


Expand Down Expand Up @@ -115,6 +115,14 @@ def test_find_groups(self):
"key": "Bar Device",
}
),
json.dumps(
{
"paths": ["/dev/input/event52"],
"names": ["Qux/[Device]?"],
"types": [DeviceType.KEYBOARD],
"key": "Qux/[Device]?",
}
),
json.dumps(
{
"paths": [
Expand All @@ -129,14 +137,6 @@ def test_find_groups(self):
"key": "gamepad",
}
),
json.dumps(
{
"paths": ["/dev/input/event52"],
"names": ["Qux/[Device]?"],
"types": [DeviceType.KEYBOARD],
"key": "Qux/[Device]?",
}
),
]
)

Expand All @@ -152,8 +152,8 @@ def test_list_group_names(self):
"Foo Device",
"Foo Device",
"Bar Device",
"gamepad",
"Qux/[Device]?",
"gamepad",
],
)

Expand Down
16 changes: 8 additions & 8 deletions tests/unit/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,14 @@ def test_are_new_groups_available(self):
"key": "Bar Device",
}
),
json.dumps(
{
"paths": ["/dev/input/event52"],
"names": ["Qux/[Device]?"],
"types": [DeviceType.KEYBOARD],
"key": "Qux/[Device]?",
}
),
json.dumps(
{
"paths": [
Expand All @@ -930,14 +938,6 @@ def test_are_new_groups_available(self):
"key": "gamepad",
}
),
json.dumps(
{
"paths": ["/dev/input/event52"],
"names": ["Qux/[Device]?"],
"types": [DeviceType.KEYBOARD],
"key": "Qux/[Device]?",
}
),
]
),
)
Expand Down
Loading