summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <git@the-compiler.org>2018-03-06 21:39:57 +0100
committerFlorian Bruhin <git@the-compiler.org>2018-03-06 21:39:57 +0100
commit0d94c17edc04ea67faf1956b33a15d6f2ffd1b98 (patch)
tree735679b55f10401dd0d0ce2eeb0a0cbe85f48544
parentdb7ccb04341afb1de5e86b7fd99be97cc7ea8bee (diff)
downloadqutebrowser-0d94c17edc04ea67faf1956b33a15d6f2ffd1b98.tar.gz
qutebrowser-0d94c17edc04ea67faf1956b33a15d6f2ffd1b98.zip
Apply key_mappings to KeySequences correctly
Fixes #3678
-rw-r--r--qutebrowser/keyinput/basekeyparser.py5
-rw-r--r--qutebrowser/keyinput/keyutils.py16
-rw-r--r--tests/unit/keyinput/test_basekeyparser.py8
-rw-r--r--tests/unit/keyinput/test_keyutils.py11
4 files changed, 37 insertions, 3 deletions
diff --git a/qutebrowser/keyinput/basekeyparser.py b/qutebrowser/keyinput/basekeyparser.py
index 33b49501d..6ebb0b464 100644
--- a/qutebrowser/keyinput/basekeyparser.py
+++ b/qutebrowser/keyinput/basekeyparser.py
@@ -155,9 +155,8 @@ class BaseKeyParser(QObject):
match, binding = self._match_key(sequence)
if match == QKeySequence.NoMatch:
- mappings = config.val.bindings.key_mappings
- mapped = mappings.get(sequence, None)
- if mapped is not None:
+ mapped = sequence.with_mappings(config.val.bindings.key_mappings)
+ if sequence != mapped:
self._debug_log("Mapped {} -> {}".format(
sequence, mapped))
match, binding = self._match_key(mapped)
diff --git a/qutebrowser/keyinput/keyutils.py b/qutebrowser/keyinput/keyutils.py
index 91d6a36a3..dfe4fb3ff 100644
--- a/qutebrowser/keyinput/keyutils.py
+++ b/qutebrowser/keyinput/keyutils.py
@@ -321,6 +321,10 @@ class KeyInfo:
"""Get a QKeyEvent from this KeyInfo."""
return QKeyEvent(typ, self.key, self.modifiers, self.text())
+ def to_int(self):
+ """Get the key as an integer (with key/modifiers)."""
+ return int(self.key) | int(self.modifiers)
+
class KeySequence:
@@ -495,6 +499,18 @@ class KeySequence:
return self.__class__(*keys)
+ def with_mappings(self, mappings):
+ """Get a new KeySequence with the given mappings applied."""
+ keys = []
+ for key in self._iter_keys():
+ key_seq = KeySequence(key)
+ if key_seq in mappings:
+ new_seq = mappings[key_seq]
+ assert len(new_seq) == 1
+ key = new_seq[0].to_int()
+ keys.append(key)
+ return self.__class__(*keys)
+
@classmethod
def parse(cls, keystr):
"""Parse a keystring like <Ctrl-x> or xyz and return a KeySequence."""
diff --git a/tests/unit/keyinput/test_basekeyparser.py b/tests/unit/keyinput/test_basekeyparser.py
index 662b1f82a..581d0b676 100644
--- a/tests/unit/keyinput/test_basekeyparser.py
+++ b/tests/unit/keyinput/test_basekeyparser.py
@@ -212,6 +212,14 @@ class TestHandle:
handle_text(Qt.Key_B)
assert not keyparser.execute.called
+ def test_mapping_in_key_chain(self, config_stub, handle_text, keyparser):
+ """A mapping should work even as part of a keychain."""
+ config_stub.val.bindings.commands = {'normal':
+ {'aa': 'message-info aa'}}
+ keyparser._read_config('normal')
+ handle_text(Qt.Key_A, Qt.Key_X)
+ keyparser.execute.assert_called_once_with('message-info aa', None)
+
def test_binding_with_shift(self, keyparser, fake_keyevent):
"""Simulate a binding which involves shift."""
for key, modifiers in [(Qt.Key_Y, Qt.NoModifier),
diff --git a/tests/unit/keyinput/test_keyutils.py b/tests/unit/keyinput/test_keyutils.py
index 11dd41b1f..0557b3c3f 100644
--- a/tests/unit/keyinput/test_keyutils.py
+++ b/tests/unit/keyinput/test_keyutils.py
@@ -377,6 +377,12 @@ class TestKeySequence:
with pytest.raises(keyutils.KeyParseError):
seq.append_event(event)
+ def test_with_mappings(self):
+ seq = keyutils.KeySequence.parse('foobar')
+ mappings = {keyutils.KeySequence('b'): keyutils.KeySequence('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)),
@@ -443,6 +449,11 @@ def test_key_info_to_event():
assert ev.text() == 'A'
+def test_key_info_to_int():
+ info = keyutils.KeyInfo(Qt.Key_A, Qt.ShiftModifier)
+ assert info.to_int() == Qt.Key_A | Qt.ShiftModifier
+
+
@pytest.mark.parametrize('key, printable', [
(Qt.Key_Control, False),
(Qt.Key_Escape, False),