Exemplo n.º 1
0
    def test_gamepad_forward_joysticks(self):
        push_events(
            'gamepad',
            [
                # should forward them unmodified
                new_event(EV_ABS, ABS_X, 10),
                new_event(EV_ABS, ABS_Y, 20),
                new_event(EV_ABS, ABS_X, -30),
                new_event(EV_ABS, ABS_Y, -40),
                new_event(EV_KEY, BTN_A, 1),
                new_event(EV_KEY, BTN_A, 0)
            ] * 2)

        custom_mapping.set('gamepad.joystick.left_purpose', NONE)
        custom_mapping.set('gamepad.joystick.right_purpose', NONE)
        # BTN_A -> 77
        custom_mapping.change(Key((1, BTN_A, 1)), 'b')
        system_mapping._set('b', 77)
        self.injector = Injector(groups.find(name='gamepad'), custom_mapping)
        self.injector.start()

        # wait for the injector to start sending, at most 1s
        uinput_write_history_pipe[0].poll(1)
        time.sleep(0.2)

        # convert the write history to some easier to manage list
        history = read_write_history_pipe()

        self.assertEqual(history.count((EV_ABS, ABS_X, 10)), 2)
        self.assertEqual(history.count((EV_ABS, ABS_Y, 20)), 2)
        self.assertEqual(history.count((EV_ABS, ABS_X, -30)), 2)
        self.assertEqual(history.count((EV_ABS, ABS_Y, -40)), 2)
        self.assertEqual(history.count((EV_KEY, 77, 1)), 2)
        self.assertEqual(history.count((EV_KEY, 77, 0)), 2)
Exemplo n.º 2
0
    def test_gamepad_purpose_none_2(self):
        # forward abs joystick events for the left joystick only
        custom_mapping.set('gamepad.joystick.left_purpose', NONE)
        config.set('gamepad.joystick.right_purpose', MOUSE)

        self.injector = Injector(groups.find(name='gamepad'), custom_mapping)
        self.injector.context = Context(custom_mapping)

        path = '/dev/input/event30'
        device = self.injector._grab_device(path)
        # the right joystick maps as mouse, so it is grabbed
        # even with an empty mapping
        self.assertIsNotNone(device)
        gamepad = classify(device) == GAMEPAD
        self.assertTrue(gamepad)
        capabilities = self.injector._construct_capabilities(gamepad)
        self.assertNotIn(EV_ABS, capabilities)
        self.assertIn(EV_REL, capabilities)

        custom_mapping.change(Key(EV_KEY, BTN_A, 1), 'a')
        device = self.injector._grab_device(path)
        gamepad = classify(device) == GAMEPAD
        self.assertIsNotNone(device)
        self.assertTrue(gamepad)
        capabilities = self.injector._construct_capabilities(gamepad)
        self.assertNotIn(EV_ABS, capabilities)
        self.assertIn(EV_REL, capabilities)
        self.assertIn(EV_KEY, capabilities)
Exemplo n.º 3
0
    def test_grab_device_non_existing(self):
        custom_mapping.change(Key(EV_ABS, ABS_HAT0X, 1), 'a')
        self.injector = Injector('foobar', custom_mapping)
        self.injector.context = Context(custom_mapping)

        _grab_device = self.injector._grab_device
        self.assertIsNone(_grab_device('/dev/input/event1234'))
Exemplo n.º 4
0
    def test_gamepad_trigger(self):
        # map one of the triggers to BTN_NORTH, while the other one
        # should be forwarded unchanged
        value = MAX_ABS // 2
        push_events('gamepad', [
            new_event(EV_ABS, ABS_Z, value),
            new_event(EV_ABS, ABS_RZ, value),
        ])

        # ABS_Z -> 77
        # ABS_RZ is not mapped
        custom_mapping.change(Key((EV_ABS, ABS_Z, 1)), 'b')
        system_mapping._set('b', 77)
        self.injector = Injector(groups.find(name='gamepad'), custom_mapping)
        self.injector.start()

        # wait for the injector to start sending, at most 1s
        uinput_write_history_pipe[0].poll(1)
        time.sleep(0.2)

        # convert the write history to some easier to manage list
        history = read_write_history_pipe()

        self.assertEqual(history.count((EV_KEY, 77, 1)), 1)
        self.assertEqual(history.count((EV_ABS, ABS_RZ, value)), 1)
