Esempio n. 1
0
    def test_autoload_other_path(self):
        devices = ['device 1', 'device 2']
        presets = ['bar123', 'bar2']
        config_dir = os.path.join(tmp, 'qux', 'quux')
        paths = [
            os.path.join(config_dir, 'presets', devices[0],
                         presets[0] + '.json'),
            os.path.join(config_dir, 'presets', devices[1],
                         presets[1] + '.json')
        ]

        Mapping().save(paths[0])
        Mapping().save(paths[1])

        daemon = Daemon()

        start_history = []
        daemon.start_injecting = lambda *args: start_history.append(args)

        config.path = os.path.join(config_dir, 'config.json')
        config.load_config()
        config.set_autoload_preset(devices[0], presets[0])
        config.set_autoload_preset(devices[1], presets[1])
        config.save_config()

        control(
            options('autoload', config_dir, None, None, False, False, False),
            daemon)

        self.assertEqual(len(start_history), 2)
        self.assertEqual(start_history[0], (devices[0], presets[0]))
        self.assertEqual(start_history[1], (devices[1], presets[1]))
Esempio n. 2
0
    def test_autoload_other_path(self):
        device_names = ['Foo Device', 'Bar Device']
        groups_ = [groups.find(name=name) for name in device_names]
        presets = ['bar123', 'bar2']
        config_dir = os.path.join(tmp, 'qux', 'quux')
        paths = [
            os.path.join(config_dir, 'presets', device_names[0],
                         presets[0] + '.json'),
            os.path.join(config_dir, 'presets', device_names[1],
                         presets[1] + '.json')
        ]

        Mapping().save(paths[0])
        Mapping().save(paths[1])

        daemon = Daemon()

        start_history = []
        daemon.start_injecting = lambda *args: start_history.append(args)

        config.path = os.path.join(config_dir, 'config.json')
        config.load_config()
        config.set_autoload_preset(device_names[0], presets[0])
        config.set_autoload_preset(device_names[1], presets[1])
        config.save_config()

        communicate(
            options('autoload', config_dir, None, None, False, False, False),
            daemon)

        self.assertEqual(len(start_history), 2)
        self.assertEqual(start_history[0], (groups_[0].key, presets[0]))
        self.assertEqual(start_history[1], (groups_[1].key, presets[1]))
Esempio n. 3
0
    def test_autoload(self):
        devices = ['device 1234', 'device 2345']
        presets = ['preset', 'bar']
        paths = [
            get_preset_path(devices[0], presets[0]),
            get_preset_path(devices[1], presets[1])
        ]
        xmodmap = 'a/xmodmap.json'

        Mapping().save(paths[0])
        Mapping().save(paths[1])

        daemon = Daemon()

        start_history = []
        stop_history = []
        daemon.start_injecting = lambda *args: start_history.append(args)
        daemon.stop = lambda *args: stop_history.append(args)

        config.set_autoload_preset(devices[0], presets[0])
        config.set_autoload_preset(devices[1], presets[1])

        control(options('autoload', None, None, False, False), daemon, xmodmap)

        self.assertEqual(len(start_history), 2)
        self.assertEqual(len(stop_history), 1)
        self.assertEqual(start_history[0],
                         (devices[0], os.path.expanduser(paths[0]), xmodmap))
        self.assertEqual(start_history[1],
                         (devices[1], os.path.abspath(paths[1]), xmodmap))
Esempio n. 4
0
    def test_store_permutations_for_macros(self):
        mapping = Mapping()
        ev_1 = (EV_KEY, 41, 1)
        ev_2 = (EV_KEY, 42, 1)
        ev_3 = (EV_KEY, 43, 1)
        # a combination
        mapping.change(Key(ev_1, ev_2, ev_3), 'k(a)')
        self.injector = Injector(groups.find(key='Foo Device 2'), mapping)

        history = []

        class Stop(Exception):
            pass

        def _construct_capabilities(*args):
            history.append(args)
            # avoid going into any mainloop
            raise Stop()

        with mock.patch.object(self.injector, '_construct_capabilities',
                               _construct_capabilities):
            try:
                self.injector.run()
            except Stop:
                pass

            # one call
            self.assertEqual(len(history), 1)
            # first argument of the first call
            macros = self.injector.context.macros
            self.assertEqual(len(macros), 2)
            self.assertEqual(macros[(ev_1, ev_2, ev_3)].code, 'k(a)')
            self.assertEqual(macros[(ev_2, ev_1, ev_3)].code, 'k(a)')
