Ejemplo n.º 1
0
    def test_hat0x(self):
        # it should be possible to add all of them
        ev_1 = Key(EV_ABS, evdev.ecodes.ABS_HAT0X, -1)
        ev_2 = Key(EV_ABS, evdev.ecodes.ABS_HAT0X, 1)
        ev_3 = Key(EV_ABS, evdev.ecodes.ABS_HAT0Y, -1)
        ev_4 = Key(EV_ABS, evdev.ecodes.ABS_HAT0Y, 1)

        self.change_empty_row(ev_1, 'a')
        self.change_empty_row(ev_2, 'b')
        self.change_empty_row(ev_3, 'c')
        self.change_empty_row(ev_4, 'd')

        self.assertEqual(custom_mapping.get_character(ev_1), 'a')
        self.assertEqual(custom_mapping.get_character(ev_2), 'b')
        self.assertEqual(custom_mapping.get_character(ev_3), 'c')
        self.assertEqual(custom_mapping.get_character(ev_4), 'd')
        self.assertTrue(custom_mapping.changed)

        # and trying to add them as duplicate rows will be ignored for each
        # of them
        self.change_empty_row(ev_1, 'e', expect_success=False)
        self.change_empty_row(ev_2, 'f', expect_success=False)
        self.change_empty_row(ev_3, 'g', expect_success=False)
        self.change_empty_row(ev_4, 'h', expect_success=False)

        self.assertEqual(custom_mapping.get_character(ev_1), 'a')
        self.assertEqual(custom_mapping.get_character(ev_2), 'b')
        self.assertEqual(custom_mapping.get_character(ev_3), 'c')
        self.assertEqual(custom_mapping.get_character(ev_4), 'd')
        self.assertTrue(custom_mapping.changed)
Ejemplo n.º 2
0
    def test_rows(self):
        """Comprehensive test for rows."""
        # how many rows there should be in the end
        num_rows_target = 3

        ev_1 = Key(EV_KEY, 10, 1)
        ev_2 = Key(EV_ABS, evdev.ecodes.ABS_HAT0X, -1)
        """edit"""

        # add two rows by modifiying the one empty row that exists
        self.change_empty_row(ev_1, 'a', code_first=False)
        self.change_empty_row(ev_2, 'k(b).k(c)')

        # one empty row added automatically again
        time.sleep(0.1)
        gtk_iteration()
        self.assertEqual(len(self.get_rows()), num_rows_target)

        self.assertEqual(custom_mapping.get_character(ev_1), 'a')
        self.assertEqual(custom_mapping.get_character(ev_2), 'k(b).k(c)')
        self.assertTrue(custom_mapping.changed)
        """save"""

        self.window.on_save_preset_clicked(None)
        for row in self.get_rows():
            css_classes = row.get_style_context().list_classes()
            self.assertNotIn('changed', css_classes)

        self.assertFalse(custom_mapping.changed)
        """edit first row"""

        # now change the first row and it should turn blue,
        # but the other should remain unhighlighted
        row = self.get_rows()[0]
        row.character_input.set_text('c')
        self.assertIn('changed', row.get_style_context().list_classes())
        for row in self.get_rows()[1:]:
            css_classes = row.get_style_context().list_classes()
            self.assertNotIn('changed', css_classes)

        self.assertEqual(custom_mapping.get_character(ev_1), 'c')
        self.assertEqual(custom_mapping.get_character(ev_2), 'k(b).k(c)')
        self.assertTrue(custom_mapping.changed)
        """add duplicate"""

        # try to add a duplicate keycode, it should be ignored
        self.change_empty_row(ev_2, 'd', expect_success=False)
        self.assertEqual(custom_mapping.get_character(ev_2), 'k(b).k(c)')
        # and the number of rows shouldn't change
        self.assertEqual(len(self.get_rows()), num_rows_target)
Ejemplo n.º 3
0
    def show_injection_result(self):
        """Show if the injection was successfully started."""
        state = self.dbus.get_state(self.selected_device)

        if state == RUNNING:
            msg = f'Applied preset "{self.selected_preset}"'

            if custom_mapping.get_character(Key.btn_left()):
                msg += ', CTRL + DEL to stop'

            self.show_status(CTX_APPLY, msg)

            self.show_device_mapping_status()
            return False

        if state == FAILED:
            self.show_status(
                CTX_ERROR, f'Failed to apply preset "{self.selected_preset}"')
            return False

        if state == NO_GRAB:
            self.show_status(
                CTX_ERROR, 'The device was not grabbed',
                'Either another application is already grabbing it or '
                'your preset doesn\'t contain anything that is sent by the '
                'device.')
            return False

        # keep the timeout running
        return True
