aboutsummaryrefslogtreecommitdiffstats
path: root/src/virtualkeyboard/shadowinputcontext.cpp
diff options
context:
space:
mode:
authorJarkko Koivikko <jarkko.koivikko@code-q.fi>2017-01-11 00:11:00 +0200
committerMitch Curtis <mitch.curtis@qt.io>2017-01-30 10:51:15 +0000
commitad44e00c0d01dea15358b98865623e8f11f295a8 (patch)
treeb3f61fa370e95cd58a0e3cbd9be2de03287c6d9b /src/virtualkeyboard/shadowinputcontext.cpp
parent3076d61bc6a8462559162ac4a529ab6a9ec183c4 (diff)
Add full screen input mode for super wide screens
In full screen mode the virtual keyboard replicates the contents of the focused input field to full screen input field located on top of keyboard. This mode can be activated by VirtualKeyboardSettings.fullScreenMode. [ChangeLog] Added full screen input mode for super wide screens. Change-Id: Ib2650c04767fb0945cc2bedc5b1801d254a15a41 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src/virtualkeyboard/shadowinputcontext.cpp')
-rw-r--r--src/virtualkeyboard/shadowinputcontext.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/virtualkeyboard/shadowinputcontext.cpp b/src/virtualkeyboard/shadowinputcontext.cpp
new file mode 100644
index 00000000..b350e249
--- /dev/null
+++ b/src/virtualkeyboard/shadowinputcontext.cpp
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "shadowinputcontext.h"
+#include "inputcontext.h"
+#include "virtualkeyboarddebug.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QGuiApplication>
+#include <QQuickItem>
+
+QT_BEGIN_NAMESPACE
+bool operator==(const QInputMethodEvent::Attribute &attribute1, const QInputMethodEvent::Attribute &attribute2);
+QT_END_NAMESPACE
+
+namespace QtVirtualKeyboard {
+
+class ShadowInputContextPrivate : public QObjectPrivate
+{
+public:
+ ShadowInputContextPrivate() :
+ QObjectPrivate(),
+ inputContext(0),
+ anchorRectIntersectsClipRect(false),
+ cursorRectIntersectsClipRect(false),
+ selectionControlVisible(false)
+ {
+ }
+
+ InputContext *inputContext;
+ QPointer<QObject> inputItem;
+ QString preeditText;
+ QList<QInputMethodEvent::Attribute> preeditTextAttributes;
+ QRectF anchorRectangle;
+ QRectF cursorRectangle;
+ bool anchorRectIntersectsClipRect;
+ bool cursorRectIntersectsClipRect;
+ bool selectionControlVisible;
+};
+
+ShadowInputContext::ShadowInputContext(QObject *parent) :
+ QObject(*new ShadowInputContextPrivate(), parent)
+{
+}
+
+void ShadowInputContext::setInputContext(InputContext *inputContext)
+{
+ Q_D(ShadowInputContext);
+ d->inputContext = inputContext;
+}
+
+QObject *ShadowInputContext::inputItem() const
+{
+ Q_D(const ShadowInputContext);
+ return d->inputItem.data();
+}
+
+void ShadowInputContext::setInputItem(QObject *inputItem)
+{
+ Q_D(ShadowInputContext);
+ if (d->inputItem != inputItem) {
+ d->inputItem = inputItem;
+ emit inputItemChanged();
+ update(Qt::ImQueryAll);
+ }
+}
+
+QRectF ShadowInputContext::anchorRectangle() const
+{
+ Q_D(const ShadowInputContext);
+ return d->anchorRectangle;
+}
+
+QRectF ShadowInputContext::cursorRectangle() const
+{
+ Q_D(const ShadowInputContext);
+ return d->cursorRectangle;
+}
+
+bool ShadowInputContext::anchorRectIntersectsClipRect() const
+{
+ Q_D(const ShadowInputContext);
+ return d->anchorRectIntersectsClipRect;
+}
+
+bool ShadowInputContext::cursorRectIntersectsClipRect() const
+{
+ Q_D(const ShadowInputContext);
+ return d->cursorRectIntersectsClipRect;
+}
+
+bool ShadowInputContext::selectionControlVisible() const
+{
+ Q_D(const ShadowInputContext);
+ return d->selectionControlVisible;
+}
+
+void ShadowInputContext::setSelectionOnFocusObject(const QPointF &anchorPos, const QPointF &cursorPos)
+{
+ Q_D(ShadowInputContext);
+ QObject *focus = d->inputItem;
+ if (!focus)
+ return;
+
+ QQuickItem *quickItem = qobject_cast<QQuickItem *>(d->inputItem);
+ bool success;
+ int anchor = queryFocusObject(Qt::ImCursorPosition, quickItem ? quickItem->mapFromScene(anchorPos) : anchorPos).toInt(&success);
+ if (success) {
+ int cursor = queryFocusObject(Qt::ImCursorPosition, quickItem ? quickItem->mapFromScene(cursorPos) : cursorPos).toInt(&success);
+ if (success) {
+ QList<QInputMethodEvent::Attribute> imAttributes;
+ imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant()));
+ QInputMethodEvent event(QString(), imAttributes);
+ QGuiApplication::sendEvent(QGuiApplication::focusObject(), &event);
+ }
+ }
+}
+
+void ShadowInputContext::updateSelectionProperties()
+{
+ Q_D(ShadowInputContext);
+ if (!d->inputItem)
+ return;
+
+ QInputMethodQueryEvent imQueryEvent(Qt::ImAnchorRectangle |
+ Qt::ImCursorRectangle |
+ Qt::ImInputItemClipRectangle);
+ QGuiApplication::sendEvent(d->inputItem, &imQueryEvent);
+ QQuickItem *quickItem = qobject_cast<QQuickItem *>(d->inputItem);
+ const QRectF anchorRect = imQueryEvent.value(Qt::ImAnchorRectangle).toRectF();
+ const QRectF cursorRect = imQueryEvent.value(Qt::ImCursorRectangle).toRectF();
+ const QRectF anchorRectangle = quickItem ? quickItem->mapRectToScene(anchorRect) : anchorRect;
+ const QRectF cursorRectangle = quickItem ? quickItem->mapRectToScene(cursorRect) : cursorRect;
+ const QRectF inputItemClipRect = imQueryEvent.value(Qt::ImInputItemClipRectangle).toRectF();
+ const bool anchorRectIntersectsClipRect = inputItemClipRect.intersects(anchorRect);
+ const bool cursorRectIntersectsClipRect = inputItemClipRect.intersects(cursorRect);
+ const bool selectionControlVisible = d->inputContext->selectionControlVisible();
+
+ const bool newAnchorRectangle = anchorRectangle != d->anchorRectangle;
+ const bool newCursorRectangle = cursorRectangle != d->cursorRectangle;
+ const bool newAnchorRectIntersectsClipRect = anchorRectIntersectsClipRect != d->anchorRectIntersectsClipRect;
+ const bool newCursorRectIntersectsClipRect = cursorRectIntersectsClipRect != d->cursorRectIntersectsClipRect;
+ const bool newSelectionControlVisible = selectionControlVisible != d->selectionControlVisible;
+
+ d->anchorRectangle = anchorRectangle;
+ d->cursorRectangle = cursorRectangle;
+ d->anchorRectIntersectsClipRect = anchorRectIntersectsClipRect;
+ d->cursorRectIntersectsClipRect = cursorRectIntersectsClipRect;
+ d->selectionControlVisible = selectionControlVisible;
+
+ if (newAnchorRectangle)
+ emit anchorRectangleChanged();
+ if (newCursorRectangle)
+ emit cursorRectangleChanged();
+ if (newAnchorRectIntersectsClipRect)
+ emit anchorRectIntersectsClipRectChanged();
+ if (newCursorRectIntersectsClipRect)
+ emit cursorRectIntersectsClipRectChanged();
+ if (newSelectionControlVisible)
+ emit selectionControlVisibleChanged();
+}
+
+void ShadowInputContext::update(Qt::InputMethodQueries queries)
+{
+ Q_UNUSED(queries)
+ Q_D(ShadowInputContext);
+ if (!d->inputItem)
+ return;
+
+ QInputMethodQueryEvent imQueryEvent(Qt::ImQueryInput);
+ QGuiApplication::sendEvent(d->inputItem, &imQueryEvent);
+
+ const QString surroundingText = imQueryEvent.value(Qt::ImSurroundingText).toString();
+ const int cursorPosition = imQueryEvent.value(Qt::ImCursorPosition).toInt();
+ const int anchorPosition = imQueryEvent.value(Qt::ImAnchorPosition).toInt();
+
+ const QString newSurroundingText = d->inputContext->surroundingText();
+ const int newCursorPosition = d->inputContext->cursorPosition();
+ const int newAnchorPosition = d->inputContext->anchorPosition();
+
+ bool updateSurroundingText = newSurroundingText != surroundingText;
+ bool updateSelection = newCursorPosition != cursorPosition || newAnchorPosition != anchorPosition;
+ if (updateSurroundingText || updateSelection) {
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
+ newAnchorPosition,
+ newCursorPosition - newAnchorPosition, QVariant()));
+ QInputMethodEvent inputEvent(QString(), attributes);
+ if (updateSurroundingText)
+ inputEvent.setCommitString(newSurroundingText, -cursorPosition, surroundingText.length());
+ QGuiApplication::sendEvent(d->inputItem, &inputEvent);
+ }
+
+ const QString newPreeditText = d->inputContext->preeditText();
+ const QList<QInputMethodEvent::Attribute> newPreeditAttributes = d->inputContext->preeditTextAttributes();
+ if (d->preeditText != newPreeditText || d->preeditTextAttributes != newPreeditAttributes) {
+ d->preeditText = newPreeditText;
+ d->preeditTextAttributes = newPreeditAttributes;
+ QInputMethodEvent inputEvent(d->preeditText, d->preeditTextAttributes);
+ QGuiApplication::sendEvent(d->inputItem, &inputEvent);
+ }
+
+ updateSelectionProperties();
+}
+
+QVariant ShadowInputContext::queryFocusObject(Qt::InputMethodQuery query, QVariant argument)
+{
+ Q_D(ShadowInputContext);
+ QVariant retval;
+ QObject *focusObject = d->inputItem;
+ 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);
+}
+
+} // namespace QtVirtualKeyboard