def clear_keystring(self): """Clear the currently entered key sequence.""" if self._sequence: self._debug_log("Clearing keystring (was: {}).".format( self._sequence)) self._sequence = keyutils.KeySequence() self._count = '' self.keystring_updated.emit('')
def __init__(self, win_id, parent=None, supports_count=True): super().__init__(parent) self._win_id = win_id self._modename = None self._sequence = keyutils.KeySequence() self._count = '' self._supports_count = supports_count self.bindings = {} config.instance.changed.connect(self._on_config_changed)
def test_iter(self): seq = keyutils.KeySequence(Qt.Key_A | Qt.ControlModifier, Qt.Key_B | Qt.ShiftModifier, Qt.Key_C, Qt.Key_D, Qt.Key_E) expected = [ keyutils.KeyInfo(Qt.Key_A, Qt.ControlModifier), keyutils.KeyInfo(Qt.Key_B, Qt.ShiftModifier), keyutils.KeyInfo(Qt.Key_C, Qt.NoModifier), keyutils.KeyInfo(Qt.Key_D, Qt.NoModifier), keyutils.KeyInfo(Qt.Key_E, Qt.NoModifier) ] assert list(seq) == expected
def _clear_partial_match(self): """Clear a partial keystring after a timeout.""" self._debug_log("Clearing partial keystring {}".format(self._sequence)) self._sequence = keyutils.KeySequence() self.keystring_updated.emit(str(self._sequence))
def test_strip_modifiers(self): seq = keyutils.KeySequence(Qt.Key_0, Qt.Key_1 | Qt.KeypadModifier, Qt.Key_A | Qt.ControlModifier) expected = keyutils.KeySequence(Qt.Key_0, Qt.Key_1, Qt.Key_A | Qt.ControlModifier) assert seq.strip_modifiers() == expected
def test_append_event_invalid(self, key): seq = keyutils.KeySequence() event = QKeyEvent(QKeyEvent.KeyPress, key, Qt.NoModifier, '') with pytest.raises(keyutils.KeyParseError): seq.append_event(event)
def test_fake_mac(self, fake_keyevent, modifiers, expected): """Make sure Control/Meta are swapped with a simulated Mac.""" seq = keyutils.KeySequence() event = fake_keyevent(key=Qt.Key_A, modifiers=modifiers) new = seq.append_event(event) assert new[0] == keyutils.KeyInfo(Qt.Key_A, expected)
def test_bool(self): seq1 = keyutils.KeySequence.parse('abcd') seq2 = keyutils.KeySequence() assert seq1 assert not seq2
def test_repr(self): seq = keyutils.KeySequence(Qt.Key_A | Qt.ControlModifier, Qt.Key_B | Qt.ShiftModifier) assert repr(seq) == ("<glimpsebrowser.keyinput.keyutils.KeySequence " "keys='<Ctrl+a>B'>")
def test_init_unknown(self, key): with pytest.raises(keyutils.KeyParseError): keyutils.KeySequence(key)
def test_init_empty(self): seq = keyutils.KeySequence() assert not seq
def test_init(self): seq = keyutils.KeySequence(Qt.Key_A, Qt.Key_B, Qt.Key_C, Qt.Key_D, Qt.Key_E) assert len(seq._sequences) == 2 assert len(seq._sequences[0]) == 4 assert len(seq._sequences[1]) == 1
class TestKeySequence: def test_init(self): seq = keyutils.KeySequence(Qt.Key_A, Qt.Key_B, Qt.Key_C, Qt.Key_D, Qt.Key_E) assert len(seq._sequences) == 2 assert len(seq._sequences[0]) == 4 assert len(seq._sequences[1]) == 1 def test_init_empty(self): seq = keyutils.KeySequence() assert not seq @pytest.mark.parametrize('key', [Qt.Key_unknown, -1, 0]) def test_init_unknown(self, key): with pytest.raises(keyutils.KeyParseError): keyutils.KeySequence(key) def test_parse_unknown(self): with pytest.raises(keyutils.KeyParseError): keyutils.KeySequence.parse('\x1f') @pytest.mark.parametrize('orig, normalized', [ ('<Control+x>', '<Ctrl+x>'), ('<Windows+x>', '<Meta+x>'), ('<Mod4+x>', '<Meta+x>'), ('<Command+x>', '<Meta+x>'), ('<Cmd+x>', '<Meta+x>'), ('<Mod1+x>', '<Alt+x>'), ('<Control-->', '<Ctrl+->'), ('<Windows++>', '<Meta++>'), ('<ctrl-x>', '<Ctrl+x>'), ('<control+x>', '<Ctrl+x>'), ('<a>b', 'ab'), ]) def test_str_normalization(self, orig, normalized): assert str(keyutils.KeySequence.parse(orig)) == normalized def test_iter(self): seq = keyutils.KeySequence(Qt.Key_A | Qt.ControlModifier, Qt.Key_B | Qt.ShiftModifier, Qt.Key_C, Qt.Key_D, Qt.Key_E) expected = [ keyutils.KeyInfo(Qt.Key_A, Qt.ControlModifier), keyutils.KeyInfo(Qt.Key_B, Qt.ShiftModifier), keyutils.KeyInfo(Qt.Key_C, Qt.NoModifier), keyutils.KeyInfo(Qt.Key_D, Qt.NoModifier), keyutils.KeyInfo(Qt.Key_E, Qt.NoModifier) ] assert list(seq) == expected def test_repr(self): seq = keyutils.KeySequence(Qt.Key_A | Qt.ControlModifier, Qt.Key_B | Qt.ShiftModifier) assert repr(seq) == ("<glimpsebrowser.keyinput.keyutils.KeySequence " "keys='<Ctrl+a>B'>") @pytest.mark.parametrize('sequences, expected', [ (['a', ''], ['', 'a']), (['abcdf', 'abcd', 'abcde'], ['abcd', 'abcde', 'abcdf']), ]) def test_sorting(self, sequences, expected): result = sorted(keyutils.KeySequence.parse(seq) for seq in sequences) expected_result = [keyutils.KeySequence.parse(seq) for seq in expected] assert result == expected_result @pytest.mark.parametrize('seq1, seq2, op, result', [ ('a', 'a', operator.eq, True), ('a', '<a>', operator.eq, True), ('a', '<Shift-a>', operator.eq, False), ('a', 'b', operator.lt, True), ('a', 'b', operator.le, True), ]) def test_operators(self, seq1, seq2, op, result): seq1 = keyutils.KeySequence.parse(seq1) seq2 = keyutils.KeySequence.parse(seq2) assert op(seq1, seq2) == result opposite = { operator.lt: operator.ge, operator.gt: operator.le, operator.le: operator.gt, operator.ge: operator.lt, operator.eq: operator.ne, operator.ne: operator.eq, } assert opposite[op](seq1, seq2) != result @pytest.mark.parametrize('seq1, seq2, equal', [ ('a', 'a', True), ('a', 'A', False), ('a', '<a>', True), ('abcd', 'abcde', False), ]) def test_hash(self, seq1, seq2, equal): seq1 = keyutils.KeySequence.parse(seq1) seq2 = keyutils.KeySequence.parse(seq2) assert (hash(seq1) == hash(seq2)) == equal @pytest.mark.parametrize('seq, length', [('', 0), ('a', 1), ('A', 1), ('<Ctrl-a>', 1), ('abcde', 5)]) def test_len(self, seq, length): assert len(keyutils.KeySequence.parse(seq)) == length def test_bool(self): seq1 = keyutils.KeySequence.parse('abcd') seq2 = keyutils.KeySequence() assert seq1 assert not seq2 def test_getitem(self): seq = keyutils.KeySequence.parse('ab') expected = keyutils.KeyInfo(Qt.Key_B, Qt.NoModifier) assert seq[1] == expected def test_getitem_slice(self): s1 = 'abcdef' s2 = 'de' seq = keyutils.KeySequence.parse(s1) expected = keyutils.KeySequence.parse(s2) assert s1[3:5] == s2 assert seq[3:5] == expected @pytest.mark.parametrize( 'entered, configured, expected', [ # config: abcd ('abc', 'abcd', QKeySequence.PartialMatch), ('abcd', 'abcd', QKeySequence.ExactMatch), ('ax', 'abcd', QKeySequence.NoMatch), ('abcdef', 'abcd', QKeySequence.NoMatch), # config: abcd ef ('abc', 'abcdef', QKeySequence.PartialMatch), ('abcde', 'abcdef', QKeySequence.PartialMatch), ('abcd', 'abcdef', QKeySequence.PartialMatch), ('abcdx', 'abcdef', QKeySequence.NoMatch), ('ax', 'abcdef', QKeySequence.NoMatch), ('abcdefg', 'abcdef', QKeySequence.NoMatch), ('abcdef', 'abcdef', QKeySequence.ExactMatch), # other examples ('ab', 'a', QKeySequence.NoMatch), # empty strings ('', '', QKeySequence.ExactMatch), ('', 'a', QKeySequence.PartialMatch), ('a', '', QKeySequence.NoMatch), ]) def test_matches(self, entered, configured, expected): entered = keyutils.KeySequence.parse(entered) configured = keyutils.KeySequence.parse(configured) assert entered.matches(configured) == expected @pytest.mark.parametrize( 'old, key, modifiers, text, expected', [ ('a', Qt.Key_B, Qt.NoModifier, 'b', 'ab'), ('a', Qt.Key_B, Qt.ShiftModifier, 'B', 'aB'), ('a', Qt.Key_B, Qt.AltModifier | Qt.ShiftModifier, 'B', 'a<Alt+Shift+b>'), # Modifier stripping with symbols ('', Qt.Key_Colon, Qt.NoModifier, ':', ':'), ('', Qt.Key_Colon, Qt.ShiftModifier, ':', ':'), ('', Qt.Key_Colon, Qt.AltModifier | Qt.ShiftModifier, ':', '<Alt+Shift+:>'), # Swapping Control/Meta on macOS ('', Qt.Key_A, Qt.ControlModifier, '', '<Meta+A>' if utils.is_mac else '<Ctrl+A>'), ('', Qt.Key_A, Qt.ControlModifier | Qt.ShiftModifier, '', '<Meta+Shift+A>' if utils.is_mac else '<Ctrl+Shift+A>'), ('', Qt.Key_A, Qt.MetaModifier, '', '<Ctrl+A>' if utils.is_mac else '<Meta+A>'), # Handling of Backtab ('', Qt.Key_Backtab, Qt.NoModifier, '', '<Backtab>'), ('', Qt.Key_Backtab, Qt.ShiftModifier, '', '<Shift+Tab>'), ('', Qt.Key_Backtab, Qt.AltModifier | Qt.ShiftModifier, '', '<Alt+Shift+Tab>'), # Stripping of Qt.GroupSwitchModifier ('', Qt.Key_A, Qt.GroupSwitchModifier, 'a', 'a'), ]) def test_append_event(self, old, key, modifiers, text, expected): seq = keyutils.KeySequence.parse(old) event = QKeyEvent(QKeyEvent.KeyPress, key, modifiers, text) new = seq.append_event(event) assert new == keyutils.KeySequence.parse(expected) @pytest.mark.fake_os('mac') @pytest.mark.parametrize('modifiers, expected', [ (Qt.ControlModifier, Qt.MetaModifier), (Qt.MetaModifier, Qt.ControlModifier), (Qt.ControlModifier | Qt.MetaModifier, Qt.ControlModifier | Qt.MetaModifier), (Qt.ControlModifier | Qt.ShiftModifier, Qt.MetaModifier | Qt.ShiftModifier), (Qt.MetaModifier | Qt.ShiftModifier, Qt.ControlModifier | Qt.ShiftModifier), (Qt.ShiftModifier, Qt.ShiftModifier), ]) def test_fake_mac(self, fake_keyevent, modifiers, expected): """Make sure Control/Meta are swapped with a simulated Mac.""" seq = keyutils.KeySequence() event = fake_keyevent(key=Qt.Key_A, modifiers=modifiers) new = seq.append_event(event) assert new[0] == keyutils.KeyInfo(Qt.Key_A, expected) @pytest.mark.parametrize('key', [Qt.Key_unknown, 0x0]) def test_append_event_invalid(self, key): seq = keyutils.KeySequence() event = QKeyEvent(QKeyEvent.KeyPress, key, Qt.NoModifier, '') with pytest.raises(keyutils.KeyParseError): seq.append_event(event) def test_strip_modifiers(self): seq = keyutils.KeySequence(Qt.Key_0, Qt.Key_1 | Qt.KeypadModifier, Qt.Key_A | Qt.ControlModifier) expected = keyutils.KeySequence(Qt.Key_0, Qt.Key_1, Qt.Key_A | Qt.ControlModifier) assert seq.strip_modifiers() == expected def test_with_mappings(self): seq = keyutils.KeySequence.parse('foobar') mappings = { keyutils.KeySequence.parse('b'): keyutils.KeySequence.parse('t') } seq2 = seq.with_mappings(mappings) assert seq2 == keyutils.KeySequence.parse('footar') @pytest.mark.parametrize('keystr, expected', [ ('<Ctrl-Alt-y>', keyutils.KeySequence(Qt.ControlModifier | Qt.AltModifier | Qt.Key_Y)), ('x', keyutils.KeySequence(Qt.Key_X)), ('X', keyutils.KeySequence(Qt.ShiftModifier | Qt.Key_X)), ('<Escape>', keyutils.KeySequence(Qt.Key_Escape)), ('xyz', keyutils.KeySequence(Qt.Key_X, Qt.Key_Y, Qt.Key_Z)), ('<Control-x><Meta-y>', keyutils.KeySequence(Qt.ControlModifier | Qt.Key_X, Qt.MetaModifier | Qt.Key_Y)), ('<Shift-x>', keyutils.KeySequence(Qt.ShiftModifier | Qt.Key_X)), ('<Alt-x>', keyutils.KeySequence(Qt.AltModifier | Qt.Key_X)), ('<Control-x>', keyutils.KeySequence(Qt.ControlModifier | Qt.Key_X)), ('<Meta-x>', keyutils.KeySequence(Qt.MetaModifier | Qt.Key_X)), ('<Num-x>', keyutils.KeySequence(Qt.KeypadModifier | Qt.Key_X)), ('>', keyutils.KeySequence(Qt.Key_Greater)), ('<', keyutils.KeySequence(Qt.Key_Less)), ('a>', keyutils.KeySequence(Qt.Key_A, Qt.Key_Greater)), ('a<', keyutils.KeySequence(Qt.Key_A, Qt.Key_Less)), ('>a', keyutils.KeySequence(Qt.Key_Greater, Qt.Key_A)), ('<a', keyutils.KeySequence(Qt.Key_Less, Qt.Key_A)), ('<alt+greater>', keyutils.KeySequence(Qt.Key_Greater | Qt.AltModifier)), ('<alt+less>', keyutils.KeySequence(Qt.Key_Less | Qt.AltModifier)), ('<alt+<>', keyutils.KeyParseError), ('<alt+>>', keyutils.KeyParseError), ('<blub>', keyutils.KeyParseError), ('<>', keyutils.KeyParseError), ('\U00010000', keyutils.KeyParseError), ]) def test_parse(self, keystr, expected): if expected is keyutils.KeyParseError: with pytest.raises(keyutils.KeyParseError): keyutils.KeySequence.parse(keystr) else: assert keyutils.KeySequence.parse(keystr) == expected @hypothesis.given(strategies.text()) def test_parse_hypothesis(self, keystr): try: seq = keyutils.KeySequence.parse(keystr) except keyutils.KeyParseError: pass else: str(seq)