Exemplo n.º 5
0
    def test_xmodmap_file(self):
        from_keycode = evdev.ecodes.KEY_A
        to_name = 'qux'
        to_keycode = 100
        event = (EV_KEY, from_keycode, 1)

        device = 'device 2'
        preset = 'foo'

        path = get_preset_path(device, preset)

        custom_mapping.change(Key(event), to_name)
        custom_mapping.save(path)

        system_mapping.clear()

        config.set_autoload_preset(device, preset)

        pending_events[device] = [InputEvent(*event)]

        xmodmap_path = os.path.join(tmp, 'foobar.json')
        with open(xmodmap_path, 'w') as file:
            file.write(f'{{"{to_name}":{to_keycode}}}')

        self.daemon = Daemon()
        self.daemon.start_injecting(device, path, xmodmap_path)

        event = uinput_write_history_pipe[0].recv()
        self.assertEqual(event.type, EV_KEY)
        self.assertEqual(event.code, to_keycode)
        self.assertEqual(event.value, 1)
Exemplo n.º 6
0
    def test_prepare_device_1(self):
        # according to the fixtures, /dev/input/event30 can do ABS_HAT0X
        custom_mapping.change(Key(EV_ABS, ABS_HAT0X, 1), 'a')
        self.injector = KeycodeInjector('foobar', custom_mapping)

        _prepare_device = self.injector._prepare_device
        self.assertIsNone(_prepare_device('/dev/input/event10')[0])
        self.assertIsNotNone(_prepare_device('/dev/input/event30')[0])
Exemplo n.º 7
0
    def test_refresh_on_start(self):
        if os.path.exists(get_config_path('xmodmap.json')):
            os.remove(get_config_path('xmodmap.json'))

        ev = (EV_KEY, 9)
        keycode_to = 100
        group_name = '9876 name'

        # expected key of the group
        group_key = group_name

        group = groups.find(name=group_name)
        # this test only makes sense if this device is unknown yet
        self.assertIsNone(group)
        custom_mapping.change(Key(*ev, 1), 'a')
        system_mapping.clear()
        system_mapping._set('a', keycode_to)

        # make the daemon load the file instead
        with open(get_config_path('xmodmap.json'), 'w') as file:
            json.dump(system_mapping._mapping, file, indent=4)
        system_mapping.clear()

        preset = 'foo'
        custom_mapping.save(get_preset_path(group_name, preset))
        config.set_autoload_preset(group_key, preset)
        push_events(group_key, [new_event(*ev, 1)])
        self.daemon = Daemon()

        # make sure the devices are populated
        groups.refresh()

        # the daemon is supposed to find this device by calling refresh
        fixtures[self.new_fixture_path] = {
            'capabilities': {
                evdev.ecodes.EV_KEY: [ev[1]]
            },
            'phys': '9876 phys',
            'info': evdev.device.DeviceInfo(4, 5, 6, 7),
            'name': group_name
        }

        self.daemon.set_config_dir(get_config_path())
        self.daemon.start_injecting(group_key, preset)

        # test if the injector called groups.refresh successfully
        group = groups.find(key=group_key)
        self.assertEqual(group.name, group_name)
        self.assertEqual(group.key, group_key)

        time.sleep(0.1)
        self.assertTrue(uinput_write_history_pipe[0].poll())

        event = uinput_write_history_pipe[0].recv()
        self.assertEqual(event.t, (EV_KEY, keycode_to, 1))

        self.daemon.stop_injecting(group_key)
        self.assertEqual(self.daemon.get_state(group_key), STOPPED)
Exemplo n.º 8
0
 def test_skip_unused_device(self):
     # skips a device because its capabilities are not used in the mapping
     custom_mapping.change(Key(EV_KEY, 10, 1), 'a')
     self.injector = Injector('device 1', custom_mapping)
     self.injector.context = Context(custom_mapping)
     path = '/dev/input/event11'
     device = self.injector._grab_device(path)
     self.assertIsNone(device)
     self.assertEqual(self.failed, 0)
Exemplo n.º 9
0
    def test_grab_device_1(self):
        # according to the fixtures, /dev/input/event30 can do ABS_HAT0X
        custom_mapping.change(Key(EV_ABS, ABS_HAT0X, 1), 'a')
        self.injector = Injector('foobar', custom_mapping)
        self.injector.context = Context(custom_mapping)

        _grab_device = self.injector._grab_device
        self.assertIsNone(_grab_device('/dev/input/event10'))
        self.assertIsNotNone(_grab_device('/dev/input/event30'))
