summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-08-27 14:41:10 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-08-27 22:41:03 +0200
commit9e1875483ceaf907226f84cd6a58ab59f7f16f80 (patch)
treea2c0c1cc406c54147acc37f5886ebaea4186019f /src/plugins/platforms/cocoa
parent587d64507a0e419c089a83d0cf30026bf3b6bd20 (diff)
macOS: Assume input method handles key event
When input methods are enabled for the focus object we send key events through interpretKeyEvents, which will involve the input method in the key event processing. The input method will get back to us with callbacks such as insertText, setMarkedText, or doCommandBySelector. In the case of insertText, when the inserted text matches the originating key event's text, we opt to not send the text as an QInputMethodEvent, and instead fall back to sending it as a normal QKeyEvent. The reason for this is that Qt's IM protocol was designed to handle composited text, so sending non-composited (but IM-initiated) text input as IM events is unexpected (see 2d05d3bd2815c220474b3c07bf3f2ef7417d3070). However, we cannot assume that the input method will always call us back with one of the above mentioned methods. The input method can very well eat the event as part of its own operation. This happens for example when pressing and holding 'a' in a US English keyboard layout, which will pop up an input panel for the various accents available. Or it may happen when using the AquaSKK third party IM, which uses the 'l' key to switch the input mode to latin without producing any characters. To allow these input methods the freedom to control the processing of key events we need to reverse the logic for when we send key events as QKeyEvent. We now assume that the IM will handle the event, and only trigger QKeyEvent in two cases where we explicitly were called back by the IM, but decided that a QKeyEvent is needed: - If the IM calls insertText and we consider the text simple text - If the IM calls doCommandBySelector and we can't find a matching selector for the command. We only implement insertNewline and cancel, so in all other cases we want to pass on the key event to let the focus object handle it, for example for 'Select All' and similar key combinations. Fixes: QTBUG-46300 Fixes: QTBUG-71394 Pick-to: 6.2 Inspired-by: Vladimir Belyavsky Change-Id: I9a73a8e1baa2ebe0c5df1166a9ec3d9843632bb1 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/qnsview_complextext.mm19
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm8
2 files changed, 15 insertions, 12 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm
index 3a494701e1..3fcc0f23fa 100644
--- a/src/plugins/platforms/cocoa/qnsview_complextext.mm
+++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm
@@ -68,7 +68,7 @@
qCDebug(lcQpaKeys).nospace() << "Inserting \"" << text << "\""
<< ", replacing range " << replacementRange;
- if (m_sendKeyEvent && m_composingText.isEmpty()) {
+ if (m_composingText.isEmpty()) {
// The input method may have transformed the incoming key event
// to text that doesn't match what the original key event would
// have produced, for example when 'Pinyin - Simplified' does smart
@@ -83,6 +83,7 @@
// We do not send input method events for simple text input,
// and instead let handleKeyEvent send the key event.
qCDebug(lcQpaKeys) << "Ignoring text insertion for simple text";
+ m_sendKeyEvent = true;
return;
}
}
@@ -111,9 +112,6 @@
}
QCoreApplication::sendEvent(focusObject, &inputMethodEvent);
-
- // prevent handleKeyEvent from sending a key event
- m_sendKeyEvent = false;
}
m_composingText.clear();
@@ -153,8 +151,6 @@
newlineEvent.nativeVirtualKey = kVK_Return;
qCDebug(lcQpaKeys) << "Inserting newline via" << newlineEvent;
newlineEvent.sendWindowSystemEvent(m_platformWindow->window());
-
- m_sendKeyEvent = false;
}
// ------------- Text composition -------------
@@ -281,8 +277,6 @@
event.setCommitString(QString(), replaceFrom, replaceLength);
}
QCoreApplication::sendEvent(focusObject, &event);
- // prevent handleKeyEvent from sending a key event
- m_sendKeyEvent = false;
}
}
}
@@ -388,8 +382,15 @@
- (void)doCommandBySelector:(SEL)selector
{
+ // Note: if the selector cannot be invoked, then doCommandBySelector:
+ // should not pass this message up the responder chain (nor should it
+ // call super, as the NSResponder base class would in that case pass
+ // the message up the responder chain, which we don't want). We will
+ // pass the originating key event up the responder chain if applicable.
+
qCDebug(lcQpaKeys) << "Trying to perform command" << selector;
- [self tryToPerform:selector with:self];
+ if (![self tryToPerform:selector with:self])
+ m_sendKeyEvent = true;
}
// ------------- Various text properties -------------
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
index fb55612212..05f2421876 100644
--- a/src/plugins/platforms/cocoa/qnsview_keys.mm
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -55,7 +55,7 @@
window = popup->window();
}
- // We will send a key event unless the input method sets m_sendKeyEvent to false
+ // We will send a key event unless the input method handles it
QBoolBlocker sendKeyEventGuard(m_sendKeyEvent, true);
if (keyEvent.type == QEvent::KeyPress) {
@@ -84,8 +84,10 @@
const bool ignoreHidden = (hints & Qt::ImhHiddenText) && !isDeadKey && !m_lastKeyDead;
if (!(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || ignoreHidden)) {
- // Pass the key event to the input method. Note that m_sendKeyEvent may be set
- // to false during this call
+ // Pass the key event to the input method, and assume it handles the event,
+ // unless we explicit set m_sendKeyEvent to deliver as a normal key event.
+ m_sendKeyEvent = false;
+
qCDebug(lcQpaKeys) << "Interpreting key event for focus object" << focusObject;
m_currentlyInterpretedKeyEvent = nsevent;
[self interpretKeyEvents:@[nsevent]];