Esempio n. 5
0
    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],
                    evdev.ecodes.EV_ABS: [1, 2, 3]
                }

        mapping = Mapping()
        mapping.change(Key(EV_KEY, 80, 1), 'a')
        mapping.change(Key(EV_KEY, 81, 1), DISABLE_NAME)

        macro_code = 'r(2, m(sHiFt_l, r(2, k(1).k(2))))'
        macro = parse(macro_code, mapping)

        mapping.change(Key(EV_KEY, 60, 111), macro_code)

        # going to be ignored, because EV_REL cannot be mapped, that's
        # mouse movements.
        mapping.change(Key(EV_REL, 1234, 3), 'b')

        a = system_mapping.get('a')
        shift_l = system_mapping.get('ShIfT_L')
        one = system_mapping.get(1)
        two = system_mapping.get('2')
        btn_left = system_mapping.get('BtN_lEfT')

        self.injector = KeycodeInjector('foo', mapping)
        fake_device = FakeDevice()
        capabilities_1 = self.injector._modify_capabilities({60: macro},
                                                            fake_device,
                                                            abs_to_rel=False)

        self.assertIn(EV_KEY, capabilities_1)
        keys = capabilities_1[EV_KEY]
        self.assertIn(a, keys)
        self.assertIn(one, keys)
        self.assertIn(two, keys)
        self.assertIn(shift_l, keys)
        self.assertNotIn(DISABLE_CODE, keys)
        # abs_to_rel is false, so mouse capabilities are not needed
        self.assertNotIn(btn_left, keys)

        self.assertNotIn(evdev.ecodes.EV_SYN, capabilities_1)
        self.assertNotIn(evdev.ecodes.EV_FF, capabilities_1)
        self.assertNotIn(evdev.ecodes.EV_REL, capabilities_1)
        self.assertNotIn(evdev.ecodes.EV_ABS, capabilities_1)

        # abs_to_rel makes sure that BTN_LEFT is present
        capabilities_2 = self.injector._modify_capabilities({60: macro},
                                                            fake_device,
                                                            abs_to_rel=True)
        keys = capabilities_2[EV_KEY]
        self.assertIn(a, keys)
        self.assertIn(one, keys)
        self.assertIn(two, keys)
        self.assertIn(shift_l, keys)
        self.assertIn(btn_left, keys)
Esempio n. 6
0
    def test_save_load_2(self):
        # loads mappings with only (type, code) as the key by using 1 as value,
        # loads combinations chained with +
        path = os.path.join(tmp, 'presets', 'device 1', 'test.json')
        os.makedirs(os.path.dirname(path), exist_ok=True)
        with open(path, 'w') as file:
            json.dump(
                {
                    'mapping': {
                        f'{EV_KEY},3': 'a',
                        f'{EV_ABS},{ABS_HAT0X},-1': 'b',
                        f'{EV_ABS},1,1+{EV_ABS},2,-1+{EV_ABS},3,1': 'c',
                        # ignored because broken
                        f'3,1,1,2': 'e',
                        f'3': 'e',
                        f',,+3,1,2': 'g',
                        f'': 'h',
                    }
                },
                file)

        loaded = Mapping()
        self.assertEqual(loaded.num_saved_keys, 0)
        loaded.load(get_preset_path('device 1', 'test'))
        self.assertEqual(len(loaded), 3)
        self.assertEqual(loaded.num_saved_keys, 3)
        self.assertEqual(loaded.get_character(Key(EV_KEY, 3, 1)), 'a')
        self.assertEqual(loaded.get_character(Key(EV_ABS, ABS_HAT0X, -1)), 'b')
        self.assertEqual(
            loaded.get_character(
                Key((EV_ABS, 1, 1), (EV_ABS, 2, -1), Key(EV_ABS, 3, 1))), 'c')
Esempio n. 7
0
    def test_store_permutations_for_macros(self):
        mapping = Mapping()
        ev_1 = (EV_KEY, 41, 1)
        ev_2 = (EV_KEY, 42, 1)
        ev_3 = (EV_KEY, 43, 1)
        # a combination
        mapping.change(Key(ev_1, ev_2, ev_3), 'k(a)')
        self.injector = KeycodeInjector('device 1', mapping)

        history = []

        class Stop(Exception):
            pass

        def _modify_capabilities(*args):
            history.append(args)
            # avoid going into any mainloop
            raise Stop()

        self.injector._modify_capabilities = _modify_capabilities
        try:
            self.injector._start_injecting()
        except Stop:
            pass

        # one call
        self.assertEqual(len(history), 1)
        # first argument of the first call
        self.assertEqual(len(history[0][0]), 2)
        self.assertEqual(history[0][0][(ev_1, ev_2, ev_3)].code, 'k(a)')
        self.assertEqual(history[0][0][(ev_2, ev_1, ev_3)].code, 'k(a)')
Esempio n. 8
0
 def setUp(self):
     self.mapping = Mapping()
     self.mapping.set('gamepad.joystick.left_purpose', WHEEL)
     self.mapping.set('gamepad.joystick.right_purpose', WHEEL)
     self.mapping.change(Key(1, 31, 1), 'k(a)')
     self.mapping.change(Key(1, 32, 1), 'b')
     self.mapping.change(Key((1, 33, 1), (1, 34, 1), (1, 35, 1)), 'c')
     self.context = Context(self.mapping)