Ejemplo n.º 4
0
    def test_remove_row(self):
        """Comprehensive test for rows 2."""
        # sleeps are added to be able to visually follow and debug the test.
        # add two rows by modifiying the one empty row that exists
        row_1 = self.change_empty_row(Key(EV_KEY, 10, 1), 'a')
        row_2 = self.change_empty_row(Key(EV_KEY, 11, 1), 'b')
        row_3 = self.change_empty_row(None, 'c')

        # no empty row added because one is unfinished
        time.sleep(0.2)
        gtk_iteration()
        self.assertEqual(len(self.get_rows()), 3)

        self.assertEqual(custom_mapping.get_character(Key(EV_KEY, 11, 1)), 'b')

        def remove(row, code, char, num_rows_after):
            """Remove a row by clicking the delete button.

            Parameters
            ----------
            row : Row
            code : int or None
                keycode of the mapping that is displayed by this row
            char : string or None
                ouptut of the mapping that is displayed by this row
            num_rows_after : int
                after deleting, how many rows are expected to still be there
            """
            if code is not None and char is not None:
                self.assertEqual(
                    custom_mapping.get_character(Key(EV_KEY, code, 1)), char)

            self.assertEqual(row.get_character(), char)
            if code is None:
                self.assertIsNone(row.get_key())
            else:
                self.assertEqual(row.get_key(), Key(EV_KEY, code, 1))

            row.on_delete_button_clicked()
            time.sleep(0.2)
            gtk_iteration()

            # if a reference to the row is held somewhere and it is
            # accidentally used again, make sure to not provide any outdated
            # information that is supposed to be deleted
            self.assertIsNone(row.get_key())
            self.assertIsNone(row.get_character())
            if code is not None:
                self.assertIsNone(
                    custom_mapping.get_character(Key(EV_KEY, code, 1)))
            self.assertEqual(len(self.get_rows()), num_rows_after)

        remove(row_1, 10, 'a', 2)
        remove(row_2, 11, 'b', 1)
        # there is no empty row at the moment, so after removing that one,
        # which is the only row, one empty row will be there. So the number
        # of rows won't change.
        remove(row_3, None, 'c', 1)
Ejemplo n.º 5
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())
Ejemplo n.º 6
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)
Ejemplo n.º 7
0
        def remove(row, code, char, num_rows_after):
            """Remove a row by clicking the delete button.

            Parameters
            ----------
            row : Row
            code : int or None
                keycode of the mapping that is displayed by this row
            char : string or None
                ouptut of the mapping that is displayed by this row
            num_rows_after : int
                after deleting, how many rows are expected to still be there
            """
            if code is not None and char is not None:
                self.assertEqual(
                    custom_mapping.get_character(Key(EV_KEY, code, 1)), char)

            self.assertEqual(row.get_character(), char)
            if code is None:
                self.assertIsNone(row.get_key())
            else:
                self.assertEqual(row.get_key(), Key(EV_KEY, code, 1))

            row.on_delete_button_clicked()
            time.sleep(0.2)
            gtk_iteration()

            # if a reference to the row is held somewhere and it is
            # accidentally used again, make sure to not provide any outdated
            # information that is supposed to be deleted
            self.assertIsNone(row.get_key())
            self.assertIsNone(row.get_character())
            if code is not None:
                self.assertIsNone(
                    custom_mapping.get_character(Key(EV_KEY, code, 1)))
            self.assertEqual(len(self.get_rows()), num_rows_after)
Ejemplo n.º 8
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)')
Ejemplo n.º 9
0
    def test_row_simple(self):
        rows = self.window.get('key_list').get_children()
        self.assertEqual(len(rows), 1)

        row = rows[0]

        row.set_new_key(None)
        self.assertIsNone(row.get_key())
        self.assertEqual(len(custom_mapping), 0)
        self.assertEqual(row.keycode_input.get_label(), 'click here')

        row.set_new_key(Key(EV_KEY, 30, 1))
        self.assertEqual(len(custom_mapping), 0)
        self.assertEqual(row.get_key(), (EV_KEY, 30, 1))
        # this is KEY_A in linux/input-event-codes.h,
        # but KEY_ is removed from the text
        self.assertEqual(row.keycode_input.get_label(), 'A')

        row.set_new_key(Key(EV_KEY, 30, 1))
        self.assertEqual(len(custom_mapping), 0)
        self.assertEqual(row.get_key(), (EV_KEY, 30, 1))

        time.sleep(0.1)
        gtk_iteration()
        self.assertEqual(len(self.window.get('key_list').get_children()), 1)

        row.character_input.set_text('Shift_L')
        self.assertEqual(len(custom_mapping), 1)

        time.sleep(0.1)
        gtk_iteration()
        self.assertEqual(len(self.window.get('key_list').get_children()), 2)

        self.assertEqual(custom_mapping.get_character(Key(EV_KEY, 30, 1)),
                         'Shift_L')
        self.assertEqual(row.get_character(), 'Shift_L')
        self.assertEqual(row.get_key(), (EV_KEY, 30, 1))
