diff options
Diffstat (limited to 'src/plugins/platforms/ios/qiosinputcontext.mm')
-rw-r--r-- | src/plugins/platforms/ios/qiosinputcontext.mm | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 68088540c6..237077400b 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -498,15 +498,32 @@ void QIOSInputContext::scrollToCursor() return; } - const int margin = 20; - QRectF translatedCursorPos = qApp->inputMethod()->cursorRectangle(); - translatedCursorPos.translate(focusView().qwindow->geometry().topLeft()); - - qreal keyboardY = [rootView convertRect:m_keyboardState.keyboardEndRect fromView:nil].origin.y; - int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y(); + QWindow *focusWindow = qApp->focusWindow(); + QRect cursorRect = qApp->inputMethod()->cursorRectangle().translated(focusWindow->geometry().topLeft()).toRect(); + if (cursorRect.isNull()) { + scroll(0); + return; + } - scroll((translatedCursorPos.bottomLeft().y() < keyboardY - margin) ? 0 - : qMin(rootView.bounds.size.height - keyboardY, translatedCursorPos.y() - statusBarY - margin)); + // Add some padding so that the cusor does not end up directly above the keyboard + static const int kCursorRectPadding = 20; + cursorRect.adjust(0, -kCursorRectPadding, 0, kCursorRectPadding); + + // We explicitly ask for the geometry of the screen instead of the availableGeometry, + // as we hide the statusbar when scrolling the screen, so the available geometry will + // include the space taken by the status bar at the moment. + QRect screenGeometry = focusWindow->screen()->geometry(); + QRect keyboardGeometry = QRectF::fromCGRect(m_keyboardState.keyboardEndRect).toRect(); + QRect availableGeometry = (QRegion(screenGeometry) - keyboardGeometry).boundingRect(); + + if (!availableGeometry.contains(cursorRect, true)) { + qImDebug() << "cursor rect" << cursorRect << "not fully within" << availableGeometry; + int scrollToCenter = -(availableGeometry.center() - cursorRect.center()).y(); + int scrollToBottom = focusWindow->screen()->geometry().bottom() - availableGeometry.bottom(); + scroll(qMin(scrollToCenter, scrollToBottom)); + } else { + scroll(0); + } } void QIOSInputContext::scroll(int y) @@ -519,6 +536,8 @@ void QIOSInputContext::scroll(int y) if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform)) return; + qImDebug() << "scrolling root view to y =" << -y; + QPointer<QIOSInputContext> self = this; [UIView animateWithDuration:m_keyboardState.animationDuration delay:0 options:(m_keyboardState.animationCurve << 16) | UIViewAnimationOptionBeginFromCurrentState @@ -631,11 +650,21 @@ void QIOSInputContext::focusWindowChanged(QWindow *focusWindow) */ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) { + qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject(); + + // Changes to the focus object should always result in a call to setFocusObject(), + // triggering a reset() which will update all the properties based on the new + // focus object. We try to detect code paths that fail this assertion and smooth + // over the situation by doing a manual update of the focus object. + if (qApp->focusObject() != m_imeState.focusObject && updatedProperties != Qt::ImQueryAll) { + qWarning() << "stale focus object" << m_imeState.focusObject << ", doing manual update"; + setFocusObject(qApp->focusObject()); + return; + } + // Mask for properties that we are interested in and see if any of them changed updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImEnterKeyType | Qt::ImPlatformData); - qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject(); - // Perform update first, so we can trust the value of inputMethodAccepted() Qt::InputMethodQueries changedProperties = m_imeState.update(updatedProperties); |