diff options
Diffstat (limited to 'src/plugins/platforms/android/qandroidinputcontext.cpp')
-rw-r--r-- | src/plugins/platforms/android/qandroidinputcontext.cpp | 133 |
1 files changed, 75 insertions, 58 deletions
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 687cced1e2..8a44482d44 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -95,6 +95,7 @@ private: static QAndroidInputContext *m_androidInputContext = 0; static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection"; static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText"; +static char const *const QtObjectType = "QDialog"; static jclass m_extractedTextClass = 0; static jmethodID m_classConstructorMethodID = 0; static jfieldID m_partialEndOffsetFieldID = 0; @@ -506,14 +507,19 @@ QAndroidInputContext::QAndroidInputContext() m_androidInputContext = this; QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged, - this, &QAndroidInputContext::updateInputItemRectangle); + this, &QAndroidInputContext::updateSelectionHandles); QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::anchorRectangleChanged, this, &QAndroidInputContext::updateSelectionHandles); QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::inputItemClipRectangleChanged, this, [this]{ auto im = qGuiApp->inputMethod(); if (!im->inputItemClipRectangle().contains(im->anchorRectangle()) || !im->inputItemClipRectangle().contains(im->cursorRectangle())) { - m_handleMode = Hidden; + // Undoes the hidden request if the only reason for the hidden is that + // X of the cursorRectangle or X of the anchorRectangle is less than 0. + const int rectX = im->inputItemClipRectangle().x(); + if (im->cursorRectangle().x() > rectX && im->anchorRectangle().x() > rectX) + m_handleMode = Hidden; + updateSelectionHandles(); } }); @@ -622,13 +628,13 @@ void QAndroidInputContext::updateSelectionHandles() if (noHandles) return; + QWindow *window = qGuiApp->focusWindow(); auto im = qGuiApp->inputMethod(); - if (!m_focusObject || ((m_handleMode & 0xff) == Hidden)) { + if (!m_focusObject || ((m_handleMode & 0xff) == Hidden) || !window) { // Hide the handles QtAndroidInput::updateHandles(Hidden); return; } - QWindow *window = qGuiApp->focusWindow(); double pixelDensity = window ? QHighDpiScaling::factor(window) : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); @@ -646,14 +652,25 @@ void QAndroidInputContext::updateSelectionHandles() } auto curRect = im->cursorRectangle(); - QPoint cursorPoint = qGuiApp->focusWindow()->mapToGlobal(QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height())); - QPoint editMenuPoint(cursorPoint.x(), cursorPoint.y()); + QPoint cursorPointGlobal = window->mapToGlobal(QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height())); + QPoint cursorPoint(curRect.center().x(), curRect.bottom()); + int x = curRect.x(); + int y = curRect.y(); + + // Use x and y for the editMenuPoint from the cursorPointGlobal when the cursor is in the Dialog + if (cursorPointGlobal != cursorPoint) { + x = cursorPointGlobal.x(); + y = cursorPointGlobal.y(); + } + + QPoint editMenuPoint(x, y); m_handleMode &= ShowEditPopup; m_handleMode |= ShowCursor; uint32_t buttons = EditContext::PasteButton; if (!query.value(Qt::ImSurroundingText).toString().isEmpty()) buttons |= EditContext::SelectAllButton; - QtAndroidInput::updateHandles(m_handleMode, editMenuPoint * pixelDensity, buttons, cursorPoint * pixelDensity); + QtAndroidInput::updateHandles(m_handleMode, editMenuPoint * pixelDensity, buttons, + cursorPointGlobal * pixelDensity); // The VK is hidden, reset the timer if (m_hideCursorHandleTimer.isActive()) m_hideCursorHandleTimer.start(); @@ -666,10 +683,30 @@ void QAndroidInputContext::updateSelectionHandles() if (cpos > anchor) std::swap(leftRect, rightRect); - QPoint leftPoint(leftRect.bottomLeft().toPoint() * pixelDensity); - QPoint righPoint(rightRect.bottomRight().toPoint() * pixelDensity); - QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint() * pixelDensity); - QtAndroidInput::updateHandles(m_handleMode, editPoint, EditContext::AllButtons, leftPoint, righPoint, + // Move the left or right select handle to the center from the screen edge + // the select handle is close to or over the screen edge. Otherwise, the + // select handle might go out of the screen and it would be impossible to drag. + QPoint leftPoint(window->mapToGlobal(leftRect.bottomLeft().toPoint())); + QPoint rightPoint(window->mapToGlobal(rightRect.bottomRight().toPoint())); + static int m_selectHandleWidth = 0; + // For comparison, get the width of the handle. + // Only half of the width will protrude from the cursor on each side + if (m_selectHandleWidth == 0) + m_selectHandleWidth = QtAndroidInput::getSelectHandleWidth() / 2; + + int rightSideOfScreen = QtAndroid::androidPlatformIntegration()->screen()->availableGeometry().right(); + + // Check if handle will fit the screen on left side. If not, then move it closer to the center + if (leftPoint.x() <= m_selectHandleWidth) + leftPoint.setX(m_selectHandleWidth / pixelDensity); + + // Check if handle will fit the screen on right side. If not, then move it closer to the center + if (rightPoint.x() >= (rightSideOfScreen / pixelDensity) - m_selectHandleWidth) + rightPoint.setX((rightSideOfScreen / pixelDensity) - (m_selectHandleWidth / pixelDensity)); + + QPoint editPoint(window->mapToGlobal(leftRect.united(rightRect).topLeft().toPoint())); + QtAndroidInput::updateHandles(m_handleMode, editPoint * pixelDensity, EditContext::AllButtons, + leftPoint * pixelDensity, rightPoint * pixelDensity, query.value(Qt::ImCurrentSelection).toString().isRightToLeft()); m_hideCursorHandleTimer.stop(); } @@ -693,7 +730,17 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y) double pixelDensity = window ? QHighDpiScaling::factor(window) : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); - QPointF point(x / pixelDensity, y / pixelDensity); + auto object = m_focusObject->parent(); + int dialogMoveX = 0; + while (object) { + if (QString::compare(object->metaObject()->className(), + QtObjectType, Qt::CaseInsensitive) == 0) { + dialogMoveX += object->property("x").toInt(); + } + object = object->parent(); + }; + + QPointF point((x / pixelDensity) - dialogMoveX, y / pixelDensity); point.setY(point.y() - leftRect.width() / 2); QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition @@ -931,50 +978,12 @@ void QAndroidInputContext::showInputPanel() else m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition())); - QRect rect = cursorRect(); + QRect rect = inputItemRectangle(); QtAndroidInput::showSoftwareKeyboard(rect.left(), rect.top(), rect.width(), rect.height(), - inputItemRectangle().height(), query->value(Qt::ImHints).toUInt(), query->value(Qt::ImEnterKeyType).toUInt()); } -QRect QAndroidInputContext::cursorRect() -{ - QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); - // if single line, we do not want to mess with the editor's position, as we do not - // have to follow the cursor in vertical axis - if (query.isNull() - || (query->value(Qt::ImHints).toUInt() & Qt::ImhMultiLine) != Qt::ImhMultiLine) - return {}; - - auto im = qGuiApp->inputMethod(); - if (!im) - return {}; - - const auto cursorRect= im->cursorRectangle().toRect(); - QRect finalRect(inputItemRectangle()); - const QWindow *window = qGuiApp->focusWindow(); - const double pd = window - ? QHighDpiScaling::factor(window) - : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); - finalRect.setY(cursorRect.y() * pd); - finalRect.setHeight(cursorRect.height() * pd); - //fiddle a bit with vert margins, so the tracking rectangle is not too tight. - finalRect += QMargins(0, cursorRect.height() / 4, 0, cursorRect.height() / 4); - return finalRect; -} - -void QAndroidInputContext::updateInputItemRectangle() -{ - QRect rect = cursorRect(); - - if (!rect.isValid()) - return; - QtAndroidInput::updateInputItemRectangle(rect.left(), rect.top(), - rect.width(), rect.height()); - updateSelectionHandles(); -} - void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state) { if (state != Qt::ApplicationActive) @@ -1234,13 +1243,21 @@ bool QAndroidInputContext::focusObjectStopComposing() m_composingCursor = -1; - // Moving Qt's cursor to where the preedit cursor used to be - QList<QInputMethodEvent::Attribute> attributes; - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0)); - - QInputMethodEvent event(QString(), attributes); - event.setCommitString(m_composingText); - sendInputMethodEvent(&event); + { + // commit the composing test + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event(QString(), attributes); + event.setCommitString(m_composingText); + sendInputMethodEvent(&event); + } + { + // Moving Qt's cursor to where the preedit cursor used to be + QList<QInputMethodEvent::Attribute> attributes; + attributes.append( + QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0)); + QInputMethodEvent event(QString(), attributes); + sendInputMethodEvent(&event); + } return true; } |