Exemplo n.º 10
0
 def test_skip_unused_device(self):
     # skips a device because its capabilities are not used in the mapping
     custom_mapping.change(Key(EV_KEY, 10, 1), 'a')
     self.injector = KeycodeInjector('device 1', custom_mapping)
     path = '/dev/input/event11'
     device, abs_to_rel = self.injector._prepare_device(path)
     self.assertFalse(abs_to_rel)
     self.assertEqual(self.failed, 0)
     self.assertIsNone(device)
Exemplo n.º 11
0
    def test_grab_device_1(self):
        custom_mapping.change(Key(EV_ABS, ABS_HAT0X, 1), 'a')
        self.injector = Injector(groups.find(name='gamepad'), custom_mapping)
        self.injector.context = Context(custom_mapping)

        _grab_device = self.injector._grab_device
        # doesn't have the required capability
        self.assertIsNone(_grab_device('/dev/input/event10'))
        # according to the fixtures, /dev/input/event30 can do ABS_HAT0X
        self.assertIsNotNone(_grab_device('/dev/input/event30'))
        # this doesn't exist
        self.assertIsNone(_grab_device('/dev/input/event1234'))
Exemplo n.º 12
0
    def test_skip_unknown_device(self):
        custom_mapping.change(Key(EV_KEY, 10, 1), 'a')

        # skips a device because its capabilities are not used in the mapping
        self.injector = Injector('device 1', custom_mapping)
        self.injector.context = Context(custom_mapping)
        path = '/dev/input/event11'
        device = self.injector._grab_device(path)

        # skips the device alltogether, so no grab attempts fail
        self.assertEqual(self.failed, 0)
        self.assertIsNone(device)
Exemplo n.º 13
0
    def on_symbol_input_change(self, _):
        """When the output symbol for that keycode is typed in."""
        key = self.get_key()
        symbol = self.get_symbol()

        if symbol is None:
            return

        if key is not None:
            custom_mapping.change(new_key=key,
                                  symbol=symbol,
                                  previous_key=None)
Exemplo n.º 14
0
    def test_capabilities_and_uinput_presence(self, ungrab_patch):
        custom_mapping.change(Key(EV_KEY, KEY_A, 1), 'c')
        custom_mapping.change(Key(EV_REL, REL_HWHEEL, 1), 'k(b)')
        self.injector = Injector(groups.find(key='Foo Device 2'),
                                 custom_mapping)
        self.injector.stop_injecting()
        self.injector.run()

        self.assertEqual(
            self.injector.context.mapping.get_symbol(Key(EV_KEY, KEY_A, 1)),
            'c')
        self.assertEqual(
            self.injector.context.key_to_code[((EV_KEY, KEY_A, 1), )], KEY_C)
        self.assertEqual(
            self.injector.context.mapping.get_symbol(Key(
                EV_REL, REL_HWHEEL, 1)), 'k(b)')
        self.assertEqual(
            self.injector.context.macros[((EV_REL, REL_HWHEEL, 1), )].code,
            'k(b)')

        self.assertListEqual(
            sorted(uinputs.keys()),
            sorted([
                # reading and preventing original events from reaching the
                # display server
                'key-mapper Foo Device foo forwarded',
                'key-mapper Foo Device forwarded',
                # injection
                'key-mapper Foo Device 2 mapped'
            ]))

        forwarded_foo = uinputs.get('key-mapper Foo Device foo forwarded')
        forwarded = uinputs.get('key-mapper Foo Device forwarded')
        mapped = uinputs.get('key-mapper Foo Device 2 mapped')
        self.assertIsNotNone(forwarded_foo)
        self.assertIsNotNone(forwarded)
        self.assertIsNotNone(mapped)

        # puts the needed capabilities into the new key-mapper device
        self.assertIn(EV_KEY, mapped.capabilities())
        self.assertEqual(len(mapped.capabilities()[EV_KEY]), 2)
        self.assertIn(KEY_C, mapped.capabilities()[EV_KEY])
        self.assertIn(KEY_B, mapped.capabilities()[EV_KEY])
        # not a gamepad that maps joysticks to mouse movements
        self.assertNotIn(EV_REL, mapped.capabilities())

        # copies capabilities for all other forwarded devices
        self.assertIn(EV_REL, forwarded_foo.capabilities())
        self.assertIn(EV_KEY, forwarded.capabilities())
        self.assertEqual(sorted(forwarded.capabilities()[EV_KEY]),
                         keyboard_keys)

        self.assertEqual(ungrab_patch.call_count, 2)
