Filter out ShortcutOverride events properly

Fixes #3419
This commit is contained in:
Florian Bruhin 2018-03-05 06:32:54 +01:00
parent 4ef5db1bc4
commit e01db79ce9
5 changed files with 51 additions and 27 deletions

View File

@ -99,6 +99,8 @@ Fixed
- QtWebEngine: `:follow-selected` should now work in more cases with Qt > 5.10.
- QtWebEngine: Incremental search now flickers less and doesn't move to the
second result when pressing Enter.
- QtWebEngine: Keys like `Ctrl-V` or `Shift-Insert` are now correctly
handled/filtered with Qt 5.10.
- QtWebKit: `:view-source` now displays a valid URL.
- URLs containing ampersands and other special chars are now shown
correctly when filtering them in the completion.

View File

@ -882,6 +882,7 @@ class EventFilter(QObject):
self._handlers = {
QEvent.KeyPress: self._handle_key_event,
QEvent.KeyRelease: self._handle_key_event,
QEvent.ShortcutOverride: self._handle_key_event,
}
def _handle_key_event(self, event):

View File

@ -114,7 +114,7 @@ class BaseKeyParser(QObject):
return (result, None)
def handle(self, e):
def handle(self, e, *, dry_run=False):
"""Handle a new keypress.
Separate the keypress into count/command, then check if it matches
@ -123,13 +123,16 @@ class BaseKeyParser(QObject):
Args:
e: the KeyPressEvent from Qt.
dry_run: Don't actually execute anything, only check whether there
would be a match.
Return:
A QKeySequence match.
"""
key = e.key()
txt = str(keyutils.KeyInfo.from_event(e))
self._debug_log("Got key: 0x{:x} / text: '{}'".format(key, txt))
self._debug_log("Got key: 0x{:x} / text: '{}' / dry_run {}".format(
key, txt, dry_run))
if keyutils.is_modifier_key(key):
self._debug_log("Ignoring, only modifier")
@ -138,33 +141,39 @@ class BaseKeyParser(QObject):
if (txt.isdigit() and self._supports_count and not
(not self._count and txt == '0')):
assert len(txt) == 1, txt
self._count += txt
if not dry_run:
self._count += txt
return QKeySequence.ExactMatch
self._sequence = self._sequence.append_event(e)
match, binding = self._match_key(self._sequence)
sequence = self._sequence.append_event(e)
match, binding = self._match_key(sequence)
if match == QKeySequence.NoMatch:
mappings = config.val.bindings.key_mappings
mapped = mappings.get(self._sequence, None)
mapped = mappings.get(sequence, None)
if mapped is not None:
self._debug_log("Mapped {} -> {}".format(
self._sequence, mapped))
sequence, mapped))
match, binding = self._match_key(mapped)
self._sequence = mapped
sequence = mapped
if dry_run:
return match
self._sequence = sequence
if match == QKeySequence.ExactMatch:
self._debug_log("Definitive match for '{}'.".format(
self._sequence))
sequence))
count = int(self._count) if self._count else None
self.clear_keystring()
self.execute(binding, count)
elif match == QKeySequence.PartialMatch:
self._debug_log("No match for '{}' (added {})".format(
self._sequence, txt))
self.keystring_updated.emit(self._count + str(self._sequence))
sequence, txt))
self.keystring_updated.emit(self._count + str(sequence))
elif match == QKeySequence.NoMatch:
self._debug_log("Giving up with '{}', no matches".format(
self._sequence))
sequence))
self.clear_keystring()
else:
raise utils.Unreachable("Invalid match value {!r}".format(match))

View File