Esempio n. 9
0
    def test_autoload(self):
        preset = 'preset7'
        group = groups.find(key='Foo Device 2')

        daemon = Daemon()
        self.daemon = daemon
        self.daemon.set_config_dir(get_config_path())

        mapping = Mapping()
        mapping.change(Key(3, 2, 1), 'a')
        mapping.save(group.get_preset_path(preset))

        # no autoloading is configured yet
        self.daemon._autoload(group.key)
        self.assertNotIn(group.key, daemon.autoload_history._autoload_history)
        self.assertTrue(daemon.autoload_history.may_autoload(
            group.key, preset))

        config.set_autoload_preset(group.key, preset)
        config.save_config()
        self.daemon.set_config_dir(get_config_path())
        len_before = len(self.daemon.autoload_history._autoload_history)
        # now autoloading is configured, so it will autoload
        self.daemon._autoload(group.key)
        len_after = len(self.daemon.autoload_history._autoload_history)
        self.assertEqual(
            daemon.autoload_history._autoload_history[group.key][1], preset)
        self.assertFalse(
            daemon.autoload_history.may_autoload(group.key, preset))
        injector = daemon.injectors[group.key]
        self.assertEqual(len_before + 1, len_after)

        # calling duplicate _autoload does nothing
        self.daemon._autoload(group.key)
        self.assertEqual(
            daemon.autoload_history._autoload_history[group.key][1], preset)
        self.assertEqual(injector, daemon.injectors[group.key])
        self.assertFalse(
            daemon.autoload_history.may_autoload(group.key, preset))

        # explicit start_injecting clears the autoload history
        self.daemon.start_injecting(group.key, preset)
        self.assertTrue(daemon.autoload_history.may_autoload(
            group.key, preset))

        # calling autoload for (yet) unknown devices does nothing
        len_before = len(self.daemon.autoload_history._autoload_history)
        self.daemon._autoload('unknown-key-1234')
        len_after = len(self.daemon.autoload_history._autoload_history)
        self.assertEqual(len_before, len_after)

        # autoloading key-mapper devices does nothing
        len_before = len(self.daemon.autoload_history._autoload_history)
        self.daemon.autoload_single('Bar Device')
        len_after = len(self.daemon.autoload_history._autoload_history)
        self.assertEqual(len_before, len_after)
Esempio n. 10
0
    def start_injecting(self, device, path, xmodmap_path=None):
        """Start injecting the preset for the device.

        Returns True on success.

        Parameters
        ----------
        device : string
            The name of the device
        path : string
            Path to the preset. The daemon, if started via systemctl, has no
            knowledge of the user and their home path, so the complete
            absolute path needs to be provided here.
        xmodmap_path : string, None
            Path to a dump of the xkb mappings, to provide more human
            readable keys in the correct keyboard layout to the service.
            The service cannot use `xmodmap -pke` because it's running via
            systemd.
        """
        if device not in get_devices():
            logger.debug('Devices possibly outdated, refreshing')
            refresh_devices()

        # reload the config, since it may have been changed
        config.load_config()
        if self.injectors.get(device) is not None:
            self.injectors[device].stop_injecting()

        mapping = Mapping()
        try:
            mapping.load(path)
        except FileNotFoundError as error:
            logger.error(str(error))
            return False

        if xmodmap_path is not None:
            try:
                with open(xmodmap_path, 'r') as file:
                    xmodmap = json.load(file)
                    logger.debug('Using keycodes from "%s"', xmodmap_path)
                    system_mapping.update(xmodmap)
                    # the service now has process wide knowledge of xmodmap
                    # keys of the users session
            except FileNotFoundError:
                logger.error('Could not find "%s"', xmodmap_path)

        try:
            injector = KeycodeInjector(device, mapping)
            injector.start_injecting()
            self.injectors[device] = injector
        except OSError:
            return False

        return True