Exemplo n.º 15
0
    def set_new_key(self, new_key):
        """Check if a keycode has been pressed and if so, display it.

        Parameters
        ----------
        new_key : Key
        """
        if new_key is not None and not isinstance(new_key, Key):
            raise TypeError('Expected new_key to be a Key object')

        # the newest_keycode is populated since the ui regularly polls it
        # in order to display it in the status bar.
        previous_key = self.get_key()

        # no input
        if new_key is None:
            return

        # it might end up being a key combination
        self.state = HOLDING

        # keycode didn't change, do nothing
        if new_key == previous_key:
            return

        # keycode is already set by some other row
        existing = custom_mapping.get_character(new_key)
        if existing is not None:
            msg = f'"{to_string(new_key)}" already mapped to "{existing}"'
            logger.info(msg)
            self.window.show_status(CTX_KEYCODE, msg)
            return

        # it's legal to display the keycode

        # always ask for get_child to set the label, otherwise line breaking
        # has to be configured again.
        self.set_keycode_input_label(to_string(new_key))

        self.key = new_key

        self.highlight()

        character = self.get_character()

        # the character is empty and therefore the mapping is not complete
        if character is None:
            return

        # else, the keycode has changed, the character is set, all good
        custom_mapping.change(new_key=new_key,
                              character=character,
                              previous_key=previous_key)
Exemplo n.º 16
0
    def on_character_input_change(self, _):
        """When the output character for that keycode is typed in."""
        key = self.get_key()
        character = self.get_character()

        if character is None:
            return

        if key is not None:
            custom_mapping.change(new_key=key,
                                  character=character,
                                  previous_key=None)
Exemplo n.º 17
0
    def test_grab(self):
        # path is from the fixtures
        custom_mapping.change(Key(EV_KEY, 10, 1), 'a')

        self.injector = KeycodeInjector('device 1', custom_mapping)
        path = '/dev/input/event10'
        # this test needs to pass around all other constraints of
        # _prepare_device
        device, abs_to_rel = self.injector._prepare_device(path)
        self.assertFalse(abs_to_rel)
        self.assertEqual(self.failed, 2)
        # success on the third try
        device.name = fixtures[path]['name']
Exemplo n.º 18
0
    def test_adds_ev_key(self):
        # for some reason, having any EV_KEY capability is needed to
        # be able to control the mouse. it probably wants the mouse click.
        custom_mapping.change(Key(EV_KEY, BTN_A, 1), 'a')
        self.injector = Injector(groups.find(name='gamepad'), custom_mapping)
        custom_mapping.set('gamepad.joystick.left_purpose', MOUSE)
        self.injector.context = Context(custom_mapping)
        """ABS device without any key capability"""

        path = self.new_gamepad_path
        gamepad_template = copy.deepcopy(fixtures['/dev/input/event30'])
        fixtures[path] = {
            'name': 'qux 2',
            'phys': 'abcd',
            'info': '1234',
            'capabilities': gamepad_template['capabilities']
        }
        del fixtures[path]['capabilities'][EV_KEY]
        device = self.injector._grab_device(path)
        # no reason to grab, BTN_A capability is missing in the device
        self.assertIsNone(device)
        """ABS device with a btn_mouse capability"""

        path = self.new_gamepad_path
        gamepad_template = copy.deepcopy(fixtures['/dev/input/event30'])
        fixtures[path] = {
            'name': 'qux 3',
            'phys': 'abcd',
            'info': '1234',
            'capabilities': gamepad_template['capabilities']
        }
        fixtures[path]['capabilities'][EV_KEY].append(BTN_LEFT)
        fixtures[path]['capabilities'][EV_KEY].append(KEY_A)
        device = self.injector._grab_device(path)
        gamepad = classify(device) == GAMEPAD
        capabilities = self.injector._construct_capabilities(gamepad)
        self.assertIn(EV_KEY, capabilities)
        self.assertIn(evdev.ecodes.BTN_MOUSE, capabilities[EV_KEY])
        self.assertIn(evdev.ecodes.KEY_A, capabilities[EV_KEY])
        """a gamepad"""

        path = '/dev/input/event30'
        device = self.injector._grab_device(path)
        gamepad = classify(device) == GAMEPAD
        self.assertIn(EV_KEY, device.capabilities())
        self.assertNotIn(evdev.ecodes.BTN_MOUSE, device.capabilities()[EV_KEY])
        capabilities = self.injector._construct_capabilities(gamepad)
        self.assertIn(EV_KEY, capabilities)
        self.assertGreater(len(capabilities), 1)
        self.assertIn(evdev.ecodes.BTN_MOUSE, capabilities[EV_KEY])
