macOS: Don't pass on key event text for function keys when IM is disabled

On macOS function keys such F1-F16 and the arrow keys result in NSEvents
with a character in the 0xF700-0xF8FF range of the private use area:

 https://unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT

We used to filter these out for all key events sent from the platform
plugin (4dbce2a469), but this had the side effect of breaking the
Unicode Hex Input keyboard's ability to explicitly input these
characters.

As of 705665957b we started trusting the
macOS text input system on whether a key event should include text or
not, which fixed both the hex keyboard and Russian keyboard input when
the key included the ^⌥ modifiers.

Unfortunately this didn't account for the case of non-IM enabled input,
so we started sending key events with text for arrow and function keys.
And since Arial Unicode MS provides glyphs for these code points, we
would end up with confusing characters in input fields when pressing
the arrow keys.

In general a client can not assume that the text() of a QKeyEvent is
printable, and the logic to determine if a character should be filtered
out or not depends on the font matching, since all code points can in
theory have a font that provides a glyph for it, but since we know that
the function key range on macOS is not supposed to have associated
glyphs we filter them out explicitly.

Note that we only do this for non-IM enabled text input, and otherwise
leave it up to the macOS text input system to determine if a event
should result in text insertion or not.

Task-number: QTBUG-106393
Pick-to: 6.4 6.4.2
Change-Id: I5498fbedee21b0720c56e99b26924959ade897bf
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Tor Arne Vestbø 2022-12-02 14:48:14 +01:00
parent 0c5f1beddc
commit b2e5d54726

View File

@ -3,6 +3,33 @@
// This file is included from qnsview.mm, and only used to organize the code
/*
Determines if the text represents one of the "special keys" on macOS
As a legacy from OpenStep, macOS reserves the range 0xF700-0xF8FF of the
Unicode private use area for representing function keys on the keyboard:
http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT
https://developer.apple.com/documentation/appkit/nsevent/specialkey
These code points are not supposed to have any glyphs associated with them,
but since we can't guarantee that the system doesn't have a font that does
provide glyphs for this range (Arial Unicode MS e.g.) we need to filter
the text of our key events up front.
*/
static bool isSpecialKey(const QString &text)
{
if (text.length() != 1)
return false;
const char16_t unicode = text.at(0).unicode();
if (unicode >= 0xF700 && unicode <= 0xF8FF)
return true;
return false;
}
@implementation QNSView (Keys)
- (bool)handleKeyEvent:(NSEvent *)nsevent
@ -20,6 +47,8 @@
// otherwise by doCommandBySelector.
m_sendKeyEventWithoutText = false;
bool didInterpretKeyEvent = false;
if (keyEvent.type == QEvent::KeyPress) {
if (m_composingText.isEmpty()) {
@ -67,6 +96,7 @@
m_currentlyInterpretedKeyEvent = nsevent;
[self interpretKeyEvents:@[nsevent]];
m_currentlyInterpretedKeyEvent = 0;
didInterpretKeyEvent = true;
// If the last key we sent was dead, then pass the next
// key to the IM as well to complete composition.
@ -80,7 +110,9 @@
bool accepted = true;
if (m_sendKeyEvent && m_composingText.isEmpty()) {
KeyEvent keyEvent(nsevent);
if (m_sendKeyEventWithoutText)
// Trust text input system on whether to send the event with text or not,
// or otherwise apply heuristics to filter out private use symbols.
if (didInterpretKeyEvent ? m_sendKeyEventWithoutText : isSpecialKey(keyEvent.text))
keyEvent.text = {};
qCDebug(lcQpaKeys) << "Sending as" << keyEvent;
accepted = keyEvent.sendWindowSystemEvent(window);