Esempio n. 11
0
    def setUp(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

        self.mapping = Mapping()

        device = InputDevice('/dev/input/event30')
        uinput = UInput()
        asyncio.ensure_future(
            ev_abs_mapper(abs_state, device, uinput, self.mapping))

        config.set('gamepad.joystick.x_scroll_speed', 1)
        config.set('gamepad.joystick.y_scroll_speed', 1)
Esempio n. 12
0
    def test_autoload(self):
        device = 'device 1'
        preset = 'preset7'
        path = '/dev/input/event11'

        daemon = Daemon()
        self.daemon = daemon
        self.daemon.set_config_dir(get_config_path())

        mapping = Mapping()
        mapping.change(Key(3, 2, 1), 'a')
        mapping.save(get_preset_path(device, preset))

        # no autoloading is configured yet
        self.daemon._autoload(device)
        self.daemon._autoload(path)
        self.assertNotIn(device, daemon.autoload_history._autoload_history)
        self.assertTrue(daemon.autoload_history.may_autoload(device, preset))

        config.set_autoload_preset(device, preset)
        config.save_config()
        self.daemon.set_config_dir(get_config_path())
        len_before = len(self.daemon.autoload_history._autoload_history)
        self.daemon._autoload(path)
        len_after = len(self.daemon.autoload_history._autoload_history)
        self.assertEqual(daemon.autoload_history._autoload_history[device][1], preset)
        self.assertFalse(daemon.autoload_history.may_autoload(device, preset))
        injector = daemon.injectors[device]
        self.assertEqual(len_before + 1, len_after)

        # calling duplicate _autoload does nothing
        self.daemon._autoload(path)
        self.assertEqual(daemon.autoload_history._autoload_history[device][1], preset)
        self.assertEqual(injector, daemon.injectors[device])
        self.assertFalse(daemon.autoload_history.may_autoload(device, preset))

        # explicit start_injecting clears the autoload history
        self.daemon.start_injecting(device, preset)
        self.assertTrue(daemon.autoload_history.may_autoload(device, preset))

        # calling autoload for (yet) unknown devices does nothing
        len_before = len(self.daemon.autoload_history._autoload_history)
        self.daemon._autoload('/dev/input/qux')
        len_after = len(self.daemon.autoload_history._autoload_history)
        self.assertEqual(len_before, len_after)

        # autoloading key-mapper devices does nothing
        len_before = len(self.daemon.autoload_history._autoload_history)
        self.daemon.autoload_single('/dev/input/event40')
        len_after = len(self.daemon.autoload_history._autoload_history)
        self.assertEqual(len_before, len_after)
Esempio n. 13
0
    def setUp(self):
        class FakeDevice:
            def __init__(self):
                self._capabilities = {
                    evdev.ecodes.EV_SYN: [1, 2, 3],
                    evdev.ecodes.EV_FF: [1, 2, 3],
                    EV_ABS: [(1,
                              evdev.AbsInfo(value=None,
                                            min=None,
                                            max=1234,
                                            fuzz=None,
                                            flat=None,
                                            resolution=None)),
                             (2,
                              evdev.AbsInfo(value=None,
                                            min=50,
                                            max=2345,
                                            fuzz=None,
                                            flat=None,
                                            resolution=None)), 3]
                }

            def capabilities(self, absinfo=False):
                assert absinfo is True
                return self._capabilities

        mapping = Mapping()
        mapping.change(Key(EV_KEY, 80, 1), 'a')
        mapping.change(Key(EV_KEY, 81, 1), DISABLE_NAME)

        macro_code = 'r(2, m(sHiFt_l, r(2, k(1).k(2))))'
        macro = parse(macro_code, mapping)

        mapping.change(Key(EV_KEY, 60, 111), macro_code)

        # going to be ignored, because EV_REL cannot be mapped, that's
        # mouse movements.
        mapping.change(Key(EV_REL, 1234, 3), 'b')

        self.a = system_mapping.get('a')
        self.shift_l = system_mapping.get('ShIfT_L')
        self.one = system_mapping.get(1)
        self.two = system_mapping.get('2')
        self.left = system_mapping.get('BtN_lEfT')
        self.fake_device = FakeDevice()
        self.mapping = mapping
        self.macro = macro
Esempio n. 14
0
    def test_clone(self):
        ev_1 = Key(EV_KEY, 1, 1)
        ev_2 = Key(EV_KEY, 2, 0)

        mapping1 = Mapping()
        mapping1.change(ev_1, ' a')
        mapping2 = mapping1.clone()
        mapping1.change(ev_2, 'b ')

        self.assertEqual(mapping1.get_character(ev_1), 'a')
        self.assertEqual(mapping1.get_character(ev_2), 'b')

        self.assertEqual(mapping2.get_character(ev_1), 'a')
        self.assertIsNone(mapping2.get_character(ev_2))

        self.assertIsNone(mapping2.get_character(Key(EV_KEY, 2, 3)))
        self.assertIsNone(mapping2.get_character(Key(EV_KEY, 1, 3)))
Esempio n. 15
0
    def setUp(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

        self.mapping = Mapping()
        self.context = Context(self.mapping)

        uinput = UInput()
        self.context.uinput = uinput

        device = InputDevice('/dev/input/event30')
        self.event_producer = EventProducer(self.context)
        self.event_producer.set_abs_range_from(device)
        asyncio.ensure_future(self.event_producer.run())

        config.set('gamepad.joystick.x_scroll_speed', 1)
        config.set('gamepad.joystick.y_scroll_speed', 1)
Esempio n. 16
0
    def test_key_to_code(self):
        mapping = Mapping()
        ev_1 = (EV_KEY, 41, 1)
        ev_2 = (EV_KEY, 42, 1)
        ev_3 = (EV_KEY, 43, 1)
        ev_4 = (EV_KEY, 44, 1)
        mapping.change(Key(ev_1), 'a')
        # a combination
        mapping.change(Key(ev_2, ev_3, ev_4), 'b')
        self.assertEqual(mapping.get_character(Key(ev_2, ev_3, ev_4)), 'b')

        system_mapping.clear()
        system_mapping._set('a', 51)
        system_mapping._set('b', 52)

        injector = KeycodeInjector('device 1', mapping)
        self.assertEqual(injector._key_to_code.get((ev_1, )), 51)
        # permutations to make matching combinations easier
        self.assertEqual(injector._key_to_code.get((ev_2, ev_3, ev_4)), 52)
        self.assertEqual(injector._key_to_code.get((ev_3, ev_2, ev_4)), 52)
        self.assertEqual(len(injector._key_to_code), 3)
Esempio n. 17
0
    def test_save_load(self):
        one = Key(EV_KEY, 10, 1)
        two = Key(EV_KEY, 11, 1)
        three = Key(EV_KEY, 12, 1)

        self.mapping.change(one, '1')
        self.mapping.change(two, '2')
        self.mapping.change(Key(two, three), '3')
        self.mapping._config['foo'] = 'bar'
        self.mapping.save(get_preset_path('device 1', 'test'))

        path = os.path.join(tmp, 'presets', 'device 1', 'test.json')
        self.assertTrue(os.path.exists(path))

        loaded = Mapping()
        self.assertEqual(len(loaded), 0)
        loaded.load(get_preset_path('device 1', 'test'))

        self.assertEqual(len(loaded), 3)
        self.assertEqual(loaded.get_character(one), '1')
        self.assertEqual(loaded.get_character(two), '2')
        self.assertEqual(loaded.get_character(Key(two, three)), '3')
        self.assertEqual(loaded._config['foo'], 'bar')
Esempio n. 18
0
    def test_key_to_code(self):
        mapping = Mapping()
        ev_1 = (EV_KEY, 41, 1)
        ev_2 = (EV_KEY, 42, 1)
        ev_3 = (EV_KEY, 43, 1)
        ev_4 = (EV_KEY, 44, 1)
        mapping.change(Key(ev_1), 'a')
        # a combination
        mapping.change(Key(ev_2, ev_3, ev_4), 'b')
        self.assertEqual(mapping.get_symbol(Key(ev_2, ev_3, ev_4)), 'b')

        system_mapping.clear()
        system_mapping._set('a', 51)
        system_mapping._set('b', 52)

        injector = Injector(groups.find(key='Foo Device 2'), mapping)
        injector.context = Context(mapping)
        self.assertEqual(injector.context.key_to_code.get((ev_1, )), 51)
        # permutations to make matching combinations easier
        self.assertEqual(injector.context.key_to_code.get((ev_2, ev_3, ev_4)),
                         52)
        self.assertEqual(injector.context.key_to_code.get((ev_3, ev_2, ev_4)),
                         52)
        self.assertEqual(len(injector.context.key_to_code), 3)
Esempio n. 19
0
    def test_autoload_3(self):
        # based on a bug
        preset = 'preset7'
        group = groups.find(key='Foo Device 2')

        mapping = Mapping()
        mapping.change(Key(3, 2, 1), 'a')
        mapping.save(group.get_preset_path(preset))

        config.set_autoload_preset(group.key, preset)
        config.save_config()

        self.daemon = Daemon()
        self.daemon.set_config_dir(get_config_path())
        groups.set_groups([])  # caused the bug
        self.assertIsNone(groups.find(key='Foo Device 2'))
        self.daemon.autoload()

        # it should try to refresh the groups because all the
        # group_keys are unknown at the moment
        history = self.daemon.autoload_history._autoload_history
        self.assertEqual(history[group.key][1], preset)
        self.assertEqual(self.daemon.get_state(group.key), STARTING)
        self.assertIsNotNone(groups.find(key='Foo Device 2'))
Esempio n. 20
0
    def test_autoload_2(self):
        self.daemon = Daemon()
        history = self.daemon.autoload_history._autoload_history

        # existing device
        preset = 'preset7'
        group = groups.find(key='Foo Device 2')
        mapping = Mapping()
        mapping.change(Key(3, 2, 1), 'a')
        mapping.save(group.get_preset_path(preset))
        config.set_autoload_preset(group.key, preset)

        # ignored, won't cause problems:
        config.set_autoload_preset('non-existant-key', 'foo')

        # daemon is missing the config directory yet
        self.daemon.autoload()
        self.assertEqual(len(history), 0)

        config.save_config()
        self.daemon.set_config_dir(get_config_path())
        self.daemon.autoload()
        self.assertEqual(len(history), 1)
        self.assertEqual(history[group.key][1], preset)
Esempio n. 21
0
    def test_autoload(self):
        devices = ['device 1', 'device 2']
        presets = ['bar0', 'bar', 'bar2']
        paths = [
            get_preset_path(devices[0], presets[0]),
            get_preset_path(devices[1], presets[1]),
            get_preset_path(devices[1], presets[2])
        ]

        Mapping().save(paths[0])
        Mapping().save(paths[1])
        Mapping().save(paths[2])

        daemon = Daemon()

        start_history = []
        stop_counter = 0

        # using an actual injector is not within the scope of this test
        class Injector:
            def stop_injecting(self, *args, **kwargs):
                nonlocal stop_counter
                stop_counter += 1

        def start_injecting(device, preset):
            print(f'\033[90mstart_injecting\033[0m')
            start_history.append((device, preset))
            daemon.injectors[device] = Injector()

        daemon.start_injecting = start_injecting

        config.set_autoload_preset(devices[0], presets[0])
        config.set_autoload_preset(devices[1], presets[1])
        config.save_config()

        control(options('autoload', None, None, None, False, False, False),
                daemon)
        self.assertEqual(len(start_history), 2)
        self.assertEqual(start_history[0], (devices[0], presets[0]))
        self.assertEqual(start_history[1], (devices[1], presets[1]))
        self.assertIn(devices[0], daemon.injectors)
        self.assertIn(devices[1], daemon.injectors)
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[0], presets[0]))
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[1], presets[1]))

        # calling autoload again doesn't load redundantly
        control(options('autoload', None, None, None, False, False, False),
                daemon)
        self.assertEqual(len(start_history), 2)
        self.assertEqual(stop_counter, 0)
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[0], presets[0]))
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[1], presets[1]))

        # unless the injection in question ist stopped
        control(options('stop', None, None, devices[0], False, False, False),
                daemon)
        self.assertEqual(stop_counter, 1)
        self.assertTrue(
            daemon.autoload_history.may_autoload(devices[0], presets[0]))
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[1], presets[1]))
        control(options('autoload', None, None, None, False, False, False),
                daemon)
        self.assertEqual(len(start_history), 3)
        self.assertEqual(start_history[2], (devices[0], presets[0]))
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[0], presets[0]))
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[1], presets[1]))

        # if a device name is passed, will only start injecting for that one
        control(options('stop-all', None, None, None, False, False, False),
                daemon)
        self.assertTrue(
            daemon.autoload_history.may_autoload(devices[0], presets[0]))
        self.assertTrue(
            daemon.autoload_history.may_autoload(devices[1], presets[1]))
        self.assertEqual(stop_counter, 3)
        config.set_autoload_preset(devices[1], presets[2])
        config.save_config()
        control(
            options('autoload', None, None, devices[1], False, False, False),
            daemon)
        self.assertEqual(len(start_history), 4)
        self.assertEqual(start_history[3], (devices[1], presets[2]))
        self.assertTrue(
            daemon.autoload_history.may_autoload(devices[0], presets[0]))
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[1], presets[2]))

        # autoloading for the same device again redundantly will not autoload
        # again
        control(
            options('autoload', None, None, devices[1], False, False, False),
            daemon)
        self.assertEqual(len(start_history), 4)
        self.assertEqual(stop_counter, 3)
        self.assertFalse(
            daemon.autoload_history.may_autoload(devices[1], presets[2]))

        # any other arbitrary preset may be autoloaded
        self.assertTrue(
            daemon.autoload_history.may_autoload(devices[1], 'quuuux'))

        # after 15 seconds it may be autoloaded again
        daemon.autoload_history._autoload_history[devices[1]] = (time.time() -
                                                                 16,
                                                                 presets[2])
        self.assertTrue(
            daemon.autoload_history.may_autoload(devices[1], presets[2]))