Exemplo n.º 19
0
    def test_grab(self):
        # path is from the fixtures
        custom_mapping.change(Key(EV_KEY, 10, 1), 'a')

        self.injector = Injector('device 1', custom_mapping)
        path = '/dev/input/event10'
        # this test needs to pass around all other constraints of
        # _grab_device
        self.injector.context = Context(custom_mapping)
        device = self.injector._grab_device(path)
        gamepad = classify(device) == GAMEPAD
        self.assertFalse(gamepad)
        self.assertEqual(self.failed, 2)
        # success on the third try
        device.name = fixtures[path]['name']
Exemplo n.º 20
0
    def test_fail_grab(self):
        self.make_it_fail = 10
        custom_mapping.change(Key(EV_KEY, 10, 1), 'a')

        self.injector = KeycodeInjector('device 1', custom_mapping)
        path = '/dev/input/event10'
        device, abs_to_rel = self.injector._prepare_device(path)
        self.assertFalse(abs_to_rel)
        self.assertGreaterEqual(self.failed, 1)
        self.assertIsNone(device)

        self.injector.start_injecting()
        # since none can be grabbed, the process will terminate. But that
        # actually takes quite some time.
        time.sleep(1.5)
        self.assertFalse(self.injector._process.is_alive())
Exemplo n.º 21
0
    def test_xmodmap_file(self):
        from_keycode = evdev.ecodes.KEY_A
        to_name = 'qux'
        to_keycode = 100
        event = (EV_KEY, from_keycode, 1)

        device = 'device 2'
        preset = 'foo'

        config_dir = os.path.join(tmp, 'foo')

        path = os.path.join(config_dir, 'presets', device, f'{preset}.json')

        custom_mapping.change(Key(event), to_name)
        custom_mapping.save(path)

        system_mapping.clear()

        push_events(device, [
            new_event(*event)
        ])

        # an existing config file is needed otherwise set_config_dir refuses
        # to use the directory
        config_path = os.path.join(config_dir, 'config.json')
        config.path = config_path
        config.save_config()

        xmodmap_path = os.path.join(config_dir, 'xmodmap.json')
        with open(xmodmap_path, 'w') as file:
            file.write(f'{{"{to_name}":{to_keycode}}}')

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

        self.daemon.start_injecting(device, preset)

        time.sleep(0.1)
        self.assertTrue(uinput_write_history_pipe[0].poll())

        event = uinput_write_history_pipe[0].recv()
        self.assertEqual(event.type, EV_KEY)
        self.assertEqual(event.code, to_keycode)
        self.assertEqual(event.value, 1)
