• Jarkko Koivikko's avatar
    Add full screen input mode for super wide screens · ad44e00c
    Jarkko Koivikko authored
    
    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: default avatarMitch Curtis <mitch.curtis@qt.io>
    ad44e00c
shadowinputcontext.cpp 9.67 KiB
/****************************************************************************
**
** 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)
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
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);
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} } } 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;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
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