summaryrefslogtreecommitdiff
path: root/qutebrowser/keyinput/keyutils.py
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2019-09-11 12:14:31 +0200
committerFlorian Bruhin <me@the-compiler.org>2019-09-11 12:14:31 +0200
commit2df9bf8e537c0196d9768e5d38d601c79c3aef3e (patch)
tree8aad4f26db1a3ad317dd25822c70fd8ce10b2e34 /qutebrowser/keyinput/keyutils.py
parent1c25bd11c141900de66dd9fea52dbbc45bc0cbe1 (diff)
parenta86a47406157e4e09afea8a912dc983d2831b15c (diff)
downloadqutebrowser-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.py34
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)