Exemplo n.º 22
0
    def test_select_device_and_preset(self):
        # created on start because the first device is selected and some empty
        # preset prepared.
        self.assertTrue(
            os.path.exists(f'{CONFIG_PATH}/presets/device 1/new preset.json'))
        self.assertEqual(self.window.selected_device, 'device 1')
        self.assertEqual(self.window.selected_preset, 'new preset')

        # create another one
        self.window.on_create_preset_clicked(None)
        gtk_iteration()
        self.assertTrue(
            os.path.exists(f'{CONFIG_PATH}/presets/device 1/new preset.json'))
        self.assertTrue(
            os.path.exists(
                f'{CONFIG_PATH}/presets/device 1/new preset 2.json'))
        self.assertEqual(self.window.selected_preset, 'new preset 2')

        self.window.on_select_preset(FakeDropdown('new preset'))
        gtk_iteration()
        self.assertEqual(self.window.selected_preset, 'new preset')

        self.assertListEqual(
            sorted(os.listdir(f'{CONFIG_PATH}/presets/device 1')),
            sorted(['new preset.json', 'new preset 2.json']))

        # now try to change the name
        self.window.get('preset_name_input').set_text('abc 123')
        gtk_iteration()
        self.assertEqual(self.window.selected_preset, 'new preset')
        self.assertFalse(
            os.path.exists(f'{CONFIG_PATH}/presets/device 1/abc 123.json'))
        custom_mapping.change(Key(EV_KEY, 10, 1), '1', None)
        self.window.on_save_preset_clicked(None)
        gtk_iteration()
        self.assertEqual(self.window.selected_preset, 'abc 123')
        self.assertTrue(
            os.path.exists(f'{CONFIG_PATH}/presets/device 1/abc 123.json'))
        self.assertListEqual(
            sorted(os.listdir(os.path.join(CONFIG_PATH, 'presets'))),
            sorted(['device 1']))
        self.assertListEqual(
            sorted(os.listdir(f'{CONFIG_PATH}/presets/device 1')),
            sorted(['abc 123.json', 'new preset 2.json']))
Exemplo n.º 23
0
    def test_rename_and_save(self):
        custom_mapping.change(Key(EV_KEY, 14, 1), 'a', None)
        self.assertEqual(self.window.selected_preset, 'new preset')
        self.window.on_save_preset_clicked(None)
        self.assertEqual(custom_mapping.get_character(Key(EV_KEY, 14, 1)), 'a')

        custom_mapping.change(Key(EV_KEY, 14, 1), 'b', None)
        self.window.get('preset_name_input').set_text('asdf')
        self.window.on_save_preset_clicked(None)
        self.assertEqual(self.window.selected_preset, 'asdf')
        self.assertTrue(
            os.path.exists(f'{CONFIG_PATH}/presets/device 1/asdf.json'))
        self.assertEqual(custom_mapping.get_character(Key(EV_KEY, 14, 1)), 'b')

        error_icon = self.window.get('error_status_icon')
        status = self.window.get('status_bar')
        tooltip = status.get_tooltip_text().lower()
        self.assertIn('saved', tooltip)
        self.assertFalse(error_icon.get_visible())
Exemplo n.º 24
0
    def test_fail_grab(self):
        self.make_it_fail = 10
        custom_mapping.change(Key(EV_KEY, 10, 1), 'a')

        self.injector = Injector('device 1', custom_mapping)
        path = '/dev/input/event10'
        self.injector.context = Context(custom_mapping)
        device = self.injector._grab_device(path)
        self.assertIsNone(device)
        self.assertGreaterEqual(self.failed, 1)

        self.assertEqual(self.injector.get_state(), UNKNOWN)
        self.injector.start()
        self.assertEqual(self.injector.get_state(), STARTING)
        # since none can be grabbed, the process will terminate. But that
        # actually takes quite some time.
        time.sleep(1.5)
        self.assertFalse(self.injector.is_alive())
        self.assertEqual(self.injector.get_state(), NO_GRAB)
Exemplo n.º 25
0
    def test_gamepad_purpose_none(self):
        # forward abs joystick events
        custom_mapping.set('gamepad.joystick.left_purpose', NONE)
        config.set('gamepad.joystick.right_purpose', NONE)

        self.injector = Injector(groups.find(name='gamepad'), custom_mapping)
        self.injector.context = Context(custom_mapping)

        path = '/dev/input/event30'
        device = self.injector._grab_device(path)
        self.assertIsNone(device)  # no capability is used, so it won't grab

        custom_mapping.change(Key(EV_KEY, BTN_A, 1), 'a')
        device = self.injector._grab_device(path)
        self.assertIsNotNone(device)
        gamepad = classify(device) == GAMEPAD
        self.assertTrue(gamepad)
        capabilities = self.injector._construct_capabilities(gamepad)
        self.assertNotIn(EV_ABS, capabilities)
