Extending the inputMethodQuery API

Currently, inputMethodQuery() only provides information about the
current paragraph. On some platforms, such as Android, the input method
needs information about the global cursor position, and more of the
surrounding text. Some queries need to pass parameters.

The current inputmethodQuery() implementation does not allow parameters to
be passed. Changing this would require new or modified virtual functions, which
is not possible until Qt 6. Therefore, a completely new mechanism is needed.

Change-Id: Ic64fd90198ade70aa0fa6fa5ad3867dfa7ed763c
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Paul Olav Tvete 2014-01-20 12:30:35 +01:00 committed by The Qt Project
parent 25e7fe1650
commit f8dbed1226
10 changed files with 93 additions and 7 deletions

View File

@ -1332,6 +1332,10 @@ public:
ImHints = 0x100,
ImPreferredLanguage = 0x200,
ImAbsolutePosition = 0x400,
ImTextBeforeCursor = 0x800,
ImTextAfterCursor = 0x1000,
ImPlatformData = 0x80000000,
ImQueryInput = ImCursorRectangle | ImCursorPosition | ImSurroundingText |
ImCurrentSelection | ImAnchorPosition,

View File

@ -2446,6 +2446,11 @@
\value ImHints The hints for input method on expected input. (See Qt::InputMethodHints)
\value ImPreferredLanguage The preferred input language.
\value ImPlatformData Platform specific data for input method.
\value ImAbsolutePosition The logical position of the cursor within the entire document.
\value ImTextBeforeCursor The plain text before the cursor. The widget can decide how much text to return,
but \b{must} not return an empty string unless the cursor is at the start of the document.
\value ImTextAfterCursor The plain text after the cursor. The widget can decide how much text to return,
but \b{must} not return an empty string unless the cursor is at the end of the document.
Masks:

View File

@ -45,6 +45,8 @@
#include <qtimer.h>
#include <qpa/qplatforminputcontext_p.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
/*!
@ -365,6 +367,29 @@ bool QInputMethodPrivate::objectAcceptsInputMethod(QObject *object)
return enabled;
}
/*!
Send \a query to the current focus object with parameters \a argument and return the result.
*/
QVariant QInputMethod::queryFocusObject(Qt::InputMethodQuery query, QVariant argument)
{
QVariant retval;
QObject *focusObject = qGuiApp->focusObject();
if (!focusObject)
return retval;
bool newMethodWorks = QMetaObject::invokeMethod(focusObject, "inputMethodQuery",
Qt::DirectConnection,
Q_RETURN_ARG(QVariant, retval),
Q_ARG(Qt::InputMethodQuery, query),
Q_ARG(QVariant, argument));
if (newMethodWorks)
return retval;
QInputMethodQueryEvent queryEvent(query);
QCoreApplication::sendEvent(focusObject, &queryEvent);
return queryEvent.value(query);
}
QT_END_NAMESPACE
#include "moc_qinputmethod.cpp"

View File

@ -50,6 +50,7 @@ class QInputMethodPrivate;
class QWindow;
class QRectF;
class QTransform;
class QInputMethodQueryEvent;
class Q_GUI_EXPORT QInputMethod : public QObject
{
@ -89,6 +90,8 @@ public:
QLocale locale() const;
Qt::LayoutDirection inputDirection() const;
static QVariant queryFocusObject(Qt::InputMethodQuery query, QVariant argument);
public Q_SLOTS:
void show();
void hide();

View File

@ -10316,7 +10316,7 @@ QVariant QGraphicsTextItem::inputMethodQuery(Qt::InputMethodQuery query) const
if (query == Qt::ImHints)
v = int(inputMethodHints());
else if (dd->control)
v = dd->control->inputMethodQuery(query);
v = dd->control->inputMethodQuery(query, QVariant());
if (v.type() == QVariant::RectF)
v = v.toRectF().translated(-dd->controlOffset());
else if (v.type() == QVariant::PointF)

View File

@ -2192,7 +2192,7 @@ QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
v = QWidget::inputMethodQuery(property);
break;
default:
v = d->control->inputMethodQuery(property);
v = d->control->inputMethodQuery(property, QVariant());
const QPoint offset(-d->horizontalOffset(), -0);
if (v.type() == QVariant::RectF)
v = v.toRectF().toRect().translated(offset);

View File

@ -1716,15 +1716,22 @@ void QTextEdit::scrollContentsBy(int dx, int dy)
/*!\reimp
*/
QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
{
return inputMethodQuery(property, QVariant());
}
/*!\internal
*/
QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const
{
Q_D(const QTextEdit);
QVariant v;
switch (property) {
switch (query) {
case Qt::ImHints:
v = QWidget::inputMethodQuery(property);
v = QWidget::inputMethodQuery(query);
break;
default:
v = d->control->inputMethodQuery(property);
v = d->control->inputMethodQuery(query, argument);
const QPoint offset(-d->horizontalOffset(), -d->verticalOffset());
if (v.type() == QVariant::RectF)
v = v.toRectF().toRect().translated(offset);

View File

@ -212,6 +212,7 @@ public:
void print(QPagedPaintDevice *printer) const;
QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
public Q_SLOTS:
void setFontPointSize(qreal s);

View File

@ -2024,7 +2024,7 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
emit q->microFocusChanged();
}
QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
{
Q_D(const QWidgetTextControl);
QTextBlock block = d->cursor.block();
@ -2043,6 +2043,47 @@ QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property) con
return QVariant(); // No limit.
case Qt::ImAnchorPosition:
return QVariant(d->cursor.anchor() - block.position());
case Qt::ImAbsolutePosition:
return QVariant(d->cursor.position());
case Qt::ImTextAfterCursor:
{
int maxLength = argument.isValid() ? argument.toInt() : 1024;
QTextCursor tmpCursor = d->cursor;
int localPos = d->cursor.position() - block.position();
QString result = block.text().mid(localPos);
while (result.length() < maxLength) {
int currentBlock = tmpCursor.blockNumber();
tmpCursor.movePosition(QTextCursor::NextBlock);
if (tmpCursor.blockNumber() == currentBlock)
break;
result += QLatin1Char('\n') + tmpCursor.block().text();
}
return QVariant(result);
}
case Qt::ImTextBeforeCursor:
{
int maxLength = argument.isValid() ? argument.toInt() : 1024;
QTextCursor tmpCursor = d->cursor;
int localPos = d->cursor.position() - block.position();
int numBlocks = 0;
int resultLen = localPos;
while (resultLen < maxLength) {
int currentBlock = tmpCursor.blockNumber();
tmpCursor.movePosition(QTextCursor::PreviousBlock);
if (tmpCursor.blockNumber() == currentBlock)
break;
numBlocks++;
resultLen += tmpCursor.block().length();
}
QString result;
while (numBlocks) {
result += tmpCursor.block().text() + QLatin1Char('\n');
tmpCursor.movePosition(QTextCursor::NextBlock);
--numBlocks;
}
result += block.text().mid(0,localPos);
return QVariant(result);
}
default:
return QVariant();
}

View File

@ -239,7 +239,7 @@ public:
void setFocus(bool focus, Qt::FocusReason = Qt::OtherFocusReason);
virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
virtual QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const;
virtual QMimeData *createMimeDataFromSelection() const;
virtual bool canInsertFromMimeData(const QMimeData *source) const;