diff options
author | Florian Bruhin <me@the-compiler.org> | 2019-09-11 12:14:31 +0200 |
---|---|---|
committer | Florian Bruhin <me@the-compiler.org> | 2019-09-11 12:14:31 +0200 |
commit | 2df9bf8e537c0196d9768e5d38d601c79c3aef3e (patch) | |
tree | 8aad4f26db1a3ad317dd25822c70fd8ce10b2e34 /qutebrowser/keyinput/keyutils.py | |
parent | 1c25bd11c141900de66dd9fea52dbbc45bc0cbe1 (diff) | |
parent | a86a47406157e4e09afea8a912dc983d2831b15c (diff) | |
download | qutebrowser-2df9bf8e537c0196d9768e5d38d601c79c3aef3e.tar.gz qutebrowser-2df9bf8e537c0196d9768e5d38d601c79c3aef3e.zip |
Merge remote-tracking branch 'origin/pr/4492'
Diffstat (limited to 'qutebrowser/keyinput/keyutils.py')
-rw-r--r-- | qutebrowser/keyinput/keyutils.py | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/qutebrowser/keyinput/keyutils.py b/qutebrowser/keyinput/keyutils.py index 95b270ea2..81e7f2e21 100644 --- a/qutebrowser/keyinput/keyutils.py +++ b/qutebrowser/keyinput/keyutils.py @@ -163,6 +163,15 @@ def _is_printable(key): return key <= 0xff and key not in [Qt.Key_Space, 0x0] +def _is_surrogate(key): + """Check if a codepoint is a UTF-16 surrogate. + + UTF-16 surrogates are a reserved range of Unicode from 0xd800 + to 0xd8ff, used to encode Unicode codepoints above the BMP + (Base Multilingual Plane)""" + return 0xd800 <= key <= 0xdfff + + def is_special(key, modifiers): """Check whether this key requires special key syntax.""" _assert_plain_key(key) @@ -182,6 +191,27 @@ def is_modifier_key(key): return key in _MODIFIER_MAP +def _remap_unicode(key, text): + """Work around QtKeyEvent's bad values for high codepoints. + + QKeyEvent handles higher unicode codepoints poorly (see + QTBUG-72776). It uses UTF-16 to handle key events, and for + higher codepoints that require UTF-16 surrogates (e.g. emoji + and some CJK characters), it sets the keycode to just the + upper half of the surrogate, which renders it useless, and + breaks UTF-8 encoding, causing crashes. So we detect this + case, and reassign the key code to be the full Unicode + codepoint, which we can recover from the text() property, + wihch has the full character.""" + if _is_surrogate(key): + if len(text) != 1: + raise KeyParseError(text, "Key had too many characters!") + else: + return ord(text[0]) + else: + return key + + def _check_valid_utf8(s, data): """Make sure the given string is valid UTF-8. @@ -317,7 +347,7 @@ class KeyInfo: @classmethod def from_event(cls, e): - return cls(e.key(), e.modifiers()) + return cls(_remap_unicode(e.key(), e.text()), e.modifiers()) def __str__(self): """Convert this KeyInfo to a meaningful name. @@ -525,7 +555,7 @@ class KeySequence: def append_event(self, ev): """Create a new KeySequence object with the given QKeyEvent added.""" - key = ev.key() + key = _remap_unicode(ev.key(), ev.text()) modifiers = ev.modifiers() _assert_plain_key(key) |