diff options
Diffstat (limited to 'src/plugins/platforms/ios')
-rw-r--r-- | src/plugins/platforms/ios/qiosinputcontext.mm | 32 | ||||
-rw-r--r-- | src/plugins/platforms/ios/quiview.mm | 12 |
2 files changed, 37 insertions, 7 deletions
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 985eecdb1d..ac75367d7f 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -160,7 +160,7 @@ static QUIView *focusView() return; // Enable hide-keyboard gesture - self.enabled = YES; + self.enabled = m_context->isInputPanelVisible(); m_context->scrollToCursor(); } @@ -402,7 +402,7 @@ void QIOSInputContext::updateKeyboardState(NSNotification *notification) // The isInputPanelVisible() property is based on whether or not the virtual keyboard // is visible on screen, and does not follow the logic of the iOS WillShow and WillHide // notifications which are not emitted for undocked keyboards, and are buggy when dealing - // with input-accesosory-views. The reason for using frameEnd here (the future state), + // with input-accessory-views. The reason for using frameEnd here (the future state), // instead of the current state reflected in frameBegin, is that QInputMethod::isVisible() // is documented to reflect the future state in the case of animated transitions. m_keyboardState.keyboardVisible = CGRectIntersectsRect(frameEnd, [UIScreen mainScreen].bounds); @@ -727,12 +727,34 @@ bool QIOSInputContext::inputMethodAccepted() const */ void QIOSInputContext::reset() { - qImDebug("updating Qt::ImQueryAll and unmarking text"); + qImDebug("releasing text responder"); + + // UIKit will sometimes, for unknown reasons, unset the input delegate on the + // current text responder. This seems to happen as a result of us calling + // [self.inputDelegate textDidChange:self] from [m_textResponder reset]. + // But it won't be set to nil directly, only after a character is typed on + // the input panel after the reset. This strange behavior seems to be related + // to us overriding [QUIView setInteraction] to ignore UITextInteraction. If we + // didn't do that, the delegate would be kept. But not overriding that function + // has its own share of issues, so it seems better to keep that way for now. + // Instead, we choose to recreate the text responder as a brute-force solution + // until we have better knowledge of what is going on (or implement the new + // UITextInteraction protocol). + const auto oldResponder = m_textResponder; + [m_textResponder setMarkedText:@"" selectedRange:NSMakeRange(0, 0)]; + [m_textResponder notifyInputDelegate:Qt::ImQueryInput]; + [m_textResponder autorelease]; + m_textResponder = nullptr; update(Qt::ImQueryAll); - [m_textResponder setMarkedText:@"" selectedRange:NSMakeRange(0, 0)]; - [m_textResponder notifyInputDelegate:Qt::ImQueryInput]; + // If update() didn't end up creating a new text responder, oldResponder will still be + // the first responder. In that case we need to resign it, so that the input panel hides. + // (the input panel will apparently not hide if the first responder is only released). + if ([oldResponder isFirstResponder]) { + qImDebug("IM not enabled, resigning autoreleased text responder as first responder"); + [oldResponder resignFirstResponder]; + } } /*! diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 6ff495ab85..9289cc68c9 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -465,7 +465,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>( self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); } else { - QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>( + // Send the touch event asynchronously, as the application might spin a recursive + // event loop in response to the touch event (a dialog e.g.), which will deadlock + // the UIKit event delivery system (QTBUG-98651). + QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>( self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); } } @@ -571,7 +574,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime]; QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); - QWindowSystemInterface::handleTouchCancelEvent(self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); + + // Send the touch event asynchronously, as the application might spin a recursive + // event loop in response to the touch event (a dialog e.g.), which will deadlock + // the UIKit event delivery system (QTBUG-98651). + QWindowSystemInterface::handleTouchCancelEvent<QWindowSystemInterface::AsynchronousDelivery>( + self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); } - (int)mapPressTypeToKey:(UIPress*)press |