Exemplo n.º 26
0
    def test_refresh_devices_on_start(self):
        ev = (EV_KEY, 9)
        keycode_to = 100
        device = '9876 name'
        # this test only makes sense if this device is unknown yet
        self.assertIsNone(get_devices().get(device))
        custom_mapping.change(Key(*ev, 1), 'a')
        system_mapping.clear()
        system_mapping._set('a', keycode_to)
        preset = 'foo'
        custom_mapping.save(get_preset_path(device, preset))
        config.set_autoload_preset(device, preset)
        pending_events[device] = [InputEvent(*ev, 1)]
        self.daemon = Daemon()
        preset_path = get_preset_path(device, preset)

        # make sure the devices are populated
        get_devices()
        fixtures[self.new_fixture] = {
            'capabilities': {
                evdev.ecodes.EV_KEY: [ev[1]]
            },
            'phys': '9876 phys',
            'info': 'abcd',
            'name': device
        }

        self.daemon.start_injecting(device, preset_path)

        # test if the injector called refresh_devices successfully
        self.assertIsNotNone(get_devices().get(device))

        event = uinput_write_history_pipe[0].recv()
        self.assertEqual(event.type, EV_KEY)
        self.assertEqual(event.code, keycode_to)
        self.assertEqual(event.value, 1)

        self.daemon.stop_injecting(device)
        self.assertFalse(self.daemon.is_injecting(device))
Exemplo n.º 27
0
    def test_check_macro_syntax(self):
        status = self.window.get('status_bar')
        error_icon = self.window.get('error_status_icon')
        warning_icon = self.window.get('warning_status_icon')

        custom_mapping.change(Key(EV_KEY, 9, 1), 'k(1))', None)
        self.window.on_save_preset_clicked(None)
        tooltip = status.get_tooltip_text().lower()
        self.assertIn('brackets', tooltip)
        self.assertTrue(error_icon.get_visible())
        self.assertFalse(warning_icon.get_visible())

        custom_mapping.change(Key(EV_KEY, 9, 1), 'k(1)', None)
        self.window.on_save_preset_clicked(None)
        tooltip = status.get_tooltip_text().lower()
        self.assertNotIn('brackets', tooltip)
        self.assertIn('saved', tooltip)
        self.assertFalse(error_icon.get_visible())
        self.assertFalse(warning_icon.get_visible())

        self.assertEqual(custom_mapping.get_character(Key(EV_KEY, 9, 1)),
                         'k(1)')
Exemplo n.º 28
0
 def test_select_device(self):
     # creates a new empty preset when no preset exists for the device
     self.window.on_select_device(FakeDropdown('device 1'))
     custom_mapping.change(Key(EV_KEY, 50, 1), 'q')
     custom_mapping.change(Key(EV_KEY, 51, 1), 'u')
     custom_mapping.change(Key(EV_KEY, 52, 1), 'x')
     self.assertEqual(len(custom_mapping), 3)
     self.window.on_select_device(FakeDropdown('device 2'))
     self.assertEqual(len(custom_mapping), 0)
     # it creates the file for that right away. It may have been possible
     # to write it such that it doesn't (its empty anyway), but it does,
     # so use that to test it in more detail.
     path = get_preset_path('device 2', 'new preset')
     self.assertTrue(os.path.exists(path))
     with open(path, 'r') as file:
         preset = json.load(file)
         self.assertEqual(len(preset['mapping']), 0)
