Android: Cleanup the threading handling
Make sure all the call that are coming from Android UI thread are delegate to Qt thread. Change-Id: Ice1a25d01d107d7221b88c65b96dc1459c7f77f0 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>bb10
parent
afeba6978f
commit
c6af7cf666
|
|
@ -98,6 +98,11 @@ static jfieldID m_selectionStartFieldID = 0;
|
|||
static jfieldID m_startOffsetFieldID = 0;
|
||||
static jfieldID m_textFieldID = 0;
|
||||
|
||||
static void runOnQtThread(const std::function<void()> &func)
|
||||
{
|
||||
QMetaObject::invokeMethod(m_androidInputContext, "safeCall", Qt::BlockingQueuedConnection, Q_ARG(std::function<void()>, func));
|
||||
}
|
||||
|
||||
static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
|
|
@ -106,10 +111,9 @@ static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@ BEGINBATCH");
|
||||
#endif
|
||||
|
||||
return m_androidInputContext->beginBatchEdit();
|
||||
|
||||
return JNI_TRUE;
|
||||
jboolean res;
|
||||
runOnQtThread([&res]{res = m_androidInputContext->beginBatchEdit();});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -121,9 +125,9 @@ static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
qDebug("@@@ ENDBATCH");
|
||||
#endif
|
||||
|
||||
return m_androidInputContext->endBatchEdit();
|
||||
|
||||
return JNI_TRUE;
|
||||
jboolean res;
|
||||
runOnQtThread([&res]{res = m_androidInputContext->endBatchEdit();});
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -140,7 +144,9 @@ static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint new
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ COMMIT" << str << newCursorPosition;
|
||||
#endif
|
||||
return m_androidInputContext->commitText(str, newCursorPosition);
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->commitText(str, newCursorPosition);});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint leftLength, jint rightLength)
|
||||
|
|
@ -151,7 +157,9 @@ static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint le
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ DELETE" << leftLength << rightLength;
|
||||
#endif
|
||||
return m_androidInputContext->deleteSurroundingText(leftLength, rightLength);
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->deleteSurroundingText(leftLength, rightLength);});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -162,7 +170,9 @@ static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@ FINISH");
|
||||
#endif
|
||||
return m_androidInputContext->finishComposingText();
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->finishComposingText();});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
|
||||
|
|
@ -170,7 +180,9 @@ static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
|
|||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
return m_androidInputContext->getCursorCapsMode(reqModes);
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->getCursorCapsMode(reqModes);});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars, int hintMaxLines, jint flags)
|
||||
|
|
@ -178,8 +190,8 @@ static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars,
|
|||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QAndroidInputContext::ExtractedText &extractedText =
|
||||
m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);
|
||||
QAndroidInputContext::ExtractedText extractedText;
|
||||
runOnQtThread([&]{extractedText = m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);});
|
||||
|
||||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1("0x") + QString::number(flags,16) << extractedText.text << "partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset << "sel:" << extractedText.selectionStart << extractedText.selectionEnd << "offset:" << extractedText.startOffset;
|
||||
|
|
@ -204,7 +216,8 @@ static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
|
|||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QString &text = m_androidInputContext->getSelectedText(flags);
|
||||
QString text;
|
||||
runOnQtThread([&]{text = m_androidInputContext->getSelectedText(flags);});
|
||||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ GETSEL" << text;
|
||||
#endif
|
||||
|
|
@ -218,7 +231,8 @@ static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, ji
|
|||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QString &text = m_androidInputContext->getTextAfterCursor(length, flags);
|
||||
QString text;
|
||||
runOnQtThread([&]{text = m_androidInputContext->getTextAfterCursor(length, flags);});
|
||||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ GETA" << length << text;
|
||||
#endif
|
||||
|
|
@ -230,7 +244,8 @@ static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, j
|
|||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QString &text = m_androidInputContext->getTextBeforeCursor(length, flags);
|
||||
QString text;
|
||||
runOnQtThread([&]{text = m_androidInputContext->getTextBeforeCursor(length, flags);});
|
||||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ GETB" << length << text;
|
||||
#endif
|
||||
|
|
@ -250,7 +265,9 @@ static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, ji
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ SET" << str << newCursorPosition;
|
||||
#endif
|
||||
return m_androidInputContext->setComposingText(str, newCursorPosition);
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->setComposingText(str, newCursorPosition);});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint end)
|
||||
|
|
@ -261,7 +278,9 @@ static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ SETR" << start << end;
|
||||
#endif
|
||||
return m_androidInputContext->setComposingRegion(start, end);
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->setComposingRegion(start, end);});
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -273,7 +292,10 @@ static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug() << "@@@ SETSEL" << start << end;
|
||||
#endif
|
||||
return m_androidInputContext->setSelection(start, end);
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->setSelection(start, end);});
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -284,7 +306,9 @@ static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@ SELALL");
|
||||
#endif
|
||||
return m_androidInputContext->selectAll();
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->selectAll();});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -295,7 +319,9 @@ static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@");
|
||||
#endif
|
||||
return m_androidInputContext->cut();
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->cut();});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -306,7 +332,9 @@ static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@");
|
||||
#endif
|
||||
return m_androidInputContext->copy();
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->copy();});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -317,7 +345,9 @@ static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@");
|
||||
#endif
|
||||
return m_androidInputContext->copyURL();
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->copyURL();});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -328,7 +358,9 @@ static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@ PASTE");
|
||||
#endif
|
||||
return m_androidInputContext->paste();
|
||||
jboolean res;
|
||||
runOnQtThread([&]{res = m_androidInputContext->paste();});
|
||||
return res;
|
||||
}
|
||||
|
||||
static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
|
|
@ -339,7 +371,8 @@ static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
|
|||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
qDebug("@@@ UPDATECURSORPOS");
|
||||
#endif
|
||||
m_androidInputContext->updateCursorPosition();
|
||||
|
||||
runOnQtThread([&]{m_androidInputContext->updateCursorPosition();});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -517,7 +550,7 @@ void QAndroidInputContext::reset()
|
|||
m_batchEditNestingLevel = 0;
|
||||
m_handleMode = Hidden;
|
||||
if (qGuiApp->focusObject()) {
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(Qt::ImEnabled);
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(Qt::ImEnabled);
|
||||
if (!query.isNull() && query->value(Qt::ImEnabled).toBool()) {
|
||||
QtAndroidInput::resetSoftwareKeyboard();
|
||||
return;
|
||||
|
|
@ -533,7 +566,7 @@ void QAndroidInputContext::commit()
|
|||
|
||||
void QAndroidInputContext::updateCursorPosition()
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) {
|
||||
const int cursorPos = getAbsoluteCursorPosition(query);
|
||||
const int composeLength = m_composingText.length();
|
||||
|
|
@ -629,8 +662,10 @@ void QAndroidInputContext::updateSelectionHandles()
|
|||
*/
|
||||
void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
|
||||
{
|
||||
if (m_batchEditNestingLevel.load() || m_blockUpdateSelection)
|
||||
if (m_batchEditNestingLevel.load() || m_blockUpdateSelection) {
|
||||
qWarning() << "QAndroidInputContext::handleLocationChanged returned";
|
||||
return;
|
||||
}
|
||||
|
||||
finishComposingText();
|
||||
|
||||
|
|
@ -710,7 +745,7 @@ void QAndroidInputContext::touchDown(int x, int y)
|
|||
// The VK will appear in a moment, stop the timer
|
||||
m_hideCursorHandleTimer.stop();
|
||||
finishComposingText();
|
||||
QMetaObject::invokeMethod(this, "updateSelectionHandles", Qt::QueuedConnection);
|
||||
updateSelectionHandles();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -748,7 +783,7 @@ void QAndroidInputContext::longPress(int x, int y)
|
|||
}
|
||||
if (cursor == anchor || cursor < 0 || cursor - anchor > 500) {
|
||||
m_handleMode = ShowCursor | ShowEditPopup;
|
||||
QMetaObject::invokeMethod(this, "updateSelectionHandles", Qt::QueuedConnection);
|
||||
updateSelectionHandles();
|
||||
return;
|
||||
}
|
||||
QList<QInputMethodEvent::Attribute> imAttributes;
|
||||
|
|
@ -758,7 +793,7 @@ void QAndroidInputContext::longPress(int x, int y)
|
|||
QGuiApplication::sendEvent(m_focusObject, &event);
|
||||
|
||||
m_handleMode = ShowSelection | ShowEditPopup;
|
||||
QMetaObject::invokeMethod(this, "updateSelectionHandles", Qt::QueuedConnection);
|
||||
updateSelectionHandles();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -783,7 +818,7 @@ void QAndroidInputContext::hideSelectionHandles()
|
|||
|
||||
void QAndroidInputContext::update(Qt::InputMethodQueries queries)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(queries);
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
|
||||
if (query.isNull())
|
||||
return;
|
||||
#warning TODO extract the needed data from query
|
||||
|
|
@ -815,7 +850,7 @@ void QAndroidInputContext::showInputPanel()
|
|||
connect(qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(showInputPanelLater(Qt::ApplicationState)));
|
||||
return;
|
||||
}
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return;
|
||||
|
||||
|
|
@ -839,6 +874,14 @@ void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state)
|
|||
showInputPanel();
|
||||
}
|
||||
|
||||
void QAndroidInputContext::safeCall(const std::function<void()> &func, Qt::ConnectionType conType)
|
||||
{
|
||||
if (qGuiApp->thread() == QThread::currentThread())
|
||||
func();
|
||||
else
|
||||
QMetaObject::invokeMethod(this, "safeCall", conType, Q_ARG(std::function<void()>, func));
|
||||
}
|
||||
|
||||
void QAndroidInputContext::hideInputPanel()
|
||||
{
|
||||
QtAndroidInput::hideSoftwareKeyboard();
|
||||
|
|
@ -900,12 +943,12 @@ jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPos
|
|||
ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true);
|
||||
QInputMethodEvent event;
|
||||
event.setCommitString(text);
|
||||
sendInputMethodEventThreadSafe(&event);
|
||||
sendInputMethodEvent(&event);
|
||||
clear();
|
||||
|
||||
// Qt has now put the cursor at the end of the text, corresponding to newCursorPosition == 1
|
||||
if (newCursorPosition != 1) {
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (!query.isNull()) {
|
||||
QList<QInputMethodEvent::Attribute> attributes;
|
||||
const int localPos = query->value(Qt::ImCursorPosition).toInt();
|
||||
|
|
@ -924,7 +967,7 @@ jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPos
|
|||
|
||||
jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return JNI_TRUE;
|
||||
|
||||
|
|
@ -938,7 +981,7 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right
|
|||
|
||||
QInputMethodEvent event;
|
||||
event.setCommitString(QString(), -leftLength, leftLength+rightLength);
|
||||
sendInputMethodEventThreadSafe(&event);
|
||||
sendInputMethodEvent(&event);
|
||||
clear();
|
||||
|
||||
return JNI_TRUE;
|
||||
|
|
@ -950,7 +993,7 @@ jboolean QAndroidInputContext::finishComposingText()
|
|||
if (m_composingText.isEmpty())
|
||||
return JNI_TRUE; // not composing
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return JNI_FALSE;
|
||||
|
||||
|
|
@ -963,7 +1006,7 @@ jboolean QAndroidInputContext::finishComposingText()
|
|||
|
||||
QInputMethodEvent event(QString(), attributes);
|
||||
event.setCommitString(m_composingText);
|
||||
sendInputMethodEventThreadSafe(&event);
|
||||
sendInputMethodEvent(&event);
|
||||
clear();
|
||||
|
||||
return JNI_TRUE;
|
||||
|
|
@ -972,7 +1015,7 @@ jboolean QAndroidInputContext::finishComposingText()
|
|||
jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
|
||||
{
|
||||
jint res = 0;
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return res;
|
||||
|
||||
|
|
@ -995,7 +1038,7 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
|
|||
// updateExtractedText(View, int, ExtractedText) whenever you call
|
||||
// updateSelection(View, int, int, int, int)." QTBUG-37980
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return m_extractedText;
|
||||
|
||||
|
|
@ -1040,7 +1083,7 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
|
|||
|
||||
QString QAndroidInputContext::getSelectedText(jint /*flags*/)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return QString();
|
||||
|
||||
|
|
@ -1050,13 +1093,13 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/)
|
|||
QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
|
||||
{
|
||||
//### the preedit text could theoretically be after the cursor
|
||||
QVariant textAfter = queryFocusObjectThreadSafe(Qt::ImTextAfterCursor, QVariant(length));
|
||||
QVariant textAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, QVariant(length));
|
||||
if (textAfter.isValid()) {
|
||||
return textAfter.toString().left(length);
|
||||
}
|
||||
|
||||
//compatibility code for old controls that do not implement the new API
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return QString();
|
||||
|
||||
|
|
@ -1070,12 +1113,12 @@ QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
|
|||
|
||||
QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
|
||||
{
|
||||
QVariant textBefore = queryFocusObjectThreadSafe(Qt::ImTextBeforeCursor, QVariant(length));
|
||||
QVariant textBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, QVariant(length));
|
||||
if (textBefore.isValid())
|
||||
return textBefore.toString().rightRef(length) + m_composingText;
|
||||
|
||||
//compatibility code for old controls that do not implement the new API
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return QString();
|
||||
|
||||
|
|
@ -1101,7 +1144,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
|
|||
|
||||
jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return JNI_FALSE;
|
||||
|
||||
|
|
@ -1123,7 +1166,7 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
|
|||
QVariant(underlined)));
|
||||
|
||||
QInputMethodEvent event(m_composingText, attributes);
|
||||
sendInputMethodEventThreadSafe(&event);
|
||||
sendInputMethodEvent(&event);
|
||||
|
||||
QMetaObject::invokeMethod(this, "keyDown");
|
||||
|
||||
|
|
@ -1147,7 +1190,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
|
|||
if (wasComposing)
|
||||
finishComposingText();
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return JNI_FALSE;
|
||||
|
||||
|
|
@ -1192,10 +1235,10 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
|
|||
|
||||
QInputMethodEvent event(m_composingText, attributes);
|
||||
event.setCommitString(QString(), relativeStart, length);
|
||||
sendInputMethodEventThreadSafe(&event);
|
||||
sendInputMethodEvent(&event);
|
||||
|
||||
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
|
||||
QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQuery();
|
||||
if (!query2.isNull()) {
|
||||
qDebug() << "Setting. Prev local cpos:" << localPos << "block pos:" <<blockPosition << "comp.start:" << m_composingTextStart << "rel.start:" << relativeStart << "len:" << length << "cpos attr:" << localPos - localStart;
|
||||
qDebug() << "New cursor pos" << getAbsoluteCursorPosition(query2);
|
||||
|
|
@ -1207,7 +1250,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
|
|||
|
||||
jboolean QAndroidInputContext::setSelection(jint start, jint end)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return JNI_FALSE;
|
||||
|
||||
|
|
@ -1238,7 +1281,7 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end)
|
|||
end - start));
|
||||
}
|
||||
QInputMethodEvent event(m_composingText, attributes);
|
||||
sendInputMethodEventThreadSafe(&event);
|
||||
sendInputMethodEvent(&event);
|
||||
updateCursorPosition();
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
|
@ -1292,65 +1335,24 @@ void QAndroidInputContext::sendShortcut(const QKeySequence &sequence)
|
|||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE QVariant QAndroidInputContext::queryFocusObjectUnsafe(Qt::InputMethodQuery query, QVariant argument)
|
||||
{
|
||||
return QInputMethod::queryFocusObject(query, argument);
|
||||
}
|
||||
|
||||
QVariant QAndroidInputContext::queryFocusObjectThreadSafe(Qt::InputMethodQuery query, QVariant argument)
|
||||
{
|
||||
QVariant retval;
|
||||
QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries) {
|
||||
if (!qGuiApp)
|
||||
return retval;
|
||||
const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
|
||||
if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
|
||||
return retval;
|
||||
AndroidDeadlockProtector protector;
|
||||
if (!inMainThread && !protector.acquire())
|
||||
return retval;
|
||||
return {};
|
||||
|
||||
QMetaObject::invokeMethod(this, "queryFocusObjectUnsafe",
|
||||
inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, retval),
|
||||
Q_ARG(Qt::InputMethodQuery, query),
|
||||
Q_ARG(QVariant, argument));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQueryThreadSafe(Qt::InputMethodQueries queries) {
|
||||
QSharedPointer<QInputMethodQueryEvent> retval;
|
||||
if (!qGuiApp)
|
||||
return QSharedPointer<QInputMethodQueryEvent>();
|
||||
const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
|
||||
if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
|
||||
return QSharedPointer<QInputMethodQueryEvent>();
|
||||
AndroidDeadlockProtector protector;
|
||||
if (!inMainThread && !protector.acquire())
|
||||
return QSharedPointer<QInputMethodQueryEvent>();
|
||||
|
||||
QInputMethodQueryEvent *queryEvent = 0;
|
||||
QMetaObject::invokeMethod(this, "focusObjectInputMethodQueryUnsafe",
|
||||
inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QInputMethodQueryEvent*, queryEvent),
|
||||
Q_ARG(Qt::InputMethodQueries, queries));
|
||||
|
||||
return QSharedPointer<QInputMethodQueryEvent>(queryEvent);
|
||||
}
|
||||
|
||||
QInputMethodQueryEvent *QAndroidInputContext::focusObjectInputMethodQueryUnsafe(Qt::InputMethodQueries queries)
|
||||
{
|
||||
QObject *focusObject = qGuiApp->focusObject();
|
||||
if (!focusObject)
|
||||
return 0;
|
||||
return {};
|
||||
|
||||
QInputMethodQueryEvent *ret = new QInputMethodQueryEvent(queries);
|
||||
QCoreApplication::sendEvent(focusObject, ret);
|
||||
return ret;
|
||||
return QSharedPointer<QInputMethodQueryEvent>(ret);
|
||||
}
|
||||
|
||||
void QAndroidInputContext::sendInputMethodEventUnsafe(QInputMethodEvent *event)
|
||||
void QAndroidInputContext::sendInputMethodEvent(QInputMethodEvent *event)
|
||||
{
|
||||
if (!qGuiApp)
|
||||
return;
|
||||
|
||||
QObject *focusObject = qGuiApp->focusObject();
|
||||
if (!focusObject)
|
||||
return;
|
||||
|
|
@ -1358,19 +1360,4 @@ void QAndroidInputContext::sendInputMethodEventUnsafe(QInputMethodEvent *event)
|
|||
QCoreApplication::sendEvent(focusObject, event);
|
||||
}
|
||||
|
||||
void QAndroidInputContext::sendInputMethodEventThreadSafe(QInputMethodEvent *event)
|
||||
{
|
||||
if (!qGuiApp)
|
||||
return;
|
||||
const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
|
||||
if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
|
||||
return;
|
||||
AndroidDeadlockProtector protector;
|
||||
if (!inMainThread && !protector.acquire())
|
||||
return;
|
||||
QMetaObject::invokeMethod(this, "sendInputMethodEventUnsafe",
|
||||
inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QInputMethodEvent*, event));
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#define ANDROIDINPUTCONTEXT_H
|
||||
|
||||
#include <qpa/qplatforminputcontext.h>
|
||||
#include <functional>
|
||||
#include <jni.h>
|
||||
#include <qevent.h>
|
||||
#include <QTimer>
|
||||
|
|
@ -135,6 +136,7 @@ public:
|
|||
jboolean paste();
|
||||
|
||||
public slots:
|
||||
void safeCall(const std::function<void()> &func, Qt::ConnectionType conType = Qt::BlockingQueuedConnection);
|
||||
void updateCursorPosition();
|
||||
void updateSelectionHandles();
|
||||
void handleLocationChanged(int handleId, int x, int y);
|
||||
|
|
@ -147,14 +149,8 @@ private slots:
|
|||
void showInputPanelLater(Qt::ApplicationState);
|
||||
|
||||
private:
|
||||
void sendInputMethodEventThreadSafe(QInputMethodEvent *event);
|
||||
Q_INVOKABLE void sendInputMethodEventUnsafe(QInputMethodEvent *event);
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQueryThreadSafe(Qt::InputMethodQueries queries = Qt::ImQueryAll);
|
||||
Q_INVOKABLE QInputMethodQueryEvent *focusObjectInputMethodQueryUnsafe(Qt::InputMethodQueries queries);
|
||||
|
||||
Q_INVOKABLE QVariant queryFocusObjectUnsafe(Qt::InputMethodQuery query, QVariant argument);
|
||||
QVariant queryFocusObjectThreadSafe(Qt::InputMethodQuery query, QVariant argument);
|
||||
void sendInputMethodEvent(QInputMethodEvent *event);
|
||||
QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
|
||||
|
||||
private:
|
||||
ExtractedText m_extractedText;
|
||||
|
|
|
|||
Loading…
Reference in New Issue