Ejemplo n.º 10
0
    def test_combination(self):
        # it should be possible to write a key combination
        ev_1 = Key(EV_KEY, evdev.ecodes.KEY_A, 1)
        ev_2 = Key(EV_ABS, evdev.ecodes.ABS_HAT0X, 1)
        ev_3 = Key(EV_KEY, evdev.ecodes.KEY_C, 1)
        ev_4 = Key(EV_ABS, evdev.ecodes.ABS_HAT0X, -1)
        combination_1 = Key(ev_1, ev_2, ev_3)
        combination_2 = Key(ev_2, ev_1, ev_3)

        # same as 1, but different D-Pad direction
        combination_3 = Key(ev_1, ev_4, ev_3)
        combination_4 = Key(ev_4, ev_1, ev_3)

        # same as 1, but the last key is different
        combination_5 = Key(ev_1, ev_3, ev_2)
        combination_6 = Key(ev_3, ev_1, ev_2)

        self.change_empty_row(combination_1, 'a')
        self.assertEqual(custom_mapping.get_character(combination_1), 'a')
        self.assertEqual(custom_mapping.get_character(combination_2), 'a')
        self.assertIsNone(custom_mapping.get_character(combination_3))
        self.assertIsNone(custom_mapping.get_character(combination_4))
        self.assertIsNone(custom_mapping.get_character(combination_5))
        self.assertIsNone(custom_mapping.get_character(combination_6))

        # it won't write the same combination again, even if the
        # first two events are in a different order
        self.change_empty_row(combination_2, 'b', expect_success=False)
        self.assertEqual(custom_mapping.get_character(combination_1), 'a')
        self.assertEqual(custom_mapping.get_character(combination_2), 'a')
        self.assertIsNone(custom_mapping.get_character(combination_3))
        self.assertIsNone(custom_mapping.get_character(combination_4))
        self.assertIsNone(custom_mapping.get_character(combination_5))
        self.assertIsNone(custom_mapping.get_character(combination_6))

        self.change_empty_row(combination_3, 'c')
        self.assertEqual(custom_mapping.get_character(combination_1), 'a')
        self.assertEqual(custom_mapping.get_character(combination_2), 'a')
        self.assertEqual(custom_mapping.get_character(combination_3), 'c')
        self.assertEqual(custom_mapping.get_character(combination_4), 'c')
        self.assertIsNone(custom_mapping.get_character(combination_5))
        self.assertIsNone(custom_mapping.get_character(combination_6))

        # same as with combination_2, the existing combination_3 blocks
        # combination_4 because they have the same keys and end in the
        # same key.
        self.change_empty_row(combination_4, 'd', expect_success=False)
        self.assertEqual(custom_mapping.get_character(combination_1), 'a')
        self.assertEqual(custom_mapping.get_character(combination_2), 'a')
        self.assertEqual(custom_mapping.get_character(combination_3), 'c')
        self.assertEqual(custom_mapping.get_character(combination_4), 'c')
        self.assertIsNone(custom_mapping.get_character(combination_5))
        self.assertIsNone(custom_mapping.get_character(combination_6))

        self.change_empty_row(combination_5, 'e')
        self.assertEqual(custom_mapping.get_character(combination_1), 'a')
        self.assertEqual(custom_mapping.get_character(combination_2), 'a')
        self.assertEqual(custom_mapping.get_character(combination_3), 'c')
        self.assertEqual(custom_mapping.get_character(combination_4), 'c')
        self.assertEqual(custom_mapping.get_character(combination_5), 'e')
        self.assertEqual(custom_mapping.get_character(combination_6), 'e')

        error_icon = self.window.get('error_status_icon')
        warning_icon = self.window.get('warning_status_icon')

        self.assertFalse(error_icon.get_visible())
        self.assertFalse(warning_icon.get_visible())