Exemplo n.º 29
0
    def test_wheel(self):
        # this tests both keycode_mapper and event_producer, and it seems
        # to test stuff not covered in test_keycode_mapper, so it's a quite
        # important one.

        # wheel release events are made up with a debouncer

        # map those two to stuff
        w_up = (EV_REL, REL_WHEEL, -1)
        hw_right = (EV_REL, REL_HWHEEL, 1)

        # should be forwarded and present in the capabilities
        hw_left = (EV_REL, REL_HWHEEL, -1)

        custom_mapping.change(Key(*hw_right), 'k(b)')
        custom_mapping.change(Key(*w_up), 'c')

        system_mapping.clear()
        code_b = 91
        code_c = 92
        system_mapping._set('b', code_b)
        system_mapping._set('c', code_c)

        group_key = 'Foo Device 2'
        push_events(group_key, [
            new_event(*w_up),
        ] * 10 + [
            new_event(*hw_right),
            new_event(*w_up),
        ] * 5 + [new_event(*hw_left)])

        group = groups.find(key=group_key)
        self.injector = Injector(group, custom_mapping)

        device = InputDevice('/dev/input/event11')
        # make sure this test uses a device that has the needed capabilities
        # for the injector to grab it
        self.assertIn(EV_REL, device.capabilities())
        self.assertIn(REL_WHEEL, device.capabilities()[EV_REL])
        self.assertIn(REL_HWHEEL, device.capabilities()[EV_REL])
        self.assertIn(device.path, group.paths)

        self.injector.start()

        # wait for the first injected key down event
        uinput_write_history_pipe[0].poll(timeout=1)
        self.assertTrue(uinput_write_history_pipe[0].poll())
        event = uinput_write_history_pipe[0].recv()
        self.assertEqual(event.t, (EV_KEY, code_c, 1))

        time.sleep(EVENT_READ_TIMEOUT * 5)
        # in 5 more read-loop ticks, nothing new should have happened
        self.assertFalse(uinput_write_history_pipe[0].poll())

        time.sleep(EVENT_READ_TIMEOUT * 6)
        # 5 more and it should be within the second phase in which
        # the horizontal wheel is used. add some tolerance
        self.assertTrue(uinput_write_history_pipe[0].poll())
        event = uinput_write_history_pipe[0].recv()
        self.assertEqual(event.t, (EV_KEY, code_b, 1))

        time.sleep(EVENT_READ_TIMEOUT * 10 + 5 / 60)
        # after 21 read-loop ticks all events should be consumed, wait for
        # at least 3 (=5) producer-ticks so that the debouncers are triggered.
        # Key-up events for both wheel events should be written now that no
        # new key-down event arrived.
        events = read_write_history_pipe()
        self.assertEqual(events.count((EV_KEY, code_b, 0)), 1)
        self.assertEqual(events.count((EV_KEY, code_c, 0)), 1)
        self.assertEqual(events.count(hw_left), 1)  # the unmapped wheel

        # the unmapped wheel won't get a debounced release command, it's
        # forwarded as is
        self.assertNotIn((EV_REL, REL_HWHEEL, 0), events)

        self.assertEqual(len(events), 3)
Exemplo n.º 30
0
    def test_any_funky_event_as_button(self):
        # as long as should_map_as_btn says it should be a button,
        # it will be.
        EV_TYPE = 4531
        CODE_1 = 754
        CODE_2 = 4139

        w_down = (EV_TYPE, CODE_1, -1)
        w_up = (EV_TYPE, CODE_1, 0)

        d_down = (EV_TYPE, CODE_2, 1)
        d_up = (EV_TYPE, CODE_2, 0)

        custom_mapping.change(Key(*w_down[:2], -1), 'w')
        custom_mapping.change(Key(*d_down[:2], 1), 'k(d)')

        system_mapping.clear()
        code_w = 71
        code_d = 74
        system_mapping._set('w', code_w)
        system_mapping._set('d', code_d)

        def do_stuff():
            if self.injector is not None:
                # discard the previous injector
                self.injector.stop_injecting()
                time.sleep(0.1)
                while uinput_write_history_pipe[0].poll():
                    uinput_write_history_pipe[0].recv()

            push_events('gamepad', [
                new_event(*w_down),
                new_event(*d_down),
                new_event(*w_up),
                new_event(*d_up),
            ])

            self.injector = Injector(groups.find(name='gamepad'),
                                     custom_mapping)

            # the injector will otherwise skip the device because
            # the capabilities don't contain EV_TYPE
            input = InputDevice('/dev/input/event30')
            self.injector._grab_device = lambda *args: input

            self.injector.start()
            uinput_write_history_pipe[0].poll(timeout=1)
            time.sleep(EVENT_READ_TIMEOUT * 10)
            return read_write_history_pipe()

        """no"""

        history = do_stuff()
        self.assertEqual(history.count((EV_KEY, code_w, 1)), 0)
        self.assertEqual(history.count((EV_KEY, code_d, 1)), 0)
        self.assertEqual(history.count((EV_KEY, code_w, 0)), 0)
        self.assertEqual(history.count((EV_KEY, code_d, 0)), 0)
        """yes"""

        with mock.patch('keymapper.utils.should_map_as_btn', lambda *_: True):
            history = do_stuff()
            self.assertEqual(history.count((EV_KEY, code_w, 1)), 1)
            self.assertEqual(history.count((EV_KEY, code_d, 1)), 1)
            self.assertEqual(history.count((EV_KEY, code_w, 0)), 1)
            self.assertEqual(history.count((EV_KEY, code_d, 0)), 1)