diff --git a/keymapper/injector.py b/keymapper/injector.py index 6578da6a..77adc5a6 100644 --- a/keymapper/injector.py +++ b/keymapper/injector.py @@ -75,8 +75,9 @@ def _modify_capabilities(device): # to act like the device. capabilities = device.capabilities(absinfo=False) # However, make sure that it supports all keycodes, not just some - # random ones. That's why I avoid from_device for this - capabilities[evdev.ecodes.EV_KEY] = evdev.ecodes.keys.keys() + # random ones, because the mapping could contain anything. + # That's why I avoid from_device for this + capabilities[evdev.ecodes.EV_KEY] = list(evdev.ecodes.keys.keys()) # just like what python-evdev does in from_device if evdev.ecodes.EV_SYN in capabilities: diff --git a/tests/test.py b/tests/test.py index 6388ef64..927008c9 100644 --- a/tests/test.py +++ b/tests/test.py @@ -24,6 +24,9 @@ import sys import unittest + +import evdev + from keymapper.logger import update_verbosity @@ -31,6 +34,54 @@ tmp = '/tmp/key-mapper-test' uinput_write_history = [] pending_events = {} +# key-mapper is only interested in devices that have EV_KEY, add some +# random other stuff to test that they are ignored. +fixtures = { + # device 1 + '/dev/input/event11': { + 'capabilities': {evdev.ecodes.EV_KEY: [], evdev.ecodes.EV_ABS: []}, + 'phys': 'usb-0000:03:00.0-1/input2', + 'name': 'device 1 foo' + }, + '/dev/input/event10': { + 'capabilities': {evdev.ecodes.EV_KEY: []}, + 'phys': 'usb-0000:03:00.0-1/input3', + 'name': 'device 1' + }, + '/dev/input/event13': { + 'capabilities': {evdev.ecodes.EV_KEY: [], evdev.ecodes.EV_SYN: []}, + 'phys': 'usb-0000:03:00.0-1/input1', + 'name': 'device 1' + }, + '/dev/input/event14': { + 'capabilities': {evdev.ecodes.EV_SYN: []}, + 'phys': 'usb-0000:03:00.0-1/input0', + 'name': 'device 1 qux' + }, + + # device 2 + '/dev/input/event20': { + 'capabilities': {evdev.ecodes.EV_KEY: []}, + 'phys': 'usb-0000:03:00.0-2/input1', + 'name': 'device 2' + }, + + # something that is completely ignored + '/dev/input/event30': { + 'capabilities': {evdev.ecodes.EV_SYN: []}, + 'phys': 'usb-0000:03:00.0-3/input1', + 'name': 'device 3' + }, + + # key-mapper devices are also ignored, another instance of key-mapper + # started injecting apparently. + '/dev/input/event40': { + 'capabilities': {evdev.ecodes.EV_KEY: []}, + 'phys': 'key-mapper/input1', + 'name': 'key-mapper device 2' + }, +} + def get_events(): """Get all events written by the injector.""" @@ -75,55 +126,6 @@ def patch_paths(): def patch_evdev(): - import evdev - # key-mapper is only interested in devices that have EV_KEY, add some - # random other stuff to test that they are ignored. - fixtures = { - # device 1 - '/dev/input/event11': { - 'capabilities': {evdev.ecodes.EV_KEY: [], evdev.ecodes.EV_ABS: []}, - 'phys': 'usb-0000:03:00.0-1/input2', - 'name': 'device 1 foo' - }, - '/dev/input/event10': { - 'capabilities': {evdev.ecodes.EV_KEY: []}, - 'phys': 'usb-0000:03:00.0-1/input3', - 'name': 'device 1' - }, - '/dev/input/event13': { - 'capabilities': {evdev.ecodes.EV_KEY: [], evdev.ecodes.EV_SYN: []}, - 'phys': 'usb-0000:03:00.0-1/input1', - 'name': 'device 1' - }, - '/dev/input/event14': { - 'capabilities': {evdev.ecodes.EV_SYN: []}, - 'phys': 'usb-0000:03:00.0-1/input0', - 'name': 'device 1 qux' - }, - - # device 2 - '/dev/input/event20': { - 'capabilities': {evdev.ecodes.EV_KEY: []}, - 'phys': 'usb-0000:03:00.0-2/input1', - 'name': 'device 2' - }, - - # something that is completely ignored - '/dev/input/event30': { - 'capabilities': {evdev.ecodes.EV_SYN: []}, - 'phys': 'usb-0000:03:00.0-3/input1', - 'name': 'device 3' - }, - - # key-mapper devices are also ignored, another instance of key-mapper - # started injecting apparently. - '/dev/input/event40': { - 'capabilities': {evdev.ecodes.EV_KEY: []}, - 'phys': 'key-mapper/input1', - 'name': 'key-mapper device 2' - }, - } - def list_devices(): return fixtures.keys() diff --git a/tests/testcases/injector.py b/tests/testcases/injector.py index 898d6fdd..4ffbdc47 100644 --- a/tests/testcases/injector.py +++ b/tests/testcases/injector.py @@ -23,23 +23,61 @@ import unittest import evdev -from keymapper.injector import _start_injecting_worker, \ - is_numlock_on, toggle_numlock, ensure_numlock +from keymapper.injector import _start_injecting_worker, _grab, \ + is_numlock_on, toggle_numlock, ensure_numlock, _modify_capabilities from keymapper.getdevices import get_devices from keymapper.state import custom_mapping, system_mapping -from test import uinput_write_history, Event, pending_events +from test import uinput_write_history, Event, pending_events, fixtures class TestInjector(unittest.TestCase): @classmethod def setUpClass(cls): cls.injector = None + cls.grab = evdev.InputDevice.grab + + def setUp(self): + self.failed = 0 + + def grab_fail_twice(_): + if self.failed < 2: + self.failed += 1 + raise OSError() + + evdev.InputDevice.grab = grab_fail_twice def tearDown(self): if self.injector is not None: self.injector.stop_injecting() self.injector = None + evdev.InputDevice.grab = self.grab + + def test_modify_capabilities(self): + class FakeDevice: + def capabilities(self, absinfo=True): + assert absinfo is False + return { + evdev.ecodes.EV_SYN: [1, 2, 3], + evdev.ecodes.EV_FF: [1, 2, 3] + } + + capabilities = _modify_capabilities(FakeDevice()) + + self.assertIn(evdev.ecodes.EV_KEY, capabilities) + self.assertIsInstance(capabilities[evdev.ecodes.EV_KEY], list) + self.assertIsInstance(capabilities[evdev.ecodes.EV_KEY][0], int) + + self.assertNotIn(evdev.ecodes.EV_SYN, capabilities) + self.assertNotIn(evdev.ecodes.EV_FF, capabilities) + + def test_grab(self): + # path is from the fixtures + path = '/dev/input/event11' + device = _grab(path) + self.assertEqual(self.failed, 2) + # success on the third try + device.name = fixtures[path]['name'] def test_numlock(self): before = is_numlock_on()