Handle invalid keys coming from Qt

When pressing a key which doesn't exist as Qt.Key, we don't get Qt.Key_unknown
like we'd expect, but we get 0x0 instead...

Let's add that as a new "nil" key (to not conflict with None/unknown/zero/...)
and handle it appropriately.

This can be reproduced by doing:
setxkbmap -layout us,gr -option grp:alt_shift_toggle
and pressing Alt-Shift/Shift-Alt.
This commit is contained in:
Florian Bruhin 2018-03-05 15:36:51 +01:00
parent 52c280ec12
commit d1854eddaf
5 changed files with 35 additions and 5 deletions

View File

@ -145,7 +145,13 @@ class BaseKeyParser(QObject):
self._count += txt
return QKeySequence.ExactMatch
sequence = self._sequence.append_event(e)
try:
sequence = self._sequence.append_event(e)
except keyutils.KeyParseError as e:
self._debug_log("{} Aborting keychain.".format(e))
self.clear_keystring()
return QKeySequence.NoMatch
match, binding = self._match_key(sequence)
if match == QKeySequence.NoMatch:
mappings = config.val.bindings.key_mappings

View File

@ -39,7 +39,7 @@ _MODIFIER_MAP = {
def is_printable(key):
return key <= 0xff and key != Qt.Key_Space
return key <= 0xff and key not in [Qt.Key_Space, 0x0]
def is_modifier_key(key):
@ -126,6 +126,7 @@ def _key_to_string(key):
special_names[getattr(Qt, 'Key_' + k)] = v
except AttributeError:
pass
special_names[0x0] = 'nil'
if key in special_names:
return special_names[key]
@ -231,7 +232,7 @@ class KeyInfo:
modifiers &= ~_MODIFIER_MAP[self.key]
elif is_printable(self.key):
# "normal" binding
if not key_string:
if not key_string: # pragma: no cover
raise ValueError("Got empty string for key 0x{:x}!"
.format(self.key))
@ -371,6 +372,9 @@ class KeySequence:
if info.key == Qt.Key_unknown:
raise KeyParseError(keystr, "Got unknown key!")
for seq in self._sequences:
assert seq
def matches(self, other):
"""Check whether the given KeySequence matches with this one.
@ -428,6 +432,9 @@ class KeySequence:
key = ev.key()
modifiers = ev.modifiers()
if key == 0x0:
raise KeyParseError(None, "Got nil key!")
if modifiers & Qt.ShiftModifier and key == Qt.Key_Backtab:
key = Qt.Key_Tab

View File

@ -48,7 +48,8 @@ class Key:
qtest = attr.ib(True)
def __attrs_post_init__(self):
self.member = getattr(Qt, 'Key_' + self.attribute, None)
if self.attribute:
self.member = getattr(Qt, 'Key_' + self.attribute, None)
if self.name is None:
self.name = self.attribute
@ -585,4 +586,6 @@ KEYS = [
Key('CameraFocus', 'Camera Focus', qtest=False),
Key('unknown', 'Unknown', qtest=False),
# 0x0 is used by Qt for unknown keys...
Key(attribute='', name='nil', member=0x0, qtest=False),
]

View File

@ -182,6 +182,11 @@ class TestHandle:
keyparser.handle(fake_keyevent(Qt.Key_1), dry_run=True)
assert not keyparser._count
def test_invalid_key(self, fake_keyevent, keyparser):
keyparser.handle(fake_keyevent(Qt.Key_B))
keyparser.handle(fake_keyevent(0x0))
assert not keyparser._sequence
def test_valid_keychain(self, handle_text, keyparser):
# Press 'x' which is ignored because of no match
handle_text(Qt.Key_X,

View File

@ -182,7 +182,8 @@ class TestKeySequence:
with pytest.raises(keyutils.KeyParseError):
keyutils.KeySequence(Qt.Key_unknown)
def test_init_invalid(self):
@pytest.mark.parametrize('key', [0, -1])
def test_init_invalid(self, key):
with pytest.raises(AssertionError):
keyutils.KeySequence(-1)
@ -343,6 +344,13 @@ class TestKeySequence:
new = seq.append_event(event)
assert new == keyutils.KeySequence.parse(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)
@pytest.mark.parametrize('keystr, expected', [
('<Control-x>', keyutils.KeySequence(Qt.ControlModifier | Qt.Key_X)),
('<Meta-x>', keyutils.KeySequence(Qt.MetaModifier | Qt.Key_X)),
@ -405,6 +413,7 @@ def test_key_info_to_event():
(Qt.Key_Enter, False),
(Qt.Key_Space, False),
(Qt.Key_X | Qt.ControlModifier, False), # Wrong usage
(0x0, False), # Used by Qt for unknown keys
(Qt.Key_ydiaeresis, True),
(Qt.Key_X, True),