|
@@ -0,0 +1,236 @@
|
|
|
|
+//============================================================================
|
|
|
|
+// INCLUDES
|
|
|
|
+//============================================================================
|
|
|
|
+#include "FreeVirtualKeyboardInputContext.h"
|
|
|
|
+
|
|
|
|
+#include <QDebug>
|
|
|
|
+#include <QEvent>
|
|
|
|
+#include <QGuiApplication>
|
|
|
|
+#include <QQmlEngine>
|
|
|
|
+#include <QQmlContext>
|
|
|
|
+#include <QVariant>
|
|
|
|
+#include <QQmlEngine>
|
|
|
|
+#include <QJSEngine>
|
|
|
|
+#include <QPropertyAnimation>
|
|
|
|
+
|
|
|
|
+#include <private/qquickflickable_p.h>
|
|
|
|
+#include "DeclarativeInputEngine.h"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Private data class for FreeVirtualKeyboardInputContext
|
|
|
|
+ */
|
|
|
|
+class FreeVirtualKeyboardInputContextPrivate
|
|
|
|
+{
|
|
|
|
+public:
|
|
|
|
+ FreeVirtualKeyboardInputContextPrivate();
|
|
|
|
+ QQuickFlickable* Flickable;
|
|
|
|
+ QQuickItem* FocusItem;
|
|
|
|
+ bool Visible;
|
|
|
|
+ DeclarativeInputEngine* InputEngine;
|
|
|
|
+ QPropertyAnimation* FlickableContentScrollAnimation;//< for smooth scrolling of flickable content item
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+FreeVirtualKeyboardInputContextPrivate::FreeVirtualKeyboardInputContextPrivate()
|
|
|
|
+ : Flickable(0),
|
|
|
|
+ FocusItem(0),
|
|
|
|
+ Visible(false),
|
|
|
|
+ InputEngine(new DeclarativeInputEngine())
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+FreeVirtualKeyboardInputContext::FreeVirtualKeyboardInputContext() :
|
|
|
|
+ QPlatformInputContext(), d(new FreeVirtualKeyboardInputContextPrivate)
|
|
|
|
+{
|
|
|
|
+ d->FlickableContentScrollAnimation = new QPropertyAnimation(this);
|
|
|
|
+ d->FlickableContentScrollAnimation->setPropertyName("contentY");
|
|
|
|
+ d->FlickableContentScrollAnimation->setDuration(400);
|
|
|
|
+ d->FlickableContentScrollAnimation->setEasingCurve(QEasingCurve(QEasingCurve::OutBack));
|
|
|
|
+ qmlRegisterSingletonType<DeclarativeInputEngine>("FreeVirtualKeyboard", 1, 0,
|
|
|
|
+ "InputEngine", inputEngineProvider);
|
|
|
|
+ connect(d->InputEngine, SIGNAL(animatingChanged()), this, SLOT(ensureFocusedObjectVisible()));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+FreeVirtualKeyboardInputContext::~FreeVirtualKeyboardInputContext()
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+FreeVirtualKeyboardInputContext* FreeVirtualKeyboardInputContext::instance()
|
|
|
|
+{
|
|
|
|
+ static FreeVirtualKeyboardInputContext* InputContextInstance = new FreeVirtualKeyboardInputContext;
|
|
|
|
+ return InputContextInstance;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+bool FreeVirtualKeyboardInputContext::isValid() const
|
|
|
|
+{
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+QRectF FreeVirtualKeyboardInputContext::keyboardRect() const
|
|
|
|
+{
|
|
|
|
+ return QRectF();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+void FreeVirtualKeyboardInputContext::showInputPanel()
|
|
|
|
+{
|
|
|
|
+ qDebug( "showInputPanel");
|
|
|
|
+ d->Visible = true;
|
|
|
|
+ QPlatformInputContext::showInputPanel();
|
|
|
|
+ emitInputPanelVisibleChanged();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+void FreeVirtualKeyboardInputContext::hideInputPanel()
|
|
|
|
+{
|
|
|
|
+ qDebug( "hideInputPanel");
|
|
|
|
+ d->Visible = false;
|
|
|
|
+ QPlatformInputContext::hideInputPanel();
|
|
|
|
+ emitInputPanelVisibleChanged();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+bool FreeVirtualKeyboardInputContext::isInputPanelVisible() const
|
|
|
|
+{
|
|
|
|
+ return d->Visible;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+bool FreeVirtualKeyboardInputContext::isAnimating() const
|
|
|
|
+{
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+void FreeVirtualKeyboardInputContext::setFocusObject(QObject *object)
|
|
|
|
+{
|
|
|
|
+ static const int NumericInputHints = Qt::ImhPreferNumbers | Qt::ImhDate
|
|
|
|
+ | Qt::ImhTime | Qt::ImhDigitsOnly | Qt::ImhFormattedNumbersOnly;
|
|
|
|
+ static const int DialableInputHints = Qt::ImhDialableCharactersOnly;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ qDebug() << "FreeVirtualKeyboardInputContext::setFocusObject";
|
|
|
|
+ if (!object)
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // we only support QML at the moment - so if this is not a QML item, then
|
|
|
|
+ // we leave immediatelly
|
|
|
|
+ d->FocusItem = dynamic_cast<QQuickItem*>(object);
|
|
|
|
+ if (!d->FocusItem)
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Check if an input control has focus that accepts text input - if not,
|
|
|
|
+ // then we can leave immediatelly
|
|
|
|
+ bool AcceptsInput = d->FocusItem->inputMethodQuery(Qt::ImEnabled).toBool();
|
|
|
|
+ if (!AcceptsInput)
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Set input mode depending on input method hints queried from focused
|
|
|
|
+ // object / item
|
|
|
|
+ Qt::InputMethodHints InputMethodHints(d->FocusItem->inputMethodQuery(Qt::ImHints).toInt());
|
|
|
|
+ qDebug() << QString("InputMethodHints: %1").arg(InputMethodHints, 0, 16);
|
|
|
|
+ if (InputMethodHints & DialableInputHints)
|
|
|
|
+ {
|
|
|
|
+ d->InputEngine->setInputMode(DeclarativeInputEngine::Dialable);
|
|
|
|
+ }
|
|
|
|
+ else if (InputMethodHints & NumericInputHints)
|
|
|
|
+ {
|
|
|
|
+ d->InputEngine->setInputMode(DeclarativeInputEngine::Numeric);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ d->InputEngine->setInputMode(DeclarativeInputEngine::Latin);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Search for the top most flickable so that we can scroll the control
|
|
|
|
+ // into the visible area, if the keyboard hides the control
|
|
|
|
+ QQuickItem* i = d->FocusItem;
|
|
|
|
+ d->Flickable = 0;
|
|
|
|
+ while (i)
|
|
|
|
+ {
|
|
|
|
+ QQuickFlickable* Flickable = dynamic_cast<QQuickFlickable*>(i);
|
|
|
|
+ if (Flickable)
|
|
|
|
+ {
|
|
|
|
+ d->Flickable = Flickable;
|
|
|
|
+ qDebug() << "is QQuickFlickable";
|
|
|
|
+ }
|
|
|
|
+ i = i->parentItem();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ensureFocusedObjectVisible();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+void FreeVirtualKeyboardInputContext::ensureFocusedObjectVisible()
|
|
|
|
+{
|
|
|
|
+ // If the keyboard is hidden, no scrollable element exists or the keyboard
|
|
|
|
+ // is just animating, then we leave here
|
|
|
|
+ if (!d->Visible || !d->Flickable || d->InputEngine->isAnimating())
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ qDebug() << "FreeVirtualKeyboardInputContext::ensureFocusedObjectVisible";
|
|
|
|
+ QRectF FocusItemRect(0, 0, d->FocusItem->width(), d->FocusItem->height());
|
|
|
|
+ FocusItemRect = d->Flickable->mapRectFromItem(d->FocusItem, FocusItemRect);
|
|
|
|
+ qDebug() << "FocusItemRect: " << FocusItemRect;
|
|
|
|
+ qDebug() << "Content origin: " << QPointF(d->Flickable->contentX(),
|
|
|
|
+ d->Flickable->contentY());
|
|
|
|
+ qDebug() << "Flickable size: " << QSize(d->Flickable->width(), d->Flickable->height());
|
|
|
|
+ d->FlickableContentScrollAnimation->setTargetObject(d->Flickable);
|
|
|
|
+ qreal ContentY = d->Flickable->contentY();
|
|
|
|
+ if (FocusItemRect.bottom() >= d->Flickable->height())
|
|
|
|
+ {
|
|
|
|
+ qDebug() << "Item outside!!! FocusItemRect.bottom() >= d->Flickable->height()";
|
|
|
|
+ ContentY = d->Flickable->contentY() + (FocusItemRect.bottom() - d->Flickable->height()) + 20;
|
|
|
|
+ d->FlickableContentScrollAnimation->setEndValue(ContentY);
|
|
|
|
+ d->FlickableContentScrollAnimation->start();
|
|
|
|
+ }
|
|
|
|
+ else if (FocusItemRect.top() < 0)
|
|
|
|
+ {
|
|
|
|
+ qDebug() << "Item outside!!! d->FocusItem->position().x < 0";
|
|
|
|
+ ContentY = d->Flickable->contentY() + FocusItemRect.top() - 20;
|
|
|
|
+ d->FlickableContentScrollAnimation->setEndValue(ContentY);
|
|
|
|
+ d->FlickableContentScrollAnimation->start();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//==============================================================================
|
|
|
|
+QObject* FreeVirtualKeyboardInputContext::inputEngineProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
|
|
|
+{
|
|
|
|
+ Q_UNUSED(engine)
|
|
|
|
+ Q_UNUSED(scriptEngine)
|
|
|
|
+ return FreeVirtualKeyboardInputContext::instance()->d->InputEngine;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//------------------------------------------------------------------------------
|
|
|
|
+// EOF FreeVirtualKeyboardInpitContext.cpp
|
|
|
|
+
|