@ -143,11 +143,12 @@ class ModeManager(QObject):
def __repr__(self):
return utils.get_repr(self, mode=self.mode)
def _eventFilter_keypress(self, event):
def _eventFilter_keypress(self, event, *, dry_run=False):
"""Handle filtering of KeyPress events.
Args:
event: The KeyPress to examine.
dry_run: Don't actually handle the key, only filter it.
Return:
True if event should be filtered, False otherwise.
@ -157,7 +158,7 @@ class ModeManager(QObject):
if curmode != usertypes.KeyMode.insert:
log.modes.debug("got keypress in mode {} - delegating to "
"{}".format(curmode, utils.qualname(parser)))
match = parser.handle(event)
match = parser.handle(event, dry_run=dry_run)
is_non_alnum = (
event.modifiers() not in [Qt.NoModifier, Qt.ShiftModifier] or
@ -173,17 +174,17 @@ class ModeManager(QObject):
else:
filter_this = True
if not filter_this:
if not filter_this and not dry_run:
self._releaseevents_to_pass.add(KeyEvent.from_event(event))
if curmode != usertypes.KeyMode.insert:
focus_widget = QApplication.instance().focusWidget()
log.modes.debug("match: {}, forward_unbound_keys: {}, "
"passthrough: {}, is_non_alnum: {} --> "
"filter: {} (focused: {!r})".format(
"passthrough: {}, is_non_alnum: {}, dry_run: {} "
"--> filter: {} (focused: {!r})".format(
match, forward_unbound_keys,
parser.passthrough, is_non_alnum, filter_this,
focus_widget))
parser.passthrough, is_non_alnum, dry_run,
filter_this, focus_widget))
return filter_this
def _eventFilter_keyrelease(self, event):
@ -320,6 +321,8 @@ class ModeManager(QObject):
handlers = {
QEvent.KeyPress: self._eventFilter_keypress,
QEvent.KeyRelease: self._eventFilter_keyrelease,
QEvent.ShortcutOverride:
functools.partial(self._eventFilter_keypress, dry_run=True),
}
handler = handlers[event.type()]
return handler(event)

View File

@ -59,11 +59,13 @@ class NormalKeyParser(keyparser.CommandKeyParser):
def __repr__(self):
return utils.get_repr(self)
def handle(self, e):
def handle(self, e, *, dry_run=False):
"""Override to abort if the key is a startchar.
Args:
e: the KeyPressEvent from Qt.
dry_run: Don't actually execute anything, only check whether there
would be a match.
Return:
A self.Match member.
@ -74,9 +76,9 @@ class NormalKeyParser(keyparser.CommandKeyParser):
"currently inhibited.".format(txt))
return QKeySequence.NoMatch
match = super().handle(e)
match = super().handle(e, dry_run=dry_run)
if match == QKeySequence.PartialMatch:
if match == QKeySequence.PartialMatch and not dry_run:
timeout = config.val.input.partial_timeout
if timeout != 0:
self._partial_timer.setInterval(timeout)
@ -198,16 +200,21 @@ class HintKeyParser(keyparser.CommandKeyParser):
self._last_press = LastPress.filtertext
return QKeySequence.ExactMatch
def handle(self, e):
def handle(self, e, *, dry_run=False):
"""Handle a new keypress and call the respective handlers.
Args:
e: the KeyPressEvent from Qt
dry_run: Don't actually execute anything, only check whether there
would be a match.
Returns:
True if the match has been handled, False otherwise.
"""
match = super().handle(e)
match = super().handle(e, dry_run=dry_run)
if dry_run:
return match
if match == QKeySequence.PartialMatch:
self._last_press = LastPress.keystring
elif match == QKeySequence.ExactMatch:
@ -267,17 +274,19 @@ class RegisterKeyParser(keyparser.CommandKeyParser):
self._mode = mode
self._read_config('register')
def handle(self, e):
def handle(self, e, *, dry_run=False):
"""Override handle to always match the next key and use the register.
Args:
e: the KeyPressEvent from Qt.
dry_run: Don't actually execute anything, only check whether there
would be a match.
Return:
True if event has been handled, False otherwise.
"""
match = super().handle(e)
if match:
match = super().handle(e, dry_run=dry_run)
if match or dry_run:
return match
if not keyutils.is_printable(e.key()):