Esempio n. 22
0
        Parameters
        ----------
        mapping : dict
            maps from name to code. Make sure your keys are lowercase.
        """
        self._mapping.update(mapping)

    def _set(self, name, code):
        """Map name to code."""
        self._mapping[str(name).lower()] = code

    def get(self, name):
        """Return the code mapped to the key."""
        return self._mapping.get(str(name).lower())

    def clear(self):
        """Remove all mapped keys. Only needed for tests."""
        keys = list(self._mapping.keys())
        for key in keys:
            del self._mapping[key]


# one mapping object for the GUI application
custom_mapping = Mapping()

# this mapping represents the xmodmap output, which stays constant
system_mapping = SystemMapping()

# permissions for files created in /usr
_PERMISSIONS = stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP | stat.S_IROTH
Esempio n. 23
0
 def test_writes_keys(self):
     self.assertTrue(self.context.writes_keys())
     self.assertFalse(Context(Mapping()).writes_keys())
Esempio n. 24
0
    def test_start_stop(self):
        group = groups.find(key='Foo Device 2')
        preset = 'preset8'

        daemon = Daemon()
        self.daemon = daemon

        mapping = Mapping()
        mapping.change(Key(3, 2, 1), 'a')
        mapping.save(group.get_preset_path(preset))

        # the daemon needs set_config_dir first before doing anything
        daemon.start_injecting(group.key, preset)
        self.assertNotIn(group.key, daemon.autoload_history._autoload_history)
        self.assertNotIn(group.key, daemon.injectors)
        self.assertTrue(daemon.autoload_history.may_autoload(
            group.key, preset))

        # start
        config.save_config()
        daemon.set_config_dir(get_config_path())
        daemon.start_injecting(group.key, preset)
        # explicit start, not autoload, so the history stays empty
        self.assertNotIn(group.key, daemon.autoload_history._autoload_history)
        self.assertTrue(daemon.autoload_history.may_autoload(
            group.key, preset))
        # path got translated to the device name
        self.assertIn(group.key, daemon.injectors)

        # start again
        previous_injector = daemon.injectors[group.key]
        self.assertNotEqual(previous_injector.get_state(), STOPPED)
        daemon.start_injecting(group.key, preset)
        self.assertNotIn(group.key, daemon.autoload_history._autoload_history)
        self.assertTrue(daemon.autoload_history.may_autoload(
            group.key, preset))
        self.assertIn(group.key, daemon.injectors)
        self.assertEqual(previous_injector.get_state(), STOPPED)
        # a different injetor is now running
        self.assertNotEqual(previous_injector, daemon.injectors[group.key])
        self.assertNotEqual(daemon.injectors[group.key].get_state(), STOPPED)

        # trying to inject a non existing preset keeps the previous inejction
        # alive
        injector = daemon.injectors[group.key]
        daemon.start_injecting(group.key, 'qux')
        self.assertEqual(injector, daemon.injectors[group.key])
        self.assertNotEqual(daemon.injectors[group.key].get_state(), STOPPED)

        # trying to start injecting for an unknown device also just does
        # nothing
        daemon.start_injecting('quux', 'qux')
        self.assertNotEqual(daemon.injectors[group.key].get_state(), STOPPED)

        # after all that stuff autoload_history is still unharmed
        self.assertNotIn(group.key, daemon.autoload_history._autoload_history)
        self.assertTrue(daemon.autoload_history.may_autoload(
            group.key, preset))

        # stop
        daemon.stop_injecting(group.key)
        self.assertNotIn(group.key, daemon.autoload_history._autoload_history)
        self.assertEqual(daemon.injectors[group.key].get_state(), STOPPED)
        self.assertTrue(daemon.autoload_history.may_autoload(
            group.key, preset))
Esempio n. 25
0
    def test_should_map_as_btn(self):
        mapping = Mapping()

        def do(gamepad, event):
            return utils.should_map_as_btn(event, mapping, gamepad)

        """D-Pad"""

        self.assertTrue(do(1, new_event(EV_ABS, ABS_HAT0X, 1)))
        self.assertTrue(do(0, new_event(EV_ABS, ABS_HAT0X, -1)))
        """Mouse movements"""

        self.assertTrue(do(1, new_event(EV_REL, REL_WHEEL, 1)))
        self.assertTrue(do(0, new_event(EV_REL, REL_WHEEL, -1)))
        self.assertTrue(do(1, new_event(EV_REL, REL_HWHEEL, 1)))
        self.assertTrue(do(0, new_event(EV_REL, REL_HWHEEL, -1)))
        self.assertFalse(do(1, new_event(EV_REL, REL_X, -1)))
        """regular keys and buttons"""

        self.assertTrue(do(1, new_event(EV_KEY, KEY_A, 1)))
        self.assertTrue(do(0, new_event(EV_KEY, KEY_A, 1)))
        self.assertTrue(do(1, new_event(EV_ABS, ABS_HAT0X, -1)))
        self.assertTrue(do(0, new_event(EV_ABS, ABS_HAT0X, -1)))
        """mousepad events"""

        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MT_SLOT, 1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MT_SLOT, 1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MT_TOOL_Y, 1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MT_TOOL_Y, 1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MT_POSITION_X, 1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MT_POSITION_X, 1)))
        self.assertFalse(do(1, new_event(EV_KEY, ecodes.BTN_TOUCH, 1)))
        self.assertFalse(do(0, new_event(EV_KEY, ecodes.BTN_TOUCH, 1)))
        """stylus movements"""

        self.assertFalse(do(0, new_event(EV_KEY, ecodes.BTN_DIGI, 1)))
        self.assertFalse(do(1, new_event(EV_KEY, ecodes.BTN_DIGI, 1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_TILT_X, 1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_TILT_X, 1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_TILT_Y, 1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_TILT_Y, 1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_DISTANCE, 1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_DISTANCE, 1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_PRESSURE, 1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_PRESSURE, 1)))
        """joysticks"""

        # without a purpose of BUTTONS it won't map any button, even for
        # gamepads
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_RX, 1234)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_RX, 1234)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_Y, -1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_Y, -1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_RY, -1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_RY, -1)))

        mapping.set('gamepad.joystick.right_purpose', BUTTONS)
        config.set('gamepad.joystick.left_purpose', BUTTONS)
        # but only for gamepads
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_Y, -1)))
        self.assertTrue(do(1, new_event(EV_ABS, ecodes.ABS_Y, -1)))
        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_RY, -1)))
        self.assertTrue(do(1, new_event(EV_ABS, ecodes.ABS_RY, -1)))
        """weird events"""

        self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MISC, -1)))
        self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MISC, -1)))
Esempio n. 26
0
    def test_should_map_event_as_btn(self):
        device = InputDevice('/dev/input/event30')
        mapping = Mapping()

        # the function name is so horribly long
        do = utils.should_map_event_as_btn
        """D-Pad"""

        self.assertTrue(do(device, InputEvent(EV_ABS, ABS_HAT0X, 1), mapping))
        self.assertTrue(do(device, InputEvent(EV_ABS, ABS_HAT0X, -1), mapping))
        """Mouse movements"""

        self.assertFalse(do(device, InputEvent(EV_REL, REL_WHEEL, 1), mapping))
        self.assertFalse(do(device, InputEvent(EV_REL, REL_WHEEL, -1),
                            mapping))
        self.assertFalse(do(device, InputEvent(EV_REL, REL_HWHEEL, 1),
                            mapping))
        self.assertFalse(
            do(device, InputEvent(EV_REL, REL_HWHEEL, -1), mapping))
        self.assertFalse(do(device, InputEvent(EV_REL, REL_X, -1), mapping))
        """regular keys and buttons"""

        self.assertTrue(do(device, InputEvent(EV_KEY, KEY_A, 1), mapping))
        self.assertTrue(do(device, InputEvent(EV_ABS, ABS_HAT0X, -1), mapping))
        """mousepad events"""

        self.assertFalse(
            do(device, InputEvent(EV_ABS, ecodes.ABS_MT_SLOT, 1), mapping))
        self.assertFalse(
            do(device, InputEvent(EV_ABS, ecodes.ABS_MT_TOOL_Y, 1), mapping))
        self.assertFalse(
            do(device, InputEvent(EV_ABS, ecodes.ABS_MT_POSITION_X, 1),
               mapping))
        """joysticks"""

        self.assertFalse(
            do(device, InputEvent(EV_ABS, ecodes.ABS_RX, 1234), mapping))
        self.assertFalse(
            do(device, InputEvent(EV_ABS, ecodes.ABS_Y, -1), mapping))

        mapping.set('gamepad.joystick.left_purpose', BUTTONS)

        event = InputEvent(EV_ABS, ecodes.ABS_RX, MAX_ABS)
        self.assertFalse(do(device, event, mapping))
        self.assertEqual(event.value, MAX_ABS)
        event = InputEvent(EV_ABS, ecodes.ABS_Y, -MAX_ABS)
        self.assertTrue(do(device, event, mapping))
        self.assertEqual(event.value, -1)
        event = InputEvent(EV_ABS, ecodes.ABS_X, -MAX_ABS / 4)
        self.assertTrue(do(device, event, mapping))
        self.assertEqual(event.value, 0)

        config.set('gamepad.joystick.right_purpose', BUTTONS)

        event = InputEvent(EV_ABS, ecodes.ABS_RX, MAX_ABS)
        self.assertTrue(do(device, event, mapping))
        self.assertEqual(event.value, 1)
        event = InputEvent(EV_ABS, ecodes.ABS_Y, MAX_ABS)
        self.assertTrue(do(device, event, mapping))
        self.assertEqual(event.value, 1)
        event = InputEvent(EV_ABS, ecodes.ABS_X, MAX_ABS / 4)
        self.assertTrue(do(device, event, mapping))
        self.assertEqual(event.value, 0)
Esempio n. 27
0
    def start_injecting(self, group_key, preset):
        """Start injecting the preset for the device.

        Returns True on success. If an injection is already ongoing for
        the specified device it will stop it automatically first.

        Parameters
        ----------
        group_key : string
            The unique key of the group
        preset : string
            The name of the preset
        """
        self.refresh(group_key)

        if self.config_dir is None:
            logger.error(
                'Tried to start an injection without configuring the daemon '
                'first via set_config_dir.')
            return False

        group = groups.find(key=group_key)

        if group is None:
            logger.error('Could not find group "%s"', group_key)
            return False

        preset_path = os.path.join(self.config_dir, 'presets', group.name,
                                   f'{preset}.json')

        mapping = Mapping()
        try:
            mapping.load(preset_path)
        except FileNotFoundError as error:
            logger.error(str(error))
            return False

        if self.injectors.get(group_key) is not None:
            self.stop_injecting(group_key)

        # Path to a dump of the xkb mappings, to provide more human
        # readable keys in the correct keyboard layout to the service.
        # The service cannot use `xmodmap -pke` because it's running via
        # systemd.
        xmodmap_path = os.path.join(self.config_dir, 'xmodmap.json')
        try:
            with open(xmodmap_path, 'r') as file:
                # do this for each injection to make sure it is up to
                # date when the system layout changes.
                xmodmap = json.load(file)
                logger.debug('Using keycodes from "%s"', xmodmap_path)
                system_mapping.update(xmodmap)
                # the service now has process wide knowledge of xmodmap
                # keys of the users session
        except FileNotFoundError:
            logger.error('Could not find "%s"', xmodmap_path)

        try:
            injector = Injector(group, mapping)
            injector.start()
            self.injectors[group.key] = injector
        except OSError:
            # I think this will never happen, probably leftover from
            # some earlier version
            return False

        return True
Esempio n. 28
0
 def setUp(self):
     self.result = []
     self.loop = asyncio.get_event_loop()
     self.mapping = Mapping()
Esempio n. 29
0
 def setUp(self):
     self.mapping = Mapping()
Esempio n. 30
0
 def setUp(self):
     self.mapping = Mapping()
     self.assertFalse(self.mapping.changed)