parent
a7b6d179d4
commit
b88ac51d25
@ -147,10 +147,18 @@ class BaseKeyParser(QObject):
|
|||||||
return QKeySequence.NoMatch
|
return QKeySequence.NoMatch
|
||||||
|
|
||||||
# First, try a straightforward match
|
# First, try a straightforward match
|
||||||
|
self._debug_log("Trying simple match")
|
||||||
match, binding = self._match_key(sequence)
|
match, binding = self._match_key(sequence)
|
||||||
|
|
||||||
|
# Then try without optional modifiers
|
||||||
|
if match == QKeySequence.NoMatch:
|
||||||
|
self._debug_log("Trying match without modifiers")
|
||||||
|
sequence = sequence.strip_modifiers()
|
||||||
|
match, binding = self._match_key(sequence)
|
||||||
|
|
||||||
# If that doesn't match, try a key_mapping
|
# If that doesn't match, try a key_mapping
|
||||||
if match == QKeySequence.NoMatch:
|
if match == QKeySequence.NoMatch:
|
||||||
|
self._debug_log("Trying match with key_mappings")
|
||||||
mapped = sequence.with_mappings(config.val.bindings.key_mappings)
|
mapped = sequence.with_mappings(config.val.bindings.key_mappings)
|
||||||
if sequence != mapped:
|
if sequence != mapped:
|
||||||
self._debug_log("Mapped {} -> {}".format(
|
self._debug_log("Mapped {} -> {}".format(
|
||||||
@ -159,10 +167,12 @@ class BaseKeyParser(QObject):
|
|||||||
sequence = mapped
|
sequence = mapped
|
||||||
|
|
||||||
# If that doesn't match either, try treating it as count.
|
# If that doesn't match either, try treating it as count.
|
||||||
|
txt = str(sequence[-1]) # To account for sequences changed above.
|
||||||
if (match == QKeySequence.NoMatch and
|
if (match == QKeySequence.NoMatch and
|
||||||
txt.isdigit() and
|
txt.isdigit() and
|
||||||
self._supports_count and
|
self._supports_count and
|
||||||
not (not self._count and txt == '0')):
|
not (not self._count and txt == '0')):
|
||||||
|
self._debug_log("Trying match as count")
|
||||||
assert len(txt) == 1, txt
|
assert len(txt) == 1, txt
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
self._count += txt
|
self._count += txt
|
||||||
|
@ -510,6 +510,12 @@ class KeySequence:
|
|||||||
|
|
||||||
return self.__class__(*keys)
|
return self.__class__(*keys)
|
||||||
|
|
||||||
|
def strip_modifiers(self):
|
||||||
|
"""Strip optional modifiers from keys."""
|
||||||
|
modifiers = Qt.KeypadModifier
|
||||||
|
keys = [key & ~modifiers for key in self._iter_keys()]
|
||||||
|
return self.__class__(*keys)
|
||||||
|
|
||||||
def with_mappings(self, mappings):
|
def with_mappings(self, mappings):
|
||||||
"""Get a new KeySequence with the given mappings applied."""
|
"""Get a new KeySequence with the given mappings applied."""
|
||||||
keys = []
|
keys = []
|
||||||
|
@ -198,13 +198,34 @@ class TestHandle:
|
|||||||
keyparser.execute.assert_called_with('message-info ba', None)
|
keyparser.execute.assert_called_with('message-info ba', None)
|
||||||
assert not keyparser._sequence
|
assert not keyparser._sequence
|
||||||
|
|
||||||
@pytest.mark.parametrize('key, number', [(Qt.Key_0, 0), (Qt.Key_1, 1)])
|
@pytest.mark.parametrize('key, modifiers, number', [
|
||||||
def test_number_press(self, handle_text, keyparser, key, number):
|
(Qt.Key_0, Qt.NoModifier, 0),
|
||||||
handle_text(key)
|
(Qt.Key_1, Qt.NoModifier, 1),
|
||||||
|
(Qt.Key_1, Qt.KeypadModifier, 1),
|
||||||
|
])
|
||||||
|
def test_number_press(self, fake_keyevent, keyparser,
|
||||||
|
key, modifiers, number):
|
||||||
|
keyparser.handle(fake_keyevent(key, modifiers))
|
||||||
command = 'message-info {}'.format(number)
|
command = 'message-info {}'.format(number)
|
||||||
keyparser.execute.assert_called_once_with(command, None)
|
keyparser.execute.assert_called_once_with(command, None)
|
||||||
assert not keyparser._sequence
|
assert not keyparser._sequence
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('modifiers, text', [
|
||||||
|
(Qt.NoModifier, '2'),
|
||||||
|
(Qt.KeypadModifier, 'num-2'),
|
||||||
|
])
|
||||||
|
def test_number_press_keypad(self, fake_keyevent, keyparser, config_stub,
|
||||||
|
modifiers, text):
|
||||||
|
"""Make sure a <Num+2> binding overrides the 2 binding."""
|
||||||
|
config_stub.val.bindings.commands = {'normal': {
|
||||||
|
'2': 'message-info 2',
|
||||||
|
'<Num+2>': 'message-info num-2'}}
|
||||||
|
keyparser._read_config('normal')
|
||||||
|
keyparser.handle(fake_keyevent(Qt.Key_2, modifiers))
|
||||||
|
command = 'message-info {}'.format(text)
|
||||||
|
keyparser.execute.assert_called_once_with(command, None)
|
||||||
|
assert not keyparser._sequence
|
||||||
|
|
||||||
def test_umlauts(self, handle_text, keyparser, config_stub):
|
def test_umlauts(self, handle_text, keyparser, config_stub):
|
||||||
config_stub.val.bindings.commands = {'normal': {'ü': 'message-info ü'}}
|
config_stub.val.bindings.commands = {'normal': {'ü': 'message-info ü'}}
|
||||||
keyparser._read_config('normal')
|
keyparser._read_config('normal')
|
||||||
@ -215,6 +236,15 @@ class TestHandle:
|
|||||||
handle_text(Qt.Key_X)
|
handle_text(Qt.Key_X)
|
||||||
keyparser.execute.assert_called_once_with('message-info a', None)
|
keyparser.execute.assert_called_once_with('message-info a', None)
|
||||||
|
|
||||||
|
def test_mapping_keypad(self, config_stub, fake_keyevent, keyparser):
|
||||||
|
"""Make sure falling back to non-numpad keys works with mappings."""
|
||||||
|
config_stub.val.bindings.commands = {'normal': {'a': 'nop'}}
|
||||||
|
config_stub.val.bindings.key_mappings = {'1': 'a'}
|
||||||
|
keyparser._read_config('normal')
|
||||||
|
|
||||||
|
keyparser.handle(fake_keyevent(Qt.Key_1, Qt.KeypadModifier))
|
||||||
|
keyparser.execute.assert_called_once_with('nop', None)
|
||||||
|
|
||||||
def test_binding_and_mapping(self, config_stub, handle_text, keyparser):
|
def test_binding_and_mapping(self, config_stub, handle_text, keyparser):
|
||||||
"""with a conflicting binding/mapping, the binding should win."""
|
"""with a conflicting binding/mapping, the binding should win."""
|
||||||
handle_text(Qt.Key_B)
|
handle_text(Qt.Key_B)
|
||||||
@ -296,6 +326,15 @@ class TestCount:
|
|||||||
assert sig1.args == ('4',)
|
assert sig1.args == ('4',)
|
||||||
assert sig2.args == ('42',)
|
assert sig2.args == ('42',)
|
||||||
|
|
||||||
|
def test_numpad(self, fake_keyevent, keyparser):
|
||||||
|
"""Make sure we can enter a count via numpad."""
|
||||||
|
for key, modifiers in [(Qt.Key_4, Qt.KeypadModifier),
|
||||||
|
(Qt.Key_2, Qt.KeypadModifier),
|
||||||
|
(Qt.Key_B, Qt.NoModifier),
|
||||||
|
(Qt.Key_A, Qt.NoModifier)]:
|
||||||
|
keyparser.handle(fake_keyevent(key, modifiers))
|
||||||
|
keyparser.execute.assert_called_once_with('message-info ba', 42)
|
||||||
|
|
||||||
|
|
||||||
def test_clear_keystring(qtbot, keyparser):
|
def test_clear_keystring(qtbot, keyparser):
|
||||||
"""Test that the keystring is cleared and the signal is emitted."""
|
"""Test that the keystring is cleared and the signal is emitted."""
|
||||||
|
@ -377,6 +377,15 @@ class TestKeySequence:
|
|||||||
with pytest.raises(keyutils.KeyParseError):
|
with pytest.raises(keyutils.KeyParseError):
|
||||||
seq.append_event(event)
|
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):
|
def test_with_mappings(self):
|
||||||
seq = keyutils.KeySequence.parse('foobar')
|
seq = keyutils.KeySequence.parse('foobar')
|
||||||
mappings = {keyutils.KeySequence('b'): keyutils.KeySequence('t')}
|
mappings = {keyutils.KeySequence('b'): keyutils.KeySequence('t')}
|
||||||
|
Loading…
Reference in New Issue
Block a user