diff options
author | Piotr Mikolajczyk <piotr.mikolajczyk@qt.io> | 2020-12-18 10:51:30 +0100 |
---|---|---|
committer | Ville Voutilainen <ville.voutilainen@qt.io> | 2021-03-05 07:57:14 +0000 |
commit | 5c6b10c3cee5737dbc041d0463220898c8120807 (patch) | |
tree | aec06989da84711fa432899f84cd0adba9323e82 /src/plugins/platforms/android | |
parent | 9fb81fc28774cd4aa01a8b29d59150e1a7de8fd8 (diff) |
Android: Place cursor correctly on screen when editing
When editing text the cursor is not placed correctly. So this
has been achieved by tricking Android into thinking that the
input area is only the line where the cursor is, so it is
forced to keep it on screen.
Fixes: QTBUG-91073
Pick-to: 5.15
Change-Id: Icc2e8315deb76ca1a84819d3fdceaa7b027b1174
Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
Diffstat (limited to 'src/plugins/platforms/android')
4 files changed, 60 insertions, 6 deletions
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 1de25b2857..d720f1a317 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -79,15 +79,16 @@ namespace QtAndroidInput candidatesEnd); } - void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType) + void showSoftwareKeyboard(int left, int top, int width, int height, int editorHeight, int inputHints, int enterKeyType) { QJniObject::callStaticMethod<void>(applicationClass(), "showSoftwareKeyboard", - "(IIIIII)V", + "(IIIIIII)V", left, top, width, height, + editorHeight, inputHints, enterKeyType); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL @@ -129,6 +130,17 @@ namespace QtAndroidInput anchor.x(), anchor.y(), rtl); } + void updateInputItemRectangle(int left, int top, int width, int height) + { + QJniObject::callStaticMethod<void>(applicationClass(), + "updateInputItemRectangle", + "(IIII)V", + left, + top, + width, + height); + } + static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) { if (m_ignoreMouseEvents) diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h index 9e75f43a83..7a93e0214c 100644 --- a/src/plugins/platforms/android/androidjniinput.h +++ b/src/plugins/platforms/android/androidjniinput.h @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE namespace QtAndroidInput { // Software keyboard support - void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints, int enterKeyType); + void showSoftwareKeyboard(int top, int left, int width, int editorHeight, int height, int inputHints, int enterKeyType); void resetSoftwareKeyboard(); void hideSoftwareKeyboard(); bool isSoftwareKeyboardVisible(); @@ -57,6 +57,8 @@ namespace QtAndroidInput void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd); // Software keyboard support + // edit field resize + void updateInputItemRectangle(int left, int top, int width, int height); // cursor/selection handles void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false); diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 29236667d3..378dfa03c8 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -47,6 +47,7 @@ #include "qandroideventdispatcher.h" #include "qandroidinputcontext.h" #include "qandroidplatformintegration.h" +#include "private/qhighdpiscaling_p.h" #include <QTextBoundaryFinder> #include <QTextCharFormat> @@ -59,7 +60,6 @@ #include <qthread.h> #include <qwindow.h> #include <qpa/qplatformwindow.h> - QT_BEGIN_NAMESPACE namespace { @@ -491,7 +491,7 @@ QAndroidInputContext::QAndroidInputContext() m_androidInputContext = this; QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged, - this, &QAndroidInputContext::updateSelectionHandles); + this, &QAndroidInputContext::updateInputItemRectangle); QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::anchorRectangleChanged, this, &QAndroidInputContext::updateSelectionHandles); QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::inputItemClipRectangleChanged, this, [this]{ @@ -889,12 +889,50 @@ void QAndroidInputContext::showInputPanel() else m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition())); - QRect rect = screenInputItemRectangle(); + QRect rect = cursorRect(); QtAndroidInput::showSoftwareKeyboard(rect.left(), rect.top(), rect.width(), rect.height(), + screenInputItemRectangle().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().toRect()); + 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) diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index e9bfb98e66..02a66c367a 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h @@ -138,6 +138,7 @@ public: public slots: void safeCall(const std::function<void()> &func, Qt::ConnectionType conType = Qt::BlockingQueuedConnection); void updateCursorPosition(); + void updateInputItemRectangle(); void updateSelectionHandles(); void handleLocationChanged(int handleId, int x, int y); void touchDown(int x, int y); @@ -154,6 +155,7 @@ private: bool focusObjectIsComposing() const; void focusObjectStartComposing(); bool focusObjectStopComposing(); + QRect cursorRect(); private: ExtractedText m_extractedText; |