aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/virtualkeyboard/basic/content/AutoScroller.qml2
-rw-r--r--src/plugin/plugin.cpp3
-rw-r--r--src/plugins/lipi-toolkit/plugin/lipiinputmethod.cpp3
-rw-r--r--src/virtualkeyboard/content/HandwritingInputPanel.qml2
-rw-r--r--src/virtualkeyboard/content/InputPanel.qml2
-rw-r--r--src/virtualkeyboard/content/components/EnterKey.qml6
-rw-r--r--src/virtualkeyboard/content/components/HideKeyboardKey.qml2
-rw-r--r--src/virtualkeyboard/content/components/Keyboard.qml47
-rw-r--r--src/virtualkeyboard/content/components/ShadowInputControl.qml10
-rw-r--r--src/virtualkeyboard/content/components/ShiftKey.qml4
-rw-r--r--src/virtualkeyboard/desktopinputpanel.cpp12
-rw-r--r--src/virtualkeyboard/desktopinputselectioncontrol.cpp5
-rw-r--r--src/virtualkeyboard/inputcontext.cpp749
-rw-r--r--src/virtualkeyboard/inputcontext.h64
-rw-r--r--src/virtualkeyboard/inputcontext_p.cpp540
-rw-r--r--src/virtualkeyboard/inputcontext_p.h173
-rw-r--r--src/virtualkeyboard/inputengine.cpp22
-rw-r--r--src/virtualkeyboard/inputengine.h2
-rw-r--r--src/virtualkeyboard/platforminputcontext.cpp23
-rw-r--r--src/virtualkeyboard/platforminputcontext_p.h1
-rw-r--r--src/virtualkeyboard/shifthandler.cpp119
-rw-r--r--src/virtualkeyboard/shifthandler_p.h14
-rw-r--r--src/virtualkeyboard/virtualkeyboard.pro2
-rw-r--r--tests/auto/inputpanel/data/inputpanel/inputpanel.qml14
24 files changed, 935 insertions, 886 deletions
diff --git a/examples/virtualkeyboard/basic/content/AutoScroller.qml b/examples/virtualkeyboard/basic/content/AutoScroller.qml
index 2ea8efb0..b6b7924f 100644
--- a/examples/virtualkeyboard/basic/content/AutoScroller.qml
+++ b/examples/virtualkeyboard/basic/content/AutoScroller.qml
@@ -34,7 +34,7 @@ Item {
property var innerFlickable
property var outerFlickable
- property var inputItem: InputContext.inputItem
+ property var inputItem: InputContext.priv.inputItem
onInputItemChanged: {
innerFlickable = null
diff --git a/src/plugin/plugin.cpp b/src/plugin/plugin.cpp
index 956bafbd..b07ba0ec 100644
--- a/src/plugin/plugin.cpp
+++ b/src/plugin/plugin.cpp
@@ -31,6 +31,7 @@
#include "extensionloader.h"
#include <QtVirtualKeyboard/inputcontext.h>
#include <QtVirtualKeyboard/inputengine.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
#include <QtVirtualKeyboard/private/shifthandler_p.h>
#include <QtVirtualKeyboard/private/plaininputmethod_p.h>
#include <QtVirtualKeyboard/private/inputmethod_p.h>
@@ -102,6 +103,8 @@ QPlatformInputContext *QVirtualKeyboardPlugin::create(const QString &system, con
qmlRegisterSingletonType<InputContext>(pluginUri, 1, 0, "InputContext", createInputContextModule);
qmlRegisterSingletonType<InputContext>(pluginUri, 2, 0, "InputContext", createInputContextModule);
+ qRegisterMetaType<InputContextPrivate *>("InputContextPrivate*");
+ qmlRegisterUncreatableType<InputContextPrivate>(pluginUri, 1, 0, "InputContextPrivate", QLatin1String("Cannot create input context private"));
qRegisterMetaType<InputEngine *>("InputEngine*");
qmlRegisterUncreatableType<InputEngine>(pluginUri, 1, 0, "InputEngine", QLatin1String("Cannot create input method engine"));
qmlRegisterUncreatableType<InputEngine>(pluginUri, 2, 0, "InputEngine", QLatin1String("Cannot create input method engine"));
diff --git a/src/plugins/lipi-toolkit/plugin/lipiinputmethod.cpp b/src/plugins/lipi-toolkit/plugin/lipiinputmethod.cpp
index 86877623..c6eb2157 100644
--- a/src/plugins/lipi-toolkit/plugin/lipiinputmethod.cpp
+++ b/src/plugins/lipi-toolkit/plugin/lipiinputmethod.cpp
@@ -31,6 +31,7 @@
#include "lipisharedrecognizer_p.h"
#include <QtVirtualKeyboard/inputengine.h>
#include <QtVirtualKeyboard/inputcontext.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
#include <QtVirtualKeyboard/private/shifthandler_p.h>
#include <QLoggingCategory>
#include <QtVirtualKeyboard/trace.h>
@@ -303,7 +304,7 @@ public:
} else if (swipeTouchCount == 2) {
// Double swipe: toggle text case
cancelRecognition();
- ic->shiftHandler()->toggleShift();
+ ic->priv()->shiftHandler()->toggleShift();
}
return;
}
diff --git a/src/virtualkeyboard/content/HandwritingInputPanel.qml b/src/virtualkeyboard/content/HandwritingInputPanel.qml
index 8582f721..67bf0706 100644
--- a/src/virtualkeyboard/content/HandwritingInputPanel.qml
+++ b/src/virtualkeyboard/content/HandwritingInputPanel.qml
@@ -110,7 +110,7 @@ Item {
}
Binding {
- target: InputContext
+ target: InputContext.priv
property: "keyboardRectangle"
value: Qt.rect(hwrInputArea.x, hwrInputArea.y, hwrInputArea.width, hwrInputArea.height)
when: handwritingInputPanel.enabled && handwritingInputPanel.available && handwritingInputPanel.active
diff --git a/src/virtualkeyboard/content/InputPanel.qml b/src/virtualkeyboard/content/InputPanel.qml
index e41756a7..ef900af4 100644
--- a/src/virtualkeyboard/content/InputPanel.qml
+++ b/src/virtualkeyboard/content/InputPanel.qml
@@ -135,7 +135,7 @@ Item {
}
Binding {
- target: InputContext
+ target: InputContext.priv
property: "keyboardRectangle"
value: mapToItem(null,
__isRootItem ? keyboard.x : x,
diff --git a/src/virtualkeyboard/content/components/EnterKey.qml b/src/virtualkeyboard/content/components/EnterKey.qml
index 74b3984c..9f7c04da 100644
--- a/src/virtualkeyboard/content/components/EnterKey.qml
+++ b/src/virtualkeyboard/content/components/EnterKey.qml
@@ -45,13 +45,13 @@ BaseKey {
/*! This property holds the action id for the enter key.
*/
- readonly property int actionId: InputContext.hasEnterKeyAction(InputContext.inputItem) ? InputContext.inputItem.EnterKeyAction.actionId : EnterKeyAction.None
+ readonly property int actionId: InputContext.priv.hasEnterKeyAction(InputContext.priv.inputItem) ? InputContext.priv.inputItem.EnterKeyAction.actionId : EnterKeyAction.None
text: "\n"
- displayText: InputContext.hasEnterKeyAction(InputContext.inputItem) ? InputContext.inputItem.EnterKeyAction.label : ""
+ displayText: InputContext.priv.hasEnterKeyAction(InputContext.priv.inputItem) ? InputContext.priv.inputItem.EnterKeyAction.label : ""
key: Qt.Key_Return
showPreview: false
highlighted: enabled && displayText.length > 0
- enabled: InputContext.hasEnterKeyAction(InputContext.inputItem) ? InputContext.inputItem.EnterKeyAction.enabled : true
+ enabled: InputContext.priv.hasEnterKeyAction(InputContext.priv.inputItem) ? InputContext.priv.inputItem.EnterKeyAction.enabled : true
keyPanelDelegate: keyboard.style ? keyboard.style.enterKeyPanel : undefined
}
diff --git a/src/virtualkeyboard/content/components/HideKeyboardKey.qml b/src/virtualkeyboard/content/components/HideKeyboardKey.qml
index e9de1002..ab38fbc2 100644
--- a/src/virtualkeyboard/content/components/HideKeyboardKey.qml
+++ b/src/virtualkeyboard/content/components/HideKeyboardKey.qml
@@ -43,6 +43,6 @@ import QtQuick.VirtualKeyboard 2.1
BaseKey {
functionKey: true
- onClicked: InputContext.hideInputPanel()
+ onClicked: InputContext.priv.hideInputPanel()
keyPanelDelegate: keyboard.style ? keyboard.style.hideKeyPanel : undefined
}
diff --git a/src/virtualkeyboard/content/components/Keyboard.qml b/src/virtualkeyboard/content/components/Keyboard.qml
index 47b096e7..1290502e 100644
--- a/src/virtualkeyboard/content/components/Keyboard.qml
+++ b/src/virtualkeyboard/content/components/Keyboard.qml
@@ -126,7 +126,7 @@ Item {
}
onInputLocaleChanged: {
if (Qt.locale(inputLocale).name !== "C")
- InputContext.locale = inputLocale
+ InputContext.priv.locale = inputLocale
}
onLayoutChanged: hideLanguagePopup()
onLayoutTypeChanged: {
@@ -150,17 +150,20 @@ Item {
Connections {
target: InputContext
+ onInputMethodHintsChanged: {
+ if (InputContext.priv.focus)
+ updateInputMethod()
+ }
+ }
+ Connections {
+ target: InputContext.priv
onInputItemChanged: {
keyboard.hideLanguagePopup()
if (active && symbolMode && !preferNumbers)
symbolMode = false
}
onFocusChanged: {
- if (InputContext.focus)
- updateInputMethod()
- }
- onInputMethodHintsChanged: {
- if (InputContext.focus)
+ if (InputContext.priv.focus)
updateInputMethod()
}
onNavigationKeyPressed: {
@@ -424,7 +427,7 @@ Item {
keyboard.symbolMode = false
} else if (key === Qt.Key_Space) {
var surroundingText = InputContext.surroundingText.trim()
- if (InputContext.shiftHandler.sentenceEndingCharacters.indexOf(surroundingText.charAt(surroundingText.length-1)) >= 0)
+ if (InputContext.priv.shiftHandler.sentenceEndingCharacters.indexOf(surroundingText.charAt(surroundingText.length-1)) >= 0)
keyboard.symbolMode = false
}
}
@@ -453,8 +456,8 @@ Item {
alternativeKeys.listView.height + verticalMargin * 2)
onVisibleChanged: {
if (visible)
- InputContext.previewRectangle = Qt.binding(function() {return previewRect})
- InputContext.previewVisible = visible
+ InputContext.priv.previewRectangle = Qt.binding(function() {return previewRect})
+ InputContext.priv.previewVisible = visible
}
}
Timer {
@@ -513,19 +516,19 @@ Item {
characterPreview.height)
}
Binding {
- target: InputContext
+ target: InputContext.priv
property: "previewRectangle"
value: characterPreview.previewRect
when: characterPreview.visible
}
Binding {
- target: InputContext
+ target: InputContext.priv
property: "previewRectangle"
value: languagePopupList.previewRect
when: languagePopupListActive
}
Binding {
- target: InputContext
+ target: InputContext.priv
property: "previewVisible"
value: characterPreview.visible || languagePopupListActive
}
@@ -622,7 +625,7 @@ Item {
SelectionControl {
objectName: "fullScreenModeSelectionControl"
- inputContext: InputContext.shadow
+ inputContext: InputContext.priv.shadow
anchors.top: shadowInputControl.top
anchors.left: shadowInputControl.left
enabled: keyboard.enabled && fullScreenMode
@@ -668,7 +671,7 @@ Item {
}
}
Connections {
- target: InputContext
+ target: InputContext.priv
onInputItemChanged: wordCandidateViewAutoHideTimer.stop()
}
Connections {
@@ -1278,7 +1281,7 @@ Item {
function updateInputMethod() {
if (!keyboardLayoutLoader.item)
return
- if (!InputContext.focus)
+ if (!InputContext.priv.focus)
return
// Reset the custom input method if it is not included in the list of shared layouts
@@ -1364,7 +1367,7 @@ Item {
}
// Clear the toggle shift timer
- InputContext.shiftHandler.clearToggleShiftTimer()
+ InputContext.priv.shiftHandler.clearToggleShiftTimer()
}
function updateLayout() {
@@ -1437,7 +1440,7 @@ Item {
newIndices.sort(function(a, b) { return a - b })
availableLocaleIndices = newIndices
newAvailableLocales.sort()
- InputContext.updateAvailableLocales(newAvailableLocales)
+ InputContext.priv.updateAvailableLocales(newAvailableLocales)
// Update list of custom locale indices
newIndices = []
@@ -1544,20 +1547,20 @@ Item {
}
function layoutExists(localeName, layoutType) {
- var result = InputContext.fileExists(getLayoutFile(localeName, layoutType))
+ var result = InputContext.priv.fileExists(getLayoutFile(localeName, layoutType))
if (!result && layoutType === "handwriting")
- result = InputContext.fileExists(getFallbackFile(localeName, layoutType))
+ result = InputContext.priv.fileExists(getFallbackFile(localeName, layoutType))
return result
}
function findLayout(localeName, layoutType) {
var layoutFile = getLayoutFile(localeName, layoutType)
- if (InputContext.fileExists(layoutFile))
+ if (InputContext.priv.fileExists(layoutFile))
return layoutFile
var fallbackFile = getFallbackFile(localeName, layoutType)
- if (InputContext.fileExists(fallbackFile)) {
+ if (InputContext.priv.fileExists(fallbackFile)) {
layoutFile = getLayoutFile("fallback", layoutType)
- if (InputContext.fileExists(layoutFile))
+ if (InputContext.priv.fileExists(layoutFile))
return layoutFile
}
return ""
diff --git a/src/virtualkeyboard/content/components/ShadowInputControl.qml b/src/virtualkeyboard/content/components/ShadowInputControl.qml
index b935d5c6..a059c40e 100644
--- a/src/virtualkeyboard/content/components/ShadowInputControl.qml
+++ b/src/virtualkeyboard/content/components/ShadowInputControl.qml
@@ -40,8 +40,8 @@ Item {
anchors.fill: parent
}
- onXChanged: InputContext.shadow.updateSelectionProperties()
- onYChanged: InputContext.shadow.updateSelectionProperties()
+ onXChanged: InputContext.priv.shadow.updateSelectionProperties()
+ onYChanged: InputContext.priv.shadow.updateSelectionProperties()
Loader {
sourceComponent: keyboard.style.fullScreenInputContainerBackground
@@ -61,7 +61,7 @@ Item {
flickableDirection: Flickable.HorizontalFlick
interactive: contentWidth > width
contentWidth: shadowInput.width
- onContentXChanged: InputContext.shadow.updateSelectionProperties()
+ onContentXChanged: InputContext.priv.shadow.updateSelectionProperties()
function ensureVisible(rectangle) {
if (contentX >= rectangle.x)
@@ -113,7 +113,7 @@ Item {
onTriggered: {
var anchorPosition = shadowInput.getAnchorPosition()
if (anchorPosition !== InputContext.anchorPosition || shadowInput.cursorPosition !== InputContext.cursorPosition)
- InputContext.forceCursorPosition(anchorPosition, shadowInput.cursorPosition)
+ InputContext.priv.forceCursorPosition(anchorPosition, shadowInput.cursorPosition)
}
}
@@ -130,7 +130,7 @@ Item {
}
Binding {
- target: InputContext.shadow
+ target: InputContext.priv.shadow
property: "inputItem"
value: shadowInput
when: VirtualKeyboardSettings.fullScreenMode
diff --git a/src/virtualkeyboard/content/components/ShiftKey.qml b/src/virtualkeyboard/content/components/ShiftKey.qml
index d7705d9f..93a1ae58 100644
--- a/src/virtualkeyboard/content/components/ShiftKey.qml
+++ b/src/virtualkeyboard/content/components/ShiftKey.qml
@@ -44,9 +44,9 @@ import QtQuick.VirtualKeyboard 2.1
BaseKey {
id: shiftKey
key: Qt.Key_Shift
- enabled: InputContext.shiftHandler.toggleShiftEnabled
+ enabled: InputContext.priv.shiftHandler.toggleShiftEnabled
highlighted: InputContext.capsLock
functionKey: true
keyPanelDelegate: keyboard.style ? keyboard.style.shiftKeyPanel : undefined
- onClicked: InputContext.shiftHandler.toggleShift()
+ onClicked: InputContext.priv.shiftHandler.toggleShift()
}
diff --git a/src/virtualkeyboard/desktopinputpanel.cpp b/src/virtualkeyboard/desktopinputpanel.cpp
index e299b59d..907e4e62 100644
--- a/src/virtualkeyboard/desktopinputpanel.cpp
+++ b/src/virtualkeyboard/desktopinputpanel.cpp
@@ -31,6 +31,7 @@
#include <QtVirtualKeyboard/private/appinputpanel_p_p.h>
#include <QtVirtualKeyboard/private/inputview_p.h>
#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
#include <QtVirtualKeyboard/inputcontext.h>
#include <QGuiApplication>
#include <QQmlEngine>
@@ -175,8 +176,9 @@ void DesktopInputPanel::repositionView(const QRect &rect)
if (inputContext) {
inputContext->setAnimating(true);
if (!d->previewBindingActive) {
- connect(inputContext, SIGNAL(previewRectangleChanged()), SLOT(previewRectangleChanged()));
- connect(inputContext, SIGNAL(previewVisibleChanged()), SLOT(previewVisibleChanged()));
+ InputContextPrivate *inputContextPrivate = inputContext->priv();
+ QObject::connect(inputContextPrivate, &InputContextPrivate::previewRectangleChanged, this, &DesktopInputPanel::previewRectangleChanged);
+ QObject::connect(inputContextPrivate, &InputContextPrivate::previewVisibleChanged, this, &DesktopInputPanel::previewVisibleChanged);
d->previewBindingActive = true;
}
}
@@ -201,7 +203,7 @@ void DesktopInputPanel::focusWindowVisibleChanged(bool visible)
if (!visible) {
InputContext *inputContext = qobject_cast<PlatformInputContext *>(parent())->inputContext();
if (inputContext)
- inputContext->hideInputPanel();
+ inputContext->priv()->hideInputPanel();
}
}
@@ -209,7 +211,7 @@ void DesktopInputPanel::previewRectangleChanged()
{
Q_D(DesktopInputPanel);
InputContext *inputContext = qobject_cast<PlatformInputContext *>(parent())->inputContext();
- d->previewRect = inputContext->previewRectangle();
+ d->previewRect = inputContext->priv()->previewRectangle();
if (d->previewVisible)
updateInputRegion();
}
@@ -218,7 +220,7 @@ void DesktopInputPanel::previewVisibleChanged()
{
Q_D(DesktopInputPanel);
InputContext *inputContext = qobject_cast<PlatformInputContext *>(parent())->inputContext();
- d->previewVisible = inputContext->previewVisible();
+ d->previewVisible = inputContext->priv()->previewVisible();
if (d->view->isVisible())
updateInputRegion();
}
diff --git a/src/virtualkeyboard/desktopinputselectioncontrol.cpp b/src/virtualkeyboard/desktopinputselectioncontrol.cpp
index f17b62b6..98dee491 100644
--- a/src/virtualkeyboard/desktopinputselectioncontrol.cpp
+++ b/src/virtualkeyboard/desktopinputselectioncontrol.cpp
@@ -29,6 +29,7 @@
#include <QtVirtualKeyboard/private/desktopinputselectioncontrol_p.h>
#include <QtVirtualKeyboard/inputcontext.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
#include <QtVirtualKeyboard/private/inputselectionhandle_p.h>
#include <QtVirtualKeyboard/private/settings_p.h>
#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
@@ -123,7 +124,7 @@ void DesktopInputSelectionControl::updateVisibility()
globalAnchorRectangle.moveTopLeft(tl);
m_anchorHandleVisible = m_anchorHandleVisible
&& m_inputContext->anchorRectIntersectsClipRect()
- && !(m_inputContext->keyboardRectangle().intersects(globalAnchorRectangle));
+ && !(m_inputContext->priv()->keyboardRectangle().intersects(globalAnchorRectangle));
}
if (wasAnchorVisible != m_anchorHandleVisible) {
@@ -142,7 +143,7 @@ void DesktopInputSelectionControl::updateVisibility()
globalCursorRectangle.moveTopLeft(tl);
m_cursorHandleVisible = m_cursorHandleVisible
&& m_inputContext->cursorRectIntersectsClipRect()
- && !(m_inputContext->keyboardRectangle().intersects(globalCursorRectangle));
+ && !(m_inputContext->priv()->keyboardRectangle().intersects(globalCursorRectangle));
}
diff --git a/src/virtualkeyboard/inputcontext.cpp b/src/virtualkeyboard/inputcontext.cpp
index 493f68e6..6c7774b0 100644
--- a/src/virtualkeyboard/inputcontext.cpp
+++ b/src/virtualkeyboard/inputcontext.cpp
@@ -28,27 +28,13 @@
****************************************************************************/
#include <QtVirtualKeyboard/inputcontext.h>
-#include <QtVirtualKeyboard/inputengine.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
#include <QtVirtualKeyboard/private/shifthandler_p.h>
#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
-#include <QtVirtualKeyboard/private/shadowinputcontext_p.h>
#include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h>
-#include <QtVirtualKeyboard/private/enterkeyaction_p.h>
-#include <QtVirtualKeyboard/private/settings_p.h>
#include <QTextFormat>
#include <QGuiApplication>
-#include <QtCore/private/qobject_p.h>
-
-QT_BEGIN_NAMESPACE
-
-bool operator==(const QInputMethodEvent::Attribute &attribute1, const QInputMethodEvent::Attribute &attribute2)
-{
- return attribute1.start == attribute2.start &&
- attribute1.length == attribute2.length &&
- attribute1.type == attribute2.type &&
- attribute1.value == attribute2.value;
-}
/*!
\namespace QtVirtualKeyboard
@@ -57,86 +43,9 @@ bool operator==(const QInputMethodEvent::Attribute &attribute1, const QInputMeth
\brief Namespace for the Qt Virtual Keyboard C++ API.
*/
+QT_BEGIN_NAMESPACE
namespace QtVirtualKeyboard {
-class InputContextPrivate : public QObjectPrivate
-{
-public:
- enum StateFlag {
- ReselectEventState = 0x1,
- InputMethodEventState = 0x2,
- KeyEventState = 0x4,
- InputMethodClickState = 0x8,
- SyncShadowInputState = 0x10
- };
- Q_DECLARE_FLAGS(StateFlags, StateFlag)
-
- InputContextPrivate() :
- QObjectPrivate(),
- inputContext(nullptr),
- inputEngine(nullptr),
- shiftHandler(nullptr),
- keyboardRect(),
- previewRect(),
- previewVisible(false),
- animating(false),
- focus(false),
- shift(false),
- capsLock(false),
- cursorPosition(0),
- anchorPosition(0),
- forceAnchorPosition(-1),
- forceCursorPosition(-1),
- inputMethodHints(Qt::ImhNone),
- preeditText(),
- preeditTextAttributes(),
- surroundingText(),
- selectedText(),
- anchorRectangle(),
- cursorRectangle(),
- selectionControlVisible(false),
- anchorRectIntersectsClipRect(false),
- cursorRectIntersectsClipRect(false)
-#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
- , activeNavigationKeys()
-#endif
- {
- }
-
- PlatformInputContext *inputContext;
- InputEngine *inputEngine;
- ShiftHandler *shiftHandler;
- QRectF keyboardRect;
- QRectF previewRect;
- bool previewVisible;
- bool animating;
- bool focus;
- bool shift;
- bool capsLock;
- StateFlags stateFlags;
- int cursorPosition;
- int anchorPosition;
- int forceAnchorPosition;
- int forceCursorPosition;
- Qt::InputMethodHints inputMethodHints;
- QString preeditText;
- QList<QInputMethodEvent::Attribute> preeditTextAttributes;
- QString surroundingText;
- QString selectedText;
- QRectF anchorRectangle;
- QRectF cursorRectangle;
- bool selectionControlVisible;
- bool anchorRectIntersectsClipRect;
- bool cursorRectIntersectsClipRect;
-#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
- QSet<int> activeNavigationKeys;
-#endif
- QSet<quint32> activeKeys;
- ShadowInputContext shadow;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(InputContextPrivate::StateFlags)
-
/*!
\qmltype InputContext
\instantiates QtVirtualKeyboard::InputContext
@@ -159,17 +68,14 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(InputContextPrivate::StateFlags)
context.
*/
InputContext::InputContext(PlatformInputContext *parent) :
- QObject(*new InputContextPrivate(), parent)
+ d_ptr(new InputContextPrivate(this, parent))
{
Q_D(InputContext);
- d->inputContext = parent;
- d->shadow.setInputContext(this);
- if (d->inputContext) {
- d->inputContext->setInputContext(this);
- connect(d->inputContext, SIGNAL(focusObjectChanged()), SLOT(onInputItemChanged()));
- }
- d->inputEngine = new InputEngine(this);
- d->shiftHandler = new ShiftHandler(this);
+ d->init();
+ QObject::connect(d->_shiftHandler, &ShiftHandler::shiftChanged, this, &InputContext::shiftChanged);
+ QObject::connect(d->_shiftHandler, &ShiftHandler::capsLockChanged, this, &InputContext::capsLockChanged);
+ QObject::connect(d->_shiftHandler, &ShiftHandler::uppercaseChanged, this, &InputContext::uppercaseChanged);
+ QObject::connect(d, &InputContextPrivate::localeChanged, this, &InputContext::localeChanged);
}
/*!
@@ -180,50 +86,22 @@ InputContext::~InputContext()
{
}
-bool InputContext::focus() const
-{
- Q_D(const InputContext);
- return d->focus;
-}
-
bool InputContext::shift() const
{
Q_D(const InputContext);
- return d->shift;
-}
-
-void InputContext::setShift(bool enable)
-{
- Q_D(InputContext);
- if (d->shift != enable) {
- d->shift = enable;
- emit shiftChanged();
- if (!d->capsLock)
- emit uppercaseChanged();
- }
+ return d->_shiftHandler->shift();
}
bool InputContext::capsLock() const
{
Q_D(const InputContext);
- return d->capsLock;
-}
-
-void InputContext::setCapsLock(bool enable)
-{
- Q_D(InputContext);
- if (d->capsLock != enable) {
- d->capsLock = enable;
- emit capsLockChanged();
- if (!d->shift)
- emit uppercaseChanged();
- }
+ return d->_shiftHandler->capsLock();
}
bool InputContext::uppercase() const
{
Q_D(const InputContext);
- return d->shift || d->capsLock;
+ return d->_shiftHandler->uppercase();
}
int InputContext::anchorPosition() const
@@ -255,16 +133,16 @@ void InputContext::setPreeditText(const QString &text, QList<QInputMethodEvent::
Q_D(InputContext);
// Add default attributes
if (!text.isEmpty()) {
- if (!testAttribute(attributes, QInputMethodEvent::TextFormat)) {
+ if (!d->testAttribute(attributes, QInputMethodEvent::TextFormat)) {
QTextCharFormat textFormat;
textFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, text.length(), textFormat));
}
- } else if (d->forceCursorPosition != -1) {
- addSelectionAttribute(attributes);
+ } else if (d->_forceCursorPosition != -1) {
+ d->addSelectionAttribute(attributes);
}
- sendPreedit(text, attributes, replaceFrom, replaceLength);
+ d->sendPreedit(text, attributes, replaceFrom, replaceLength);
}
QList<QInputMethodEvent::Attribute> InputContext::preeditTextAttributes() const
@@ -297,52 +175,6 @@ QRectF InputContext::cursorRectangle() const
return d->cursorRectangle;
}
-QRectF InputContext::keyboardRectangle() const
-{
- Q_D(const InputContext);
- return d->keyboardRect;
-}
-
-void InputContext::setKeyboardRectangle(QRectF rectangle)
-{
- Q_D(InputContext);
- if (d->keyboardRect != rectangle) {
- d->keyboardRect = rectangle;
- emit keyboardRectangleChanged();
- d->inputContext->emitKeyboardRectChanged();
- }
-}
-
-QRectF InputContext::previewRectangle() const
-{
- Q_D(const InputContext);
- return d->previewRect;
-}
-
-void InputContext::setPreviewRectangle(QRectF rectangle)
-{
- Q_D(InputContext);
- if (d->previewRect != rectangle) {
- d->previewRect = rectangle;
- emit previewRectangleChanged();
- }
-}
-
-bool InputContext::previewVisible() const
-{
- Q_D(const InputContext);
- return d->previewVisible;
-}
-
-void InputContext::setPreviewVisible(bool visible)
-{
- Q_D(InputContext);
- if (d->previewVisible != visible) {
- d->previewVisible = visible;
- emit previewVisibleChanged();
- }
-}
-
bool InputContext::animating() const
{
Q_D(const InputContext);
@@ -356,49 +188,14 @@ void InputContext::setAnimating(bool animating)
VIRTUALKEYBOARD_DEBUG() << "InputContext::setAnimating():" << animating;
d->animating = animating;
emit animatingChanged();
- d->inputContext->emitAnimatingChanged();
+ d->platformInputContext->emitAnimatingChanged();
}
}
-
QString InputContext::locale() const
{
Q_D(const InputContext);
- return d->inputContext->locale().name();
-}
-
-void InputContext::setLocale(const QString &locale)
-{
- Q_D(InputContext);
- VIRTUALKEYBOARD_DEBUG() << "InputContext::setLocale():" << locale;
- QLocale newLocale(locale);
- if (newLocale != d->inputContext->locale()) {
- d->inputContext->setLocale(newLocale);
- d->inputContext->setInputDirection(newLocale.textDirection());
- emit localeChanged();
- }
-}
-
-/*!
- \internal
-*/
-void InputContext::updateAvailableLocales(const QStringList &availableLocales)
-{
- Settings *settings = Settings::instance();
- if (settings)
- settings->setAvailableLocales(availableLocales);
-}
-
-QObject *InputContext::inputItem() const
-{
- Q_D(const InputContext);
- return d->inputContext ? d->inputContext->focusObject() : nullptr;
-}
-
-ShiftHandler *InputContext::shiftHandler() const
-{
- Q_D(const InputContext);
- return d->shiftHandler;
+ return d->locale();
}
InputEngine *InputContext::inputEngine() const
@@ -408,26 +205,6 @@ InputEngine *InputContext::inputEngine() const
}
/*!
- \qmlmethod void InputContext::hideInputPanel()
-
- This method hides the input panel. This method should only be called
- when the user initiates the hide, e.g. by pressing a dedicated button
- on the keyboard.
-*/
-/*!
- \fn void QtVirtualKeyboard::InputContext::hideInputPanel()
-
- This method hides the input panel. This method should only be called
- when the user initiates the hide, e.g. by pressing a dedicated button
- on the keyboard.
-*/
-void InputContext::hideInputPanel()
-{
- Q_D(InputContext);
- d->inputContext->hideInputPanel();
-}
-
-/*!
\qmlmethod void InputContext::sendKeyClick(int key, string text, int modifiers = 0)
Sends a key click event with the given \a key, \a text and \a modifiers to
@@ -440,14 +217,14 @@ void InputContext::hideInputPanel()
void InputContext::sendKeyClick(int key, const QString &text, int modifiers)
{
Q_D(InputContext);
- if (d->focus && d->inputContext) {
+ if (d->_focus && d->platformInputContext) {
QKeyEvent pressEvent(QEvent::KeyPress, key, Qt::KeyboardModifiers(modifiers), text);
QKeyEvent releaseEvent(QEvent::KeyRelease, key, Qt::KeyboardModifiers(modifiers), text);
VIRTUALKEYBOARD_DEBUG() << "InputContext::sendKeyClick():" << key;
d->stateFlags |= InputContextPrivate::KeyEventState;
- d->inputContext->sendKeyEvent(&pressEvent);
- d->inputContext->sendKeyEvent(&releaseEvent);
+ d->platformInputContext->sendKeyEvent(&pressEvent);
+ d->platformInputContext->sendKeyEvent(&releaseEvent);
if (d->activeKeys.isEmpty())
d->stateFlags &= ~InputContextPrivate::KeyEventState;
} else {
@@ -495,15 +272,15 @@ void InputContext::commit(const QString &text, int replaceFrom, int replaceLengt
VIRTUALKEYBOARD_DEBUG() << "InputContext::commit():" << text << replaceFrom << replaceLength;
bool preeditChanged = !d->preeditText.isEmpty();
- if (d->inputContext) {
+ if (d->platformInputContext) {
QList<QInputMethodEvent::Attribute> attributes;
- addSelectionAttribute(attributes);
+ d->addSelectionAttribute(attributes);
d->preeditText.clear();
d->preeditTextAttributes.clear();
QInputMethodEvent inputEvent(QString(), attributes);
inputEvent.setCommitString(text, replaceFrom, replaceLength);
d->stateFlags |= InputContextPrivate::InputMethodEventState;
- d->inputContext->sendEvent(&inputEvent);
+ d->platformInputContext->sendEvent(&inputEvent);
d->stateFlags &= ~InputContextPrivate::InputMethodEventState;
} else {
d->preeditText.clear();
@@ -531,12 +308,12 @@ void InputContext::clear()
d->preeditText.clear();
d->preeditTextAttributes.clear();
- if (d->inputContext) {
+ if (d->platformInputContext) {
QList<QInputMethodEvent::Attribute> attributes;
- addSelectionAttribute(attributes);
+ d->addSelectionAttribute(attributes);
QInputMethodEvent event(QString(), attributes);
d->stateFlags |= InputContextPrivate::InputMethodEventState;
- d->inputContext->sendEvent(&event);
+ d->platformInputContext->sendEvent(&event);
d->stateFlags &= ~InputContextPrivate::InputMethodEventState;
}
@@ -547,69 +324,11 @@ void InputContext::clear()
/*!
\internal
*/
-bool InputContext::fileExists(const QUrl &fileUrl)
-{
- QString fileName;
- if (fileUrl.scheme() == QLatin1String("qrc")) {
- fileName = QLatin1Char(':') + fileUrl.path();
- } else {
- fileName = fileUrl.toLocalFile();
- }
- return !fileName.isEmpty() && QFile::exists(fileName);
-}
-
-/*!
- \internal
-*/
-bool InputContext::hasEnterKeyAction(QObject *item) const
-{
- return item != nullptr && qmlAttachedPropertiesObject<EnterKeyAction>(item, false);
-}
-
-/*!
- \internal
-*/
void InputContext::setSelectionOnFocusObject(const QPointF &anchorPos, const QPointF &cursorPos)
{
QPlatformInputContext::setSelectionOnFocusObject(anchorPos, cursorPos);
}
-/*!
- \internal
-*/
-void InputContext::forceCursorPosition(int anchorPosition, int cursorPosition)
-{
- Q_D(InputContext);
- if (!d->shadow.inputItem())
- return;
- if (!d->inputContext->m_visible)
- return;
- if (d->stateFlags.testFlag(InputContextPrivate::ReselectEventState))
- return;
- if (d->stateFlags.testFlag(InputContextPrivate::SyncShadowInputState))
- return;
-
- VIRTUALKEYBOARD_DEBUG() << "InputContext::forceCursorPosition():" << cursorPosition << "anchorPosition:" << anchorPosition;
- if (!d->preeditText.isEmpty()) {
- d->forceAnchorPosition = -1;
- d->forceCursorPosition = cursorPosition;
- if (cursorPosition > d->cursorPosition)
- d->forceCursorPosition += d->preeditText.length();
- d->inputEngine->update();
- } else {
- d->forceAnchorPosition = anchorPosition;
- d->forceCursorPosition = cursorPosition;
- setPreeditText("");
- if (!d->inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
- cursorPosition > 0 && d->selectedText.isEmpty()) {
- d->stateFlags |= InputContextPrivate::ReselectEventState;
- if (d->inputEngine->reselect(cursorPosition, InputEngine::WordAtCursor))
- d->stateFlags |= InputContextPrivate::InputMethodClickState;
- d->stateFlags &= ~InputContextPrivate::ReselectEventState;
- }
- }
-}
-
bool InputContext::anchorRectIntersectsClipRect() const
{
Q_D(const InputContext);
@@ -628,334 +347,13 @@ bool InputContext::selectionControlVisible() const
return d->selectionControlVisible;
}
-ShadowInputContext *InputContext::shadow() const
+InputContextPrivate *InputContext::priv() const
{
Q_D(const InputContext);
- return const_cast<ShadowInputContext *>(&d->shadow);
-}
-
-void InputContext::onInputItemChanged()
-{
- Q_D(InputContext);
- if (!inputItem() && !d->activeKeys.isEmpty()) {
- // After losing keyboard focus it is impossible to track pressed keys
- d->activeKeys.clear();
- d->stateFlags &= ~InputContextPrivate::KeyEventState;
- }
- d->stateFlags &= ~InputContextPrivate::InputMethodClickState;
-
- emit inputItemChanged();
-}
-
-void InputContext::setFocus(bool enable)
-{
- Q_D(InputContext);
- if (d->focus != enable) {
- VIRTUALKEYBOARD_DEBUG() << "InputContext::setFocus():" << enable;
- d->focus = enable;
- emit focusChanged();
- }
- emit focusEditorChanged();
-}
-
-void InputContext::sendPreedit(const QString &text, const QList<QInputMethodEvent::Attribute> &attributes, int replaceFrom, int replaceLength)
-{
- Q_D(InputContext);
- VIRTUALKEYBOARD_DEBUG() << "InputContext::sendPreedit():" << text << replaceFrom << replaceLength;
-
- bool textChanged = d->preeditText != text;
- bool attributesChanged = d->preeditTextAttributes != attributes;
-
- if (textChanged || attributesChanged) {
- d->preeditText = text;
- d->preeditTextAttributes = attributes;
-
- if (d->inputContext) {
- QInputMethodEvent event(text, attributes);
- const bool replace = replaceFrom != 0 || replaceLength > 0;
- if (replace)
- event.setCommitString(QString(), replaceFrom, replaceLength);
- d->stateFlags |= InputContextPrivate::InputMethodEventState;
- d->inputContext->sendEvent(&event);
- d->stateFlags &= ~InputContextPrivate::InputMethodEventState;
-
- // Send also to shadow input if only attributes changed.
- // In this case the update() may not be called, so the shadow
- // input may be out of sync.
- if (d->shadow.inputItem() && !replace && !text.isEmpty() &&
- !textChanged && attributesChanged) {
- VIRTUALKEYBOARD_DEBUG() << "InputContext::sendPreedit(shadow):" << text << replaceFrom << replaceLength;
- event.setAccepted(true);
- QGuiApplication::sendEvent(d->shadow.inputItem(), &event);
- }
- }
-
- if (textChanged)
- emit preeditTextChanged();
- }
-
- if (d->preeditText.isEmpty())
- d->preeditTextAttributes.clear();
-}
-
-void InputContext::reset()
-{
- Q_D(InputContext);
- d->inputEngine->reset();
-}
-
-void InputContext::externalCommit()
-{
- Q_D(InputContext);
- d->inputEngine->update();
-}
-
-void InputContext::update(Qt::InputMethodQueries queries)
-{
- Q_D(InputContext);
-
- // No need to fetch input clip rectangle during animation
- if (!(queries & ~Qt::ImInputItemClipRectangle) && d->animating)
- return;
-
- // fetch
- QInputMethodQueryEvent imQueryEvent(Qt::InputMethodQueries(Qt::ImHints |
- Qt::ImQueryInput | Qt::ImInputItemClipRectangle));
- d->inputContext->sendEvent(&imQueryEvent);
- Qt::InputMethodHints inputMethodHints = Qt::InputMethodHints(imQueryEvent.value(Qt::ImHints).toInt());
- const int cursorPosition = imQueryEvent.value(Qt::ImCursorPosition).toInt();
- const int anchorPosition = imQueryEvent.value(Qt::ImAnchorPosition).toInt();
- QRectF anchorRectangle;
- QRectF cursorRectangle;
- if (const QGuiApplication *app = qApp) {
- anchorRectangle = app->inputMethod()->anchorRectangle();
- cursorRectangle = app->inputMethod()->cursorRectangle();
- } else {
- anchorRectangle = d->anchorRectangle;
- cursorRectangle = d->cursorRectangle;
- }
- QString surroundingText = imQueryEvent.value(Qt::ImSurroundingText).toString();
- QString selectedText = imQueryEvent.value(Qt::ImCurrentSelection).toString();
-
- // check against changes
- bool newInputMethodHints = inputMethodHints != d->inputMethodHints;
- bool newSurroundingText = surroundingText != d->surroundingText;
- bool newSelectedText = selectedText != d->selectedText;
- bool newAnchorPosition = anchorPosition != d->anchorPosition;
- bool newCursorPosition = cursorPosition != d->cursorPosition;
- bool newAnchorRectangle = anchorRectangle != d->anchorRectangle;
- bool newCursorRectangle = cursorRectangle != d->cursorRectangle;
- bool selectionControlVisible = d->inputContext->isInputPanelVisible() && (cursorPosition != anchorPosition) && !inputMethodHints.testFlag(Qt::ImhNoTextHandles);
- bool newSelectionControlVisible = selectionControlVisible != d->selectionControlVisible;
-
- QRectF inputItemClipRect = imQueryEvent.value(Qt::ImInputItemClipRectangle).toRectF();
- QRectF anchorRect = imQueryEvent.value(Qt::ImAnchorRectangle).toRectF();
- QRectF cursorRect = imQueryEvent.value(Qt::ImCursorRectangle).toRectF();
-
- bool anchorRectIntersectsClipRect = inputItemClipRect.intersects(anchorRect);
- bool newAnchorRectIntersectsClipRect = anchorRectIntersectsClipRect != d->anchorRectIntersectsClipRect;
-
- bool cursorRectIntersectsClipRect = inputItemClipRect.intersects(cursorRect);
- bool newCursorRectIntersectsClipRect = cursorRectIntersectsClipRect != d->cursorRectIntersectsClipRect;
-
- // update
- d->inputMethodHints = inputMethodHints;
- d->surroundingText = surroundingText;
- d->selectedText = selectedText;
- d->anchorPosition = anchorPosition;
- d->cursorPosition = cursorPosition;
- d->anchorRectangle = anchorRectangle;
- d->cursorRectangle = cursorRectangle;
- d->selectionControlVisible = selectionControlVisible;
- d->anchorRectIntersectsClipRect = anchorRectIntersectsClipRect;
- d->cursorRectIntersectsClipRect = cursorRectIntersectsClipRect;
-
- // update input engine
- if ((newSurroundingText || newCursorPosition) &&
- !d->stateFlags.testFlag(InputContextPrivate::InputMethodEventState)) {
- d->inputEngine->update();
- }
- if (newInputMethodHints) {
- d->inputEngine->reset();
- }
-
- // notify
- if (newInputMethodHints) {
- emit inputMethodHintsChanged();
- }
- if (newSurroundingText) {
- emit surroundingTextChanged();
- }
- if (newSelectedText) {
- emit selectedTextChanged();
- }
- if (newAnchorPosition) {
- emit anchorPositionChanged();
- }
- if (newCursorPosition) {
- emit cursorPositionChanged();
- }
- if (newAnchorRectangle) {
- emit anchorRectangleChanged();
- }
- if (newCursorRectangle) {
- emit cursorRectangleChanged();
- }
- if (newSelectionControlVisible) {
- emit selectionControlVisibleChanged();
- }
- if (newAnchorRectIntersectsClipRect) {
- emit anchorRectIntersectsClipRectChanged();
- }
- if (newCursorRectIntersectsClipRect) {
- emit cursorRectIntersectsClipRectChanged();
- }
-
- // word reselection
- if (newInputMethodHints || newSurroundingText || newSelectedText)
- d->stateFlags &= ~InputContextPrivate::InputMethodClickState;
- if ((newSurroundingText || newCursorPosition) && !newSelectedText && (int)d->stateFlags == 0 &&
- !d->inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
- d->cursorPosition > 0 && d->selectedText.isEmpty()) {
- d->stateFlags |= InputContextPrivate::ReselectEventState;
- if (d->inputEngine->reselect(d->cursorPosition, InputEngine::WordAtCursor))
- d->stateFlags |= InputContextPrivate::InputMethodClickState;
- d->stateFlags &= ~InputContextPrivate::ReselectEventState;
- }
-
- if (!d->stateFlags.testFlag(InputContextPrivate::SyncShadowInputState)) {
- d->stateFlags |= InputContextPrivate::SyncShadowInputState;
- d->shadow.update(queries);
- d->stateFlags &= ~InputContextPrivate::SyncShadowInputState;
- }
-}
-
-void InputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
-{
- Q_D(InputContext);
- switch (action) {
- case QInputMethod::Click:
- if ((int)d->stateFlags == 0) {
- if (d->inputEngine->clickPreeditText(cursorPosition))
- break;
-
- bool reselect = !d->inputMethodHints.testFlag(Qt::ImhNoPredictiveText) && d->selectedText.isEmpty() && cursorPosition < d->preeditText.length();
- if (reselect) {
- d->stateFlags |= InputContextPrivate::ReselectEventState;
- d->forceCursorPosition = d->cursorPosition + cursorPosition;
- d->inputEngine->update();
- d->inputEngine->reselect(d->cursorPosition, InputEngine::WordBeforeCursor);
- d->stateFlags &= ~InputContextPrivate::ReselectEventState;
- } else if (!d->preeditText.isEmpty() && cursorPosition == d->preeditText.length()) {
- d->inputEngine->update();
- }
- }
- d->stateFlags &= ~InputContextPrivate::InputMethodClickState;
- break;
-
- case QInputMethod::ContextMenu:
- break;
- }
-}
-
-bool InputContext::filterEvent(const QEvent *event)
-{
- QEvent::Type type = event->type();
- if (type == QEvent::KeyPress || type == QEvent::KeyRelease) {
- Q_D(InputContext);
- const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
-
- // Keep track of pressed keys update key event state
- if (type == QEvent::KeyPress)
- d->activeKeys += keyEvent->nativeScanCode();
- else if (type == QEvent::KeyRelease)
- d->activeKeys -= keyEvent->nativeScanCode();
-
- if (d->activeKeys.isEmpty())
- d->stateFlags &= ~InputContextPrivate::KeyEventState;
- else
- d->stateFlags |= InputContextPrivate::KeyEventState;
-
-#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
- int key = keyEvent->key();
- if ((key >= Qt::Key_Left && key <= Qt::Key_Down) || key == Qt::Key_Return) {
- if (type == QEvent::KeyPress && d->inputContext->isInputPanelVisible()) {
- d->activeNavigationKeys += key;
- emit navigationKeyPressed(key, keyEvent->isAutoRepeat());
- return true;
- } else if (type == QEvent::KeyRelease && d->activeNavigationKeys.contains(key)) {
- d->activeNavigationKeys -= key;
- emit navigationKeyReleased(key, keyEvent->isAutoRepeat());
- return true;
- }
- }
-#endif
-
- // Break composing text since the virtual keyboard does not support hard keyboard events
- if (!d->preeditText.isEmpty())
- d->inputEngine->update();
- }
- return false;
-}
-
-void InputContext::addSelectionAttribute(QList<QInputMethodEvent::Attribute> &attributes)
-{
- Q_D(InputContext);
- if (!testAttribute(attributes, QInputMethodEvent::Selection)) {
- // Convert Cursor attribute to Selection attribute.
- // In this case the cursor is set in pre-edit text, but
- // the cursor is not being forced to specific location.
- if (d->forceCursorPosition == -1) {
- int cursorAttributeIndex = findAttribute(d->preeditTextAttributes, QInputMethodEvent::Cursor);
- if (cursorAttributeIndex != -1 && d->preeditTextAttributes[cursorAttributeIndex].length > 0)
- d->forceCursorPosition = d->cursorPosition + d->preeditTextAttributes[cursorAttributeIndex].start;
- d->forceAnchorPosition = -1;
- }
-
- if (d->forceCursorPosition != -1) {
- if (d->forceAnchorPosition != -1)
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, d->forceAnchorPosition, d->forceCursorPosition - d->forceAnchorPosition, QVariant()));
- else
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, d->forceCursorPosition, 0, QVariant()));
- }
- }
- d->forceAnchorPosition = -1;
- d->forceCursorPosition = -1;
-}
-
-bool InputContext::testAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const
-{
- for (const QInputMethodEvent::Attribute &attribute : qAsConst(attributes)) {
- if (attribute.type == attributeType)
- return true;
- }
- return false;
-}
-
-int InputContext::findAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const
-{
- const int count = attributes.count();
- for (int i = 0; i < count; ++i) {
- if (attributes.at(i).type == attributeType)
- return i;
- }
- return -1;
+ return const_cast<InputContextPrivate *>(d);
}
/*!
- \qmlproperty bool InputContext::focus
-
- This property is changed when the input method receives or loses focus.
-*/
-
-/*!
- \property QtVirtualKeyboard::InputContext::focus
- \brief the focus status.
-
- This property is changed when the input method receives or loses focus.
-*/
-
-/*!
\qmlproperty bool InputContext::shift
This property is changed when the shift status changes.
@@ -1102,45 +500,6 @@ int InputContext::findAttribute(const QList<QInputMethodEvent::Attribute> &attri
*/
/*!
- \qmlproperty rect InputContext::keyboardRectangle
-
- Use this property to set the keyboard rectangle.
-*/
-
-/*!
- \property QtVirtualKeyboard::InputContext::keyboardRectangle
- \brief the keyboard rectangle.
-
- Use this property to set the keyboard rectangle.
-*/
-
-/*!
- \qmlproperty rect InputContext::previewRectangle
-
- Use this property to set the preview rectangle.
-*/
-
-/*!
- \property QtVirtualKeyboard::InputContext::previewRectangle
- \brief the preview rectangle.
-
- Use this property to set the preview rectangle.
-*/
-
-/*!
- \qmlproperty bool InputContext::previewVisible
-
- Use this property to set the visibility status of the preview.
-*/
-
-/*!
- \property QtVirtualKeyboard::InputContext::previewVisible
- \brief the animating status.
-
- Use this property to set the visibility status of the preview.
-*/
-
-/*!
\qmlproperty bool InputContext::animating
Use this property to set the animating status, for example
@@ -1158,40 +517,14 @@ int InputContext::findAttribute(const QList<QInputMethodEvent::Attribute> &attri
/*!
\qmlproperty string InputContext::locale
- Sets the locale for this input context.
+ This property is changed when the input locale changes.
*/
/*!
\property QtVirtualKeyboard::InputContext::locale
\brief the locale.
- Sets the locale for this input context.
-*/
-
-/*!
- \qmlproperty QtObject InputContext::inputItem
-
- This property is changed when the focused input item changes.
-*/
-
-/*!
- \property QtVirtualKeyboard::InputContext::inputItem
- \brief the focused input item.
-
- This property is changed when the focused input item changes.
-*/
-
-/*!
- \qmlproperty ShiftHandler InputContext::shiftHandler
-
- This property stores the shift handler.
-*/
-
-/*!
- \property QtVirtualKeyboard::InputContext::shiftHandler
- \brief the shift handler instance.
-
- This property stores the shift handler.
+ This property is changed when the input locale changes.
*/
/*!
@@ -1207,27 +540,5 @@ int InputContext::findAttribute(const QList<QInputMethodEvent::Attribute> &attri
This property stores the input engine.
*/
-/*!
- \qmlsignal InputContext::focusEditorChanged()
-
- This signal is emitted when the focus editor changes.
-*/
-
-/*!
- \fn void QtVirtualKeyboard::InputContext::focusEditorChanged()
-
- This signal is emitted when the focus editor changes.
-*/
-
-/*!
- \fn void QtVirtualKeyboard::InputContext::navigationKeyPressed(int key, bool isAutoRepeat)
- \internal
-*/
-
-/*!
- \fn void QtVirtualKeyboard::InputContext::navigationKeyReleased(int key, bool isAutoRepeat)
- \internal
-*/
-
} // namespace QtVirtualKeyboard
QT_END_NAMESPACE
diff --git a/src/virtualkeyboard/inputcontext.h b/src/virtualkeyboard/inputcontext.h
index fc2010e0..6b2ba379 100644
--- a/src/virtualkeyboard/inputcontext.h
+++ b/src/virtualkeyboard/inputcontext.h
@@ -41,9 +41,7 @@ QT_BEGIN_NAMESPACE
namespace QtVirtualKeyboard {
class PlatformInputContext;
-class ShadowInputContext;
class InputEngine;
-class ShiftHandler;
class InputContextPrivate;
class QVIRTUALKEYBOARD_EXPORT InputContext : public QObject
@@ -51,9 +49,8 @@ class QVIRTUALKEYBOARD_EXPORT InputContext : public QObject
Q_OBJECT
Q_DISABLE_COPY(InputContext)
Q_DECLARE_PRIVATE(InputContext)
- Q_PROPERTY(bool focus READ focus NOTIFY focusChanged)
- Q_PROPERTY(bool shift READ shift WRITE setShift NOTIFY shiftChanged)
- Q_PROPERTY(bool capsLock READ capsLock WRITE setCapsLock NOTIFY capsLockChanged)
+ Q_PROPERTY(bool shift READ shift NOTIFY shiftChanged)
+ Q_PROPERTY(bool capsLock READ capsLock NOTIFY capsLockChanged)
Q_PROPERTY(bool uppercase READ uppercase NOTIFY uppercaseChanged)
Q_PROPERTY(int anchorPosition READ anchorPosition NOTIFY anchorPositionChanged)
Q_PROPERTY(int cursorPosition READ cursorPosition NOTIFY cursorPositionChanged)
@@ -63,28 +60,20 @@ class QVIRTUALKEYBOARD_EXPORT InputContext : public QObject
Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged)
Q_PROPERTY(QRectF anchorRectangle READ anchorRectangle NOTIFY anchorRectangleChanged)
Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged)
- Q_PROPERTY(QRectF keyboardRectangle READ keyboardRectangle WRITE setKeyboardRectangle NOTIFY keyboardRectangleChanged)
- Q_PROPERTY(QRectF previewRectangle READ previewRectangle WRITE setPreviewRectangle NOTIFY previewRectangleChanged)
- Q_PROPERTY(bool previewVisible READ previewVisible WRITE setPreviewVisible NOTIFY previewVisibleChanged)
Q_PROPERTY(bool animating READ animating WRITE setAnimating NOTIFY animatingChanged)
- Q_PROPERTY(QString locale READ locale WRITE setLocale NOTIFY localeChanged)
- Q_PROPERTY(QObject *inputItem READ inputItem NOTIFY inputItemChanged)
- Q_PROPERTY(ShiftHandler *shiftHandler READ shiftHandler CONSTANT)
+ Q_PROPERTY(QString locale READ locale NOTIFY localeChanged)
Q_PROPERTY(InputEngine *inputEngine READ inputEngine CONSTANT)
Q_PROPERTY(bool selectionControlVisible READ selectionControlVisible NOTIFY selectionControlVisibleChanged)
Q_PROPERTY(bool anchorRectIntersectsClipRect READ anchorRectIntersectsClipRect NOTIFY anchorRectIntersectsClipRectChanged)
Q_PROPERTY(bool cursorRectIntersectsClipRect READ cursorRectIntersectsClipRect NOTIFY cursorRectIntersectsClipRectChanged)
- Q_PROPERTY(ShadowInputContext *shadow READ shadow CONSTANT)
+ Q_PROPERTY(InputContextPrivate *priv READ priv CONSTANT)
public:
explicit InputContext(PlatformInputContext *parent = nullptr);
~InputContext();
- bool focus() const;
bool shift() const;
- void setShift(bool enable);
bool capsLock() const;
- void setCapsLock(bool enable);
bool uppercase() const;
int anchorPosition() const;
int cursorPosition() const;
@@ -96,44 +85,24 @@ public:
QString selectedText() const;
QRectF anchorRectangle() const;
QRectF cursorRectangle() const;
- QRectF keyboardRectangle() const;
- void setKeyboardRectangle(QRectF rectangle);
- QRectF previewRectangle() const;
- void setPreviewRectangle(QRectF rectangle);
- bool previewVisible() const;
- void setPreviewVisible(bool visible);
bool animating() const;
void setAnimating(bool animating);
QString locale() const;
- void setLocale(const QString &locale);
- Q_INVOKABLE void updateAvailableLocales(const QStringList &availableLocales);
- QObject *inputItem() const;
- ShiftHandler *shiftHandler() const;
InputEngine *inputEngine() const;
bool selectionControlVisible() const;
bool anchorRectIntersectsClipRect() const;
bool cursorRectIntersectsClipRect() const;
- ShadowInputContext *shadow() const;
+ InputContextPrivate *priv() const;
- Q_INVOKABLE void hideInputPanel();
Q_INVOKABLE void sendKeyClick(int key, const QString &text, int modifiers = 0);
Q_INVOKABLE void commit();
Q_INVOKABLE void commit(const QString &text, int replaceFrom = 0, int replaceLength = 0);
Q_INVOKABLE void clear();
- // Helper functions
- Q_INVOKABLE bool fileExists(const QUrl &fileUrl);
- Q_INVOKABLE bool hasEnterKeyAction(QObject *item) const;
-
// For selection handles
Q_INVOKABLE void setSelectionOnFocusObject(const QPointF &anchorPos, const QPointF &cursorPos);
- // For shadow input
- Q_INVOKABLE void forceCursorPosition(int anchorPosition, int cursorPosition);
-
Q_SIGNALS:
- void focusChanged();
- void focusEditorChanged();
void preeditTextChanged();
void inputMethodHintsChanged();
void surroundingTextChanged();
@@ -145,35 +114,16 @@ Q_SIGNALS:
void shiftChanged();
void capsLockChanged();
void uppercaseChanged();
- void keyboardRectangleChanged();
- void previewRectangleChanged();
- void previewVisibleChanged();
void animatingChanged();
void localeChanged();
- void inputItemChanged();
void selectionControlVisibleChanged();
- void navigationKeyPressed(int key, bool isAutoRepeat);
- void navigationKeyReleased(int key, bool isAutoRepeat);
void anchorRectIntersectsClipRectChanged();
void cursorRectIntersectsClipRectChanged();
-private Q_SLOTS:
- void onInputItemChanged();
-
private:
- void setFocus(bool enable);
- void sendPreedit(const QString &text, const QList<QInputMethodEvent::Attribute> &attributes, int replaceFrom, int replaceLength);
- void reset();
- void externalCommit();
- void update(Qt::InputMethodQueries queries);
- void invokeAction(QInputMethod::Action action, int cursorPosition);
- bool filterEvent(const QEvent *event);
- void addSelectionAttribute(QList<QInputMethodEvent::Attribute> &attributes);
- bool testAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const;
- int findAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const;
+ friend class InputContextPrivate;
-private:
- friend class PlatformInputContext;
+ QScopedPointer<InputContextPrivate> d_ptr;
};
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/inputcontext_p.cpp b/src/virtualkeyboard/inputcontext_p.cpp
new file mode 100644
index 00000000..4f956645
--- /dev/null
+++ b/src/virtualkeyboard/inputcontext_p.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 <QtVirtualKeyboard/private/inputcontext_p.h>
+#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
+#include <QtVirtualKeyboard/private/settings_p.h>
+#include <QtVirtualKeyboard/private/shifthandler_p.h>
+#include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h>
+#include <QtVirtualKeyboard/private/enterkeyaction_p.h>
+#include <QtVirtualKeyboard/inputengine.h>
+
+#include <QGuiApplication>
+
+QT_BEGIN_NAMESPACE
+
+bool operator==(const QInputMethodEvent::Attribute &attribute1, const QInputMethodEvent::Attribute &attribute2)
+{
+ return attribute1.start == attribute2.start &&
+ attribute1.length == attribute2.length &&
+ attribute1.type == attribute2.type &&
+ attribute1.value == attribute2.value;
+}
+
+namespace QtVirtualKeyboard {
+
+InputContextPrivate::InputContextPrivate(InputContext *q_ptr, PlatformInputContext *platformInputContext) :
+ QObject(nullptr),
+ q_ptr(q_ptr),
+ platformInputContext(platformInputContext),
+ inputEngine(nullptr),
+ _shiftHandler(nullptr),
+ keyboardRect(),
+ previewRect(),
+ _previewVisible(false),
+ animating(false),
+ _focus(false),
+ cursorPosition(0),
+ anchorPosition(0),
+ forceAnchorPosition(-1),
+ _forceCursorPosition(-1),
+ inputMethodHints(Qt::ImhNone),
+ preeditText(),
+ preeditTextAttributes(),
+ surroundingText(),
+ selectedText(),
+ anchorRectangle(),
+ cursorRectangle(),
+ selectionControlVisible(false),
+ anchorRectIntersectsClipRect(false),
+ cursorRectIntersectsClipRect(false)
+#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
+ , activeNavigationKeys()
+#endif
+{
+}
+
+void InputContextPrivate::init()
+{
+ Q_Q(InputContext);
+ Q_ASSERT(inputEngine == nullptr);
+ inputEngine = new InputEngine(q);
+ _shiftHandler = new ShiftHandler(q);
+ inputEngine->init();
+ _shiftHandler->init();
+ _shadow.setInputContext(q);
+ if (platformInputContext) {
+ platformInputContext->setInputContext(q);
+ QObject::connect(platformInputContext, &PlatformInputContext::focusObjectChanged, this, &InputContextPrivate::onInputItemChanged);
+ QObject::connect(platformInputContext, &PlatformInputContext::focusObjectChanged, this, &InputContextPrivate::inputItemChanged);
+ }
+}
+
+InputContextPrivate::~InputContextPrivate()
+{
+}
+
+bool InputContextPrivate::focus() const
+{
+ return _focus;
+}
+
+void InputContextPrivate::setFocus(bool focus)
+{
+ if (_focus != focus) {
+ VIRTUALKEYBOARD_DEBUG() << "InputContextPrivate::setFocus():" << focus;
+ _focus = focus;
+ emit focusChanged();
+ }
+}
+
+QRectF InputContextPrivate::keyboardRectangle() const
+{
+ return keyboardRect;
+}
+
+void InputContextPrivate::setKeyboardRectangle(QRectF rectangle)
+{
+ if (keyboardRect != rectangle) {
+ keyboardRect = rectangle;
+ emit keyboardRectangleChanged();
+ platformInputContext->emitKeyboardRectChanged();
+ }
+}
+
+QRectF InputContextPrivate::previewRectangle() const
+{
+ return previewRect;
+}
+
+void InputContextPrivate::setPreviewRectangle(QRectF rectangle)
+{
+ if (previewRect != rectangle) {
+ previewRect = rectangle;
+ emit previewRectangleChanged();
+ }
+}
+
+bool InputContextPrivate::previewVisible() const
+{
+ return _previewVisible;
+}
+
+void InputContextPrivate::setPreviewVisible(bool visible)
+{
+ if (_previewVisible != visible) {
+ _previewVisible = visible;
+ emit previewVisibleChanged();
+ }
+}
+
+QString InputContextPrivate::locale() const
+{
+ return platformInputContext->locale().name();
+}
+
+void InputContextPrivate::setLocale(const QString &locale)
+{
+ VIRTUALKEYBOARD_DEBUG() << "InputContextPrivate::setLocale():" << locale;
+ QLocale newLocale(locale);
+ if (newLocale != platformInputContext->locale()) {
+ platformInputContext->setLocale(newLocale);
+ platformInputContext->setInputDirection(newLocale.textDirection());
+ emit localeChanged();
+ }
+}
+
+QObject *InputContextPrivate::inputItem() const
+{
+ return platformInputContext ? platformInputContext->focusObject() : nullptr;
+}
+
+ShiftHandler *InputContextPrivate::shiftHandler() const
+{
+ return _shiftHandler;
+}
+
+ShadowInputContext *InputContextPrivate::shadow() const
+{
+ return const_cast<ShadowInputContext *>(&_shadow);
+}
+
+bool InputContextPrivate::fileExists(const QUrl &fileUrl)
+{
+ QString fileName;
+ if (fileUrl.scheme() == QLatin1String("qrc")) {
+ fileName = QLatin1Char(':') + fileUrl.path();
+ } else {
+ fileName = fileUrl.toLocalFile();
+ }
+ return !fileName.isEmpty() && QFile::exists(fileName);
+}
+
+bool InputContextPrivate::hasEnterKeyAction(QObject *item) const
+{
+ return item != nullptr && qmlAttachedPropertiesObject<EnterKeyAction>(item, false);
+}
+
+void InputContextPrivate::hideInputPanel()
+{
+ platformInputContext->hideInputPanel();
+}
+
+void InputContextPrivate::updateAvailableLocales(const QStringList &availableLocales)
+{
+ Settings *settings = Settings::instance();
+ if (settings)
+ settings->setAvailableLocales(availableLocales);
+}
+
+void InputContextPrivate::forceCursorPosition(int anchorPosition, int cursorPosition)
+{
+ if (!_shadow.inputItem())
+ return;
+ if (!platformInputContext->m_visible)
+ return;
+ if (stateFlags.testFlag(InputContextPrivate::ReselectEventState))
+ return;
+ if (stateFlags.testFlag(InputContextPrivate::SyncShadowInputState))
+ return;
+
+ VIRTUALKEYBOARD_DEBUG() << "InputContextPrivate::forceCursorPosition():" << cursorPosition << "anchorPosition:" << anchorPosition;
+ if (!preeditText.isEmpty()) {
+ forceAnchorPosition = -1;
+ _forceCursorPosition = cursorPosition;
+ if (cursorPosition > this->cursorPosition)
+ _forceCursorPosition += preeditText.length();
+ commit();
+ } else {
+ forceAnchorPosition = anchorPosition;
+ _forceCursorPosition = cursorPosition;
+ Q_Q(InputContext);
+ q->setPreeditText(QString());
+ if (!inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
+ cursorPosition > 0 && selectedText.isEmpty()) {
+ stateFlags |= InputContextPrivate::ReselectEventState;
+ if (inputEngine->reselect(cursorPosition, InputEngine::WordAtCursor))
+ stateFlags |= InputContextPrivate::InputMethodClickState;
+ stateFlags &= ~InputContextPrivate::ReselectEventState;
+ }
+ }
+}
+
+void InputContextPrivate::onInputItemChanged()
+{
+ if (!inputItem() && !activeKeys.isEmpty()) {
+ // After losing keyboard focus it is impossible to track pressed keys
+ activeKeys.clear();
+ stateFlags &= ~InputContextPrivate::KeyEventState;
+ }
+ stateFlags &= ~InputContextPrivate::InputMethodClickState;
+}
+
+void InputContextPrivate::sendPreedit(const QString &text, const QList<QInputMethodEvent::Attribute> &attributes, int replaceFrom, int replaceLength)
+{
+ VIRTUALKEYBOARD_DEBUG() << "InputContextPrivate::sendPreedit():" << text << replaceFrom << replaceLength;
+
+ bool textChanged = preeditText != text;
+ bool attributesChanged = preeditTextAttributes != attributes;
+
+ if (textChanged || attributesChanged) {
+ preeditText = text;
+ preeditTextAttributes = attributes;
+
+ if (platformInputContext) {
+ QInputMethodEvent event(text, attributes);
+ const bool replace = replaceFrom != 0 || replaceLength > 0;
+ if (replace)
+ event.setCommitString(QString(), replaceFrom, replaceLength);
+ stateFlags |= InputContextPrivate::InputMethodEventState;
+ platformInputContext->sendEvent(&event);
+ stateFlags &= ~InputContextPrivate::InputMethodEventState;
+
+ // Send also to shadow input if only attributes changed.
+ // In this case the update() may not be called, so the shadow
+ // input may be out of sync.
+ if (_shadow.inputItem() && !replace && !text.isEmpty() &&
+ !textChanged && attributesChanged) {
+ VIRTUALKEYBOARD_DEBUG() << "InputContextPrivate::sendPreedit(shadow):" << text << replaceFrom << replaceLength;
+ event.setAccepted(true);
+ QGuiApplication::sendEvent(_shadow.inputItem(), &event);
+ }
+ }
+
+ if (textChanged) {
+ Q_Q(InputContext);
+ emit q->preeditTextChanged();
+ }
+ }
+
+ if (preeditText.isEmpty())
+ preeditTextAttributes.clear();
+}
+
+void InputContextPrivate::reset()
+{
+ inputEngine->reset();
+}
+
+void InputContextPrivate::commit()
+{
+ inputEngine->update();
+}
+
+void InputContextPrivate::update(Qt::InputMethodQueries queries)
+{
+ Q_Q(InputContext);
+
+ // No need to fetch input clip rectangle during animation
+ if (!(queries & ~Qt::ImInputItemClipRectangle) && animating)
+ return;
+
+ // fetch
+ QInputMethodQueryEvent imQueryEvent(Qt::InputMethodQueries(Qt::ImHints |
+ Qt::ImQueryInput | Qt::ImInputItemClipRectangle));
+ platformInputContext->sendEvent(&imQueryEvent);
+ Qt::InputMethodHints inputMethodHints = Qt::InputMethodHints(imQueryEvent.value(Qt::ImHints).toInt());
+ const int cursorPosition = imQueryEvent.value(Qt::ImCursorPosition).toInt();
+ const int anchorPosition = imQueryEvent.value(Qt::ImAnchorPosition).toInt();
+ QRectF anchorRectangle;
+ QRectF cursorRectangle;
+ if (const QGuiApplication *app = qApp) {
+ anchorRectangle = app->inputMethod()->anchorRectangle();
+ cursorRectangle = app->inputMethod()->cursorRectangle();
+ } else {
+ anchorRectangle = this->anchorRectangle;
+ cursorRectangle = this->cursorRectangle;
+ }
+ QString surroundingText = imQueryEvent.value(Qt::ImSurroundingText).toString();
+ QString selectedText = imQueryEvent.value(Qt::ImCurrentSelection).toString();
+
+ // check against changes
+ bool newInputMethodHints = inputMethodHints != this->inputMethodHints;
+ bool newSurroundingText = surroundingText != this->surroundingText;
+ bool newSelectedText = selectedText != this->selectedText;
+ bool newAnchorPosition = anchorPosition != this->anchorPosition;
+ bool newCursorPosition = cursorPosition != this->cursorPosition;
+ bool newAnchorRectangle = anchorRectangle != this->anchorRectangle;
+ bool newCursorRectangle = cursorRectangle != this->cursorRectangle;
+ bool selectionControlVisible = platformInputContext->isInputPanelVisible() && (cursorPosition != anchorPosition) && !inputMethodHints.testFlag(Qt::ImhNoTextHandles);
+ bool newSelectionControlVisible = selectionControlVisible != this->selectionControlVisible;
+
+ QRectF inputItemClipRect = imQueryEvent.value(Qt::ImInputItemClipRectangle).toRectF();
+ QRectF anchorRect = imQueryEvent.value(Qt::ImAnchorRectangle).toRectF();
+ QRectF cursorRect = imQueryEvent.value(Qt::ImCursorRectangle).toRectF();
+
+ bool anchorRectIntersectsClipRect = inputItemClipRect.intersects(anchorRect);
+ bool newAnchorRectIntersectsClipRect = anchorRectIntersectsClipRect != this->anchorRectIntersectsClipRect;
+
+ bool cursorRectIntersectsClipRect = inputItemClipRect.intersects(cursorRect);
+ bool newCursorRectIntersectsClipRect = cursorRectIntersectsClipRect != this->cursorRectIntersectsClipRect;
+
+ // update
+ this->inputMethodHints = inputMethodHints;
+ this->surroundingText = surroundingText;
+ this->selectedText = selectedText;
+ this->anchorPosition = anchorPosition;
+ this->cursorPosition = cursorPosition;
+ this->anchorRectangle = anchorRectangle;
+ this->cursorRectangle = cursorRectangle;
+ this->selectionControlVisible = selectionControlVisible;
+ this->anchorRectIntersectsClipRect = anchorRectIntersectsClipRect;
+ this->cursorRectIntersectsClipRect = cursorRectIntersectsClipRect;
+
+ // update input engine
+ if ((newSurroundingText || newCursorPosition) &&
+ !stateFlags.testFlag(InputContextPrivate::InputMethodEventState)) {
+ commit();
+ }
+ if (newInputMethodHints) {
+ reset();
+ }
+
+ // notify
+ if (newInputMethodHints) {
+ emit q->inputMethodHintsChanged();
+ }
+ if (newSurroundingText) {
+ emit q->surroundingTextChanged();
+ }
+ if (newSelectedText) {
+ emit q->selectedTextChanged();
+ }
+ if (newAnchorPosition) {
+ emit q->anchorPositionChanged();
+ }
+ if (newCursorPosition) {
+ emit q->cursorPositionChanged();
+ }
+ if (newAnchorRectangle) {
+ emit q->anchorRectangleChanged();
+ }
+ if (newCursorRectangle) {
+ emit q->cursorRectangleChanged();
+ }
+ if (newSelectionControlVisible) {
+ emit q->selectionControlVisibleChanged();
+ }
+ if (newAnchorRectIntersectsClipRect) {
+ emit q->anchorRectIntersectsClipRectChanged();
+ }
+ if (newCursorRectIntersectsClipRect) {
+ emit q->cursorRectIntersectsClipRectChanged();
+ }
+
+ // word reselection
+ if (newInputMethodHints || newSurroundingText || newSelectedText)
+ stateFlags &= ~InputContextPrivate::InputMethodClickState;
+ if ((newSurroundingText || newCursorPosition) && !newSelectedText && (int)stateFlags == 0 &&
+ !inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
+ cursorPosition > 0 && this->selectedText.isEmpty()) {
+ stateFlags |= InputContextPrivate::ReselectEventState;
+ if (inputEngine->reselect(cursorPosition, InputEngine::WordAtCursor))
+ stateFlags |= InputContextPrivate::InputMethodClickState;
+ stateFlags &= ~InputContextPrivate::ReselectEventState;
+ }
+
+ if (!stateFlags.testFlag(InputContextPrivate::SyncShadowInputState)) {
+ stateFlags |= InputContextPrivate::SyncShadowInputState;
+ _shadow.update(queries);
+ stateFlags &= ~InputContextPrivate::SyncShadowInputState;
+ }
+}
+
+void InputContextPrivate::invokeAction(QInputMethod::Action action, int cursorPosition)
+{
+ switch (action) {
+ case QInputMethod::Click:
+ if ((int)stateFlags == 0) {
+ if (inputEngine->clickPreeditText(cursorPosition))
+ break;
+
+ bool reselect = !inputMethodHints.testFlag(Qt::ImhNoPredictiveText) && selectedText.isEmpty() && cursorPosition < preeditText.length();
+ if (reselect) {
+ stateFlags |= InputContextPrivate::ReselectEventState;
+ _forceCursorPosition = this->cursorPosition + cursorPosition;
+ commit();
+ inputEngine->reselect(this->cursorPosition, InputEngine::WordBeforeCursor);
+ stateFlags &= ~InputContextPrivate::ReselectEventState;
+ } else if (!preeditText.isEmpty() && cursorPosition == preeditText.length()) {
+ commit();
+ }
+ }
+ stateFlags &= ~InputContextPrivate::InputMethodClickState;
+ break;
+
+ case QInputMethod::ContextMenu:
+ break;
+ }
+}
+
+bool InputContextPrivate::filterEvent(const QEvent *event)
+{
+ QEvent::Type type = event->type();
+ if (type == QEvent::KeyPress || type == QEvent::KeyRelease) {
+ const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
+
+ // Keep track of pressed keys update key event state
+ if (type == QEvent::KeyPress)
+ activeKeys += keyEvent->nativeScanCode();
+ else if (type == QEvent::KeyRelease)
+ activeKeys -= keyEvent->nativeScanCode();
+
+ if (activeKeys.isEmpty())
+ stateFlags &= ~InputContextPrivate::KeyEventState;
+ else
+ stateFlags |= InputContextPrivate::KeyEventState;
+
+#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
+ int key = keyEvent->key();
+ if ((key >= Qt::Key_Left && key <= Qt::Key_Down) || key == Qt::Key_Return) {
+ if (type == QEvent::KeyPress && platformInputContext->isInputPanelVisible()) {
+ activeNavigationKeys += key;
+ emit navigationKeyPressed(key, keyEvent->isAutoRepeat());
+ return true;
+ } else if (type == QEvent::KeyRelease && activeNavigationKeys.contains(key)) {
+ activeNavigationKeys -= key;
+ emit navigationKeyReleased(key, keyEvent->isAutoRepeat());
+ return true;
+ }
+ }
+#endif
+
+ // Break composing text since the virtual keyboard does not support hard keyboard events
+ if (!preeditText.isEmpty())
+ commit();
+ }
+ return false;
+}
+
+void InputContextPrivate::addSelectionAttribute(QList<QInputMethodEvent::Attribute> &attributes)
+{
+ if (!testAttribute(attributes, QInputMethodEvent::Selection)) {
+ // Convert Cursor attribute to Selection attribute.
+ // In this case the cursor is set in pre-edit text, but
+ // the cursor is not being forced to specific location.
+ if (_forceCursorPosition == -1) {
+ int cursorAttributeIndex = findAttribute(preeditTextAttributes, QInputMethodEvent::Cursor);
+ if (cursorAttributeIndex != -1 && preeditTextAttributes[cursorAttributeIndex].length > 0)
+ _forceCursorPosition = cursorPosition + preeditTextAttributes[cursorAttributeIndex].start;
+ forceAnchorPosition = -1;
+ }
+
+ if (_forceCursorPosition != -1) {
+ if (forceAnchorPosition != -1)
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, forceAnchorPosition, _forceCursorPosition - forceAnchorPosition, QVariant()));
+ else
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, _forceCursorPosition, 0, QVariant()));
+ }
+ }
+ forceAnchorPosition = -1;
+ _forceCursorPosition = -1;
+}
+
+bool InputContextPrivate::testAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const
+{
+ for (const QInputMethodEvent::Attribute &attribute : qAsConst(attributes)) {
+ if (attribute.type == attributeType)
+ return true;
+ }
+ return false;
+}
+
+int InputContextPrivate::findAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const
+{
+ const int count = attributes.count();
+ for (int i = 0; i < count; ++i) {
+ if (attributes.at(i).type == attributeType)
+ return i;
+ }
+ return -1;
+}
+
+} // namespace QtVirtualKeyboard
+QT_END_NAMESPACE
diff --git a/src/virtualkeyboard/inputcontext_p.h b/src/virtualkeyboard/inputcontext_p.h
new file mode 100644
index 00000000..be0d6c2b
--- /dev/null
+++ b/src/virtualkeyboard/inputcontext_p.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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$
+**
+****************************************************************************/
+
+#ifndef INPUTCONTEXT_P_H
+#define INPUTCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QObject>
+#include <QRectF>
+#include <QInputMethodEvent>
+#include <QtVirtualKeyboard/inputcontext.h>
+#include <QtVirtualKeyboard/private/shadowinputcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+namespace QtVirtualKeyboard {
+
+class PlatformInputContext;
+class ShadowInputContext;
+class InputEngine;
+class ShiftHandler;
+class InputContextPrivate;
+
+class QVIRTUALKEYBOARD_EXPORT InputContextPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(InputContext)
+ Q_PROPERTY(bool focus READ focus WRITE setFocus NOTIFY focusChanged)
+ Q_PROPERTY(QRectF keyboardRectangle READ keyboardRectangle WRITE setKeyboardRectangle NOTIFY keyboardRectangleChanged)
+ Q_PROPERTY(QRectF previewRectangle READ previewRectangle WRITE setPreviewRectangle NOTIFY previewRectangleChanged)
+ Q_PROPERTY(bool previewVisible READ previewVisible WRITE setPreviewVisible NOTIFY previewVisibleChanged)
+ Q_PROPERTY(QString locale READ locale WRITE setLocale NOTIFY localeChanged)
+ Q_PROPERTY(QObject *inputItem READ inputItem NOTIFY inputItemChanged)
+ Q_PROPERTY(ShiftHandler *shiftHandler READ shiftHandler CONSTANT)
+ Q_PROPERTY(ShadowInputContext *shadow READ shadow CONSTANT)
+
+ explicit InputContextPrivate(InputContext *q_ptr, PlatformInputContext *platformInputContext);
+ void init();
+
+public:
+ enum StateFlag {
+ ReselectEventState = 0x1,
+ InputMethodEventState = 0x2,
+ KeyEventState = 0x4,
+ InputMethodClickState = 0x8,
+ SyncShadowInputState = 0x10
+ };
+ Q_DECLARE_FLAGS(StateFlags, StateFlag)
+
+ ~InputContextPrivate();
+
+ bool focus() const;
+ void setFocus(bool focus);
+ QRectF keyboardRectangle() const;
+ void setKeyboardRectangle(QRectF rectangle);
+ QRectF previewRectangle() const;
+ void setPreviewRectangle(QRectF rectangle);
+ bool previewVisible() const;
+ void setPreviewVisible(bool visible);
+ QString locale() const;
+ void setLocale(const QString &locale);
+ QObject *inputItem() const;
+ ShiftHandler *shiftHandler() const;
+ ShadowInputContext *shadow() const;
+
+ // Helper functions
+ Q_INVOKABLE bool fileExists(const QUrl &fileUrl);
+ Q_INVOKABLE bool hasEnterKeyAction(QObject *item) const;
+
+Q_SIGNALS:
+ void focusChanged();
+ void keyboardRectangleChanged();
+ void previewRectangleChanged();
+ void previewVisibleChanged();
+ void localeChanged();
+ void inputItemChanged();
+ void navigationKeyPressed(int key, bool isAutoRepeat);
+ void navigationKeyReleased(int key, bool isAutoRepeat);
+
+public Q_SLOTS:
+ void hideInputPanel();
+ void updateAvailableLocales(const QStringList &availableLocales);
+ void forceCursorPosition(int anchorPosition, int cursorPosition);
+
+private Q_SLOTS:
+ void onInputItemChanged();
+
+private:
+ void sendPreedit(const QString &text, const QList<QInputMethodEvent::Attribute> &attributes, int replaceFrom, int replaceLength);
+ void reset();
+ void commit();
+ void update(Qt::InputMethodQueries queries);
+ void invokeAction(QInputMethod::Action action, int cursorPosition);
+ bool filterEvent(const QEvent *event);
+ void addSelectionAttribute(QList<QInputMethodEvent::Attribute> &attributes);
+ bool testAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const;
+ int findAttribute(const QList<QInputMethodEvent::Attribute> &attributes, QInputMethodEvent::AttributeType attributeType) const;
+
+private:
+ InputContext *q_ptr;
+ PlatformInputContext *platformInputContext;
+ InputEngine *inputEngine;
+ ShiftHandler *_shiftHandler;
+ QRectF keyboardRect;
+ QRectF previewRect;
+ bool _previewVisible;
+ bool animating;
+ bool _focus;
+ StateFlags stateFlags;
+ int cursorPosition;
+ int anchorPosition;
+ int forceAnchorPosition;
+ int _forceCursorPosition;
+ Qt::InputMethodHints inputMethodHints;
+ QString preeditText;
+ QList<QInputMethodEvent::Attribute> preeditTextAttributes;
+ QString surroundingText;
+ QString selectedText;
+ QRectF anchorRectangle;
+ QRectF cursorRectangle;
+ bool selectionControlVisible;
+ bool anchorRectIntersectsClipRect;
+ bool cursorRectIntersectsClipRect;
+#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
+ QSet<int> activeNavigationKeys;
+#endif
+ QSet<quint32> activeKeys;
+ ShadowInputContext _shadow;
+
+ friend class PlatformInputContext;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(InputContextPrivate::StateFlags)
+
+} // namespace QtVirtualKeyboard
+QT_END_NAMESPACE
+
+#endif // INPUTCONTEXT_P_H
diff --git a/src/virtualkeyboard/inputengine.cpp b/src/virtualkeyboard/inputengine.cpp
index 84b1cf09..23956401 100644
--- a/src/virtualkeyboard/inputengine.cpp
+++ b/src/virtualkeyboard/inputengine.cpp
@@ -29,6 +29,8 @@
#include <QtVirtualKeyboard/inputengine.h>
#include <QtVirtualKeyboard/inputcontext.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
+#include <QtVirtualKeyboard/private/shifthandler_p.h>
#include <QtVirtualKeyboard/private/fallbackinputmethod_p.h>
#include <QtVirtualKeyboard/trace.h>
#include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h>
@@ -154,13 +156,17 @@ InputEngine::InputEngine(InputContext *parent) :
{
Q_D(InputEngine);
d->inputContext = parent;
- if (d->inputContext) {
- connect(d->inputContext, SIGNAL(shiftChanged()), SLOT(shiftChanged()));
- connect(d->inputContext, SIGNAL(localeChanged()), SLOT(update()));
- QObject::connect(d->inputContext, &InputContext::inputMethodHintsChanged, this, &InputEngine::updateSelectionListModels);
- QObject::connect(d->inputContext, &InputContext::localeChanged, this, &InputEngine::updateInputModes);
- QObject::connect(this, &InputEngine::inputMethodChanged, this, &InputEngine::updateInputModes);
- }
+}
+
+void InputEngine::init()
+{
+ Q_D(InputEngine);
+ ShiftHandler *shiftHandler = d->inputContext->priv()->shiftHandler();
+ QObject::connect(shiftHandler, &ShiftHandler::shiftChanged, this, &InputEngine::shiftChanged);
+ QObject::connect(d->inputContext, &InputContext::localeChanged, this, &InputEngine::update);
+ QObject::connect(d->inputContext, &InputContext::inputMethodHintsChanged, this, &InputEngine::updateSelectionListModels);
+ QObject::connect(d->inputContext, &InputContext::localeChanged, this, &InputEngine::updateInputModes);
+ QObject::connect(this, &InputEngine::inputMethodChanged, this, &InputEngine::updateInputModes);
d->fallbackInputMethod = new FallbackInputMethod(this);
if (d->fallbackInputMethod)
d->fallbackInputMethod->setInputEngine(this);
@@ -619,7 +625,7 @@ void InputEngine::update()
void InputEngine::shiftChanged()
{
Q_D(InputEngine);
- TextCase newCase = d->inputContext->shift() ? Upper : Lower;
+ TextCase newCase = d->inputContext->priv()->shiftHandler()->shift() ? Upper : Lower;
if (d->textCase != newCase) {
d->textCase = newCase;
if (d->inputMethod) {
diff --git a/src/virtualkeyboard/inputengine.h b/src/virtualkeyboard/inputengine.h
index 80e13424..f4f5881c 100644
--- a/src/virtualkeyboard/inputengine.h
+++ b/src/virtualkeyboard/inputengine.h
@@ -59,6 +59,7 @@ class QVIRTUALKEYBOARD_EXPORT InputEngine : public QObject
Q_PROPERTY(bool wordCandidateListVisibleHint READ wordCandidateListVisibleHint NOTIFY wordCandidateListVisibleHintChanged)
explicit InputEngine(InputContext *parent = nullptr);
+ void init();
public:
enum TextCase {
@@ -155,6 +156,7 @@ protected:
private:
friend class InputContext;
+ friend class InputContextPrivate;
};
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/platforminputcontext.cpp b/src/virtualkeyboard/platforminputcontext.cpp
index e4a1a736..f575a5c0 100644
--- a/src/virtualkeyboard/platforminputcontext.cpp
+++ b/src/virtualkeyboard/platforminputcontext.cpp
@@ -29,6 +29,7 @@
#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
#include <QtVirtualKeyboard/inputcontext.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
#include <QtVirtualKeyboard/private/shadowinputcontext_p.h>
#include <QtVirtualKeyboard/private/abstractinputpanel_p.h>
#ifdef QT_VIRTUALKEYBOARD_DESKTOP
@@ -74,14 +75,14 @@ void PlatformInputContext::reset()
{
VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::reset()";
if (m_inputContext)
- m_inputContext->reset();
+ m_inputContext->priv()->reset();
}
void PlatformInputContext::commit()
{
VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::commit()";
if (m_inputContext)
- m_inputContext->externalCommit();
+ m_inputContext->priv()->commit();
}
void PlatformInputContext::update(Qt::InputMethodQueries queries)
@@ -99,13 +100,13 @@ void PlatformInputContext::update(Qt::InputMethodQueries queries)
if (m_inputContext) {
if (enabled) {
- m_inputContext->update(queries);
+ m_inputContext->priv()->update(queries);
if (m_visible)
updateInputPanelVisible();
} else {
hideInputPanel();
}
- m_inputContext->setFocus(enabled);
+ m_inputContext->priv()->setFocus(enabled);
}
}
@@ -113,12 +114,12 @@ void PlatformInputContext::invokeAction(QInputMethod::Action action, int cursorP
{
VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::invokeAction():" << action << cursorPosition;
if (m_inputContext)
- m_inputContext->invokeAction(action, cursorPosition);
+ m_inputContext->priv()->invokeAction(action, cursorPosition);
}
QRectF PlatformInputContext::keyboardRect() const
{
- return m_inputContext ? m_inputContext->keyboardRectangle() : QRectF();
+ return m_inputContext ? m_inputContext->priv()->keyboardRectangle() : QRectF();
}
bool PlatformInputContext::isAnimating() const
@@ -186,8 +187,8 @@ void PlatformInputContext::setFocusObject(QObject *object)
{
VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::setFocusObject():" << object;
Q_ASSERT(m_inputContext == nullptr ||
- m_inputContext->shadow()->inputItem() == nullptr ||
- m_inputContext->shadow()->inputItem() != object);
+ m_inputContext->priv()->shadow()->inputItem() == nullptr ||
+ m_inputContext->priv()->shadow()->inputItem() != object);
if (m_focusObject != object) {
if (m_focusObject)
m_focusObject->removeEventFilter(this);
@@ -207,7 +208,7 @@ InputContext *PlatformInputContext::inputContext() const
bool PlatformInputContext::eventFilter(QObject *object, QEvent *event)
{
if (event != m_filterEvent && object == m_focusObject && m_inputContext)
- return m_inputContext->filterEvent(event);
+ return m_inputContext->priv()->filterEvent(event);
return false;
}
@@ -247,7 +248,7 @@ void PlatformInputContext::setInputContext(InputContext *context)
if (m_inputContext) {
if (!m_inputPanel)
m_inputPanel = new AppInputPanel(this);
- connect(m_inputContext, SIGNAL(keyboardRectangleChanged()), SLOT(keyboardRectangleChanged()));
+ QObject::connect(m_inputContext->priv(), &InputContextPrivate::keyboardRectangleChanged, this, &PlatformInputContext::keyboardRectangleChanged);
} else if (m_inputPanel) {
m_inputPanel = nullptr;
}
@@ -255,7 +256,7 @@ void PlatformInputContext::setInputContext(InputContext *context)
void PlatformInputContext::keyboardRectangleChanged()
{
- m_inputPanel->setInputRect(m_inputContext->keyboardRectangle().toRect());
+ m_inputPanel->setInputRect(m_inputContext->priv()->keyboardRectangle().toRect());
}
void PlatformInputContext::updateInputPanelVisible()
diff --git a/src/virtualkeyboard/platforminputcontext_p.h b/src/virtualkeyboard/platforminputcontext_p.h
index 30f30bd3..3c072bbd 100644
--- a/src/virtualkeyboard/platforminputcontext_p.h
+++ b/src/virtualkeyboard/platforminputcontext_p.h
@@ -101,6 +101,7 @@ private slots:
private:
friend class InputContext;
+ friend class InputContextPrivate;
QPointer<InputContext> m_inputContext;
QPointer<AbstractInputPanel> m_inputPanel;
QPointer<DesktopInputSelectionControl> m_selectionControl;
diff --git a/src/virtualkeyboard/shifthandler.cpp b/src/virtualkeyboard/shifthandler.cpp
index 3b867b0d..7da1cb4e 100644
--- a/src/virtualkeyboard/shifthandler.cpp
+++ b/src/virtualkeyboard/shifthandler.cpp
@@ -28,6 +28,7 @@
****************************************************************************/
#include <QtVirtualKeyboard/private/shifthandler_p.h>
+#include <QtVirtualKeyboard/private/inputcontext_p.h>
#include <QtVirtualKeyboard/inputcontext.h>
#include <QtVirtualKeyboard/inputengine.h>
#include <QtCore/private/qobject_p.h>
@@ -45,10 +46,12 @@ public:
ShiftHandlerPrivate() :
QObjectPrivate(),
inputContext(nullptr),
- sentenceEndingCharacters(QString(".!?") + QChar(Qt::Key_exclamdown) + QChar(Qt::Key_questiondown)),
+ sentenceEndingCharacters(QLatin1String(".!?") + QChar(Qt::Key_exclamdown) + QChar(Qt::Key_questiondown)),
autoCapitalizationEnabled(false),
toggleShiftEnabled(false),
+ shift(false),
shiftChanged(false),
+ capsLock(false),
resetWhenVisible(false),
manualShiftLanguageFilter(QSet<QLocale::Language>() << QLocale::Arabic << QLocale::Persian << QLocale::Hindi << QLocale::Korean << QLocale::Thai),
manualCapsInputModeFilter(QSet<InputEngine::InputMode>() << InputEngine::Cangjie << InputEngine::Zhuyin << InputEngine::Hebrew),
@@ -61,7 +64,9 @@ public:
QString sentenceEndingCharacters;
bool autoCapitalizationEnabled;
bool toggleShiftEnabled;
+ bool shift;
bool shiftChanged;
+ bool capsLock;
bool resetWhenVisible;
QLocale locale;
QTime timer;
@@ -91,19 +96,20 @@ ShiftHandler::ShiftHandler(InputContext *parent) :
{
Q_D(ShiftHandler);
d->inputContext = parent;
- if (d->inputContext) {
- connect(d->inputContext, SIGNAL(inputMethodHintsChanged()), SLOT(restart()));
- connect(d->inputContext, SIGNAL(inputItemChanged()), SLOT(restart()));
- connect(d->inputContext->inputEngine(), SIGNAL(inputModeChanged()), SLOT(restart()));
- connect(d->inputContext, SIGNAL(preeditTextChanged()), SLOT(autoCapitalize()));
- connect(d->inputContext, SIGNAL(surroundingTextChanged()), SLOT(autoCapitalize()));
- connect(d->inputContext, SIGNAL(cursorPositionChanged()), SLOT(autoCapitalize()));
- connect(d->inputContext, SIGNAL(shiftChanged()), SLOT(shiftChanged()));
- connect(d->inputContext, SIGNAL(capsLockChanged()), SLOT(shiftChanged()));
- connect(d->inputContext, SIGNAL(localeChanged()), SLOT(localeChanged()));
- connect(qGuiApp->inputMethod(), SIGNAL(visibleChanged()), SLOT(inputMethodVisibleChanged()));
- d->locale = QLocale(d->inputContext->locale());
- }
+}
+
+void ShiftHandler::init()
+{
+ Q_D(ShiftHandler);
+ connect(d->inputContext, SIGNAL(inputMethodHintsChanged()), SLOT(restart()));
+ connect(d->inputContext->priv(), SIGNAL(inputItemChanged()), SLOT(restart()));
+ connect(d->inputContext->inputEngine(), SIGNAL(inputModeChanged()), SLOT(restart()));
+ connect(d->inputContext, SIGNAL(preeditTextChanged()), SLOT(autoCapitalize()));
+ connect(d->inputContext, SIGNAL(surroundingTextChanged()), SLOT(autoCapitalize()));
+ connect(d->inputContext, SIGNAL(cursorPositionChanged()), SLOT(autoCapitalize()));
+ connect(d->inputContext, SIGNAL(localeChanged()), SLOT(localeChanged()));
+ connect(qGuiApp->inputMethod(), SIGNAL(visibleChanged()), SLOT(inputMethodVisibleChanged()));
+ d->locale = QLocale(d->inputContext->locale());
}
/*!
@@ -142,6 +148,47 @@ bool ShiftHandler::toggleShiftEnabled() const
return d->toggleShiftEnabled;
}
+bool ShiftHandler::shift() const
+{
+ Q_D(const ShiftHandler);
+ return d->shift;
+}
+
+void ShiftHandler::setShift(bool enable)
+{
+ Q_D(ShiftHandler);
+ if (d->shift != enable) {
+ d->shift = enable;
+ d->shiftChanged = true;
+ emit shiftChanged();
+ if (!d->capsLock)
+ emit uppercaseChanged();
+ }
+}
+
+bool ShiftHandler::capsLock() const
+{
+ Q_D(const ShiftHandler);
+ return d->capsLock;
+}
+
+void ShiftHandler::setCapsLock(bool enable)
+{
+ Q_D(ShiftHandler);
+ if (d->capsLock != enable) {
+ d->capsLock = enable;
+ emit capsLockChanged();
+ if (!d->shift)
+ emit uppercaseChanged();
+ }
+}
+
+bool ShiftHandler::uppercase() const
+{
+ Q_D(const ShiftHandler);
+ return d->shift || d->capsLock;
+}
+
/*!
\since 1.2
@@ -170,27 +217,27 @@ void ShiftHandler::toggleShift()
if (!d->toggleShiftEnabled)
return;
if (d->manualShiftLanguageFilter.contains(d->locale.language())) {
- d->inputContext->setCapsLock(false);
- d->inputContext->setShift(!d->inputContext->shift());
+ setCapsLock(false);
+ setShift(!d->shift);
} else if (d->inputContext->inputMethodHints() & Qt::ImhNoAutoUppercase ||
d->manualCapsInputModeFilter.contains(d->inputContext->inputEngine()->inputMode())) {
- bool capsLock = d->inputContext->capsLock();
- d->inputContext->setCapsLock(!capsLock);
- d->inputContext->setShift(!capsLock);
+ bool capsLock = d->capsLock;
+ setCapsLock(!capsLock);
+ setShift(!capsLock);
} else {
- if (d->inputContext->capsLock()) {
- d->inputContext->setCapsLock(!d->inputContext->capsLock() && d->inputContext->shift() && !d->shiftChanged);
+ if (d->capsLock) {
+ setCapsLock(!d->capsLock && d->shift && !d->shiftChanged);
}
QStyleHints *style = QGuiApplication::styleHints();
if (d->timer.isNull() || d->timer.elapsed() > style->mouseDoubleClickInterval()) {
d->timer.restart();
- } else if (d->timer.elapsed() < style->mouseDoubleClickInterval() && !d->inputContext->capsLock()) {
- d->inputContext->setCapsLock(!d->inputContext->capsLock() && d->inputContext->shift() && !d->shiftChanged);
+ } else if (d->timer.elapsed() < style->mouseDoubleClickInterval() && !d->capsLock) {
+ setCapsLock(!d->capsLock && d->shift && !d->shiftChanged);
}
- d->inputContext->setShift(d->inputContext->capsLock() || !d->inputContext->shift());
+ setShift(d->capsLock || !d->shift);
d->shiftChanged = false;
}
}
@@ -208,7 +255,7 @@ void ShiftHandler::clearToggleShiftTimer()
void ShiftHandler::reset()
{
Q_D(ShiftHandler);
- if (d->inputContext->inputItem()) {
+ if (d->inputContext->priv()->inputItem()) {
Qt::InputMethodHints inputMethodHints = d->inputContext->inputMethodHints();
InputEngine::InputMode inputMode = d->inputContext->inputEngine()->inputMode();
bool preferUpperCase = (inputMethodHints & (Qt::ImhPreferUppercase | Qt::ImhUppercaseOnly));
@@ -231,9 +278,9 @@ void ShiftHandler::reset()
}
setToggleShiftEnabled(toggleShiftEnabled);
setAutoCapitalizationEnabled(autoCapitalizationEnabled);
- d->inputContext->setCapsLock(preferUpperCase);
+ setCapsLock(preferUpperCase);
if (preferUpperCase)
- d->inputContext->setShift(preferUpperCase);
+ setShift(preferUpperCase);
else
autoCapitalize();
}
@@ -242,25 +289,25 @@ void ShiftHandler::reset()
void ShiftHandler::autoCapitalize()
{
Q_D(ShiftHandler);
- if (d->inputContext->capsLock())
+ if (d->capsLock)
return;
if (!d->autoCapitalizationEnabled || !d->inputContext->preeditText().isEmpty()) {
- d->inputContext->setShift(false);
+ setShift(false);
} else {
int cursorPosition = d->inputContext->cursorPosition();
bool preferLowerCase = d->inputContext->inputMethodHints() & Qt::ImhPreferLowercase;
if (cursorPosition == 0) {
- d->inputContext->setShift(!preferLowerCase);
+ setShift(!preferLowerCase);
} else {
QString text = d->inputContext->surroundingText();
text.truncate(cursorPosition);
text = text.trimmed();
if (text.length() == 0)
- d->inputContext->setShift(!preferLowerCase);
+ setShift(!preferLowerCase);
else if (text.length() > 0 && d->sentenceEndingCharacters.indexOf(text[text.length() - 1]) >= 0)
- d->inputContext->setShift(!preferLowerCase);
+ setShift(!preferLowerCase);
else
- d->inputContext->setShift(false);
+ setShift(false);
}
}
}
@@ -276,12 +323,6 @@ void ShiftHandler::restart()
reset();
}
-void ShiftHandler::shiftChanged()
-{
- Q_D(ShiftHandler);
- d->shiftChanged = true;
-}
-
void ShiftHandler::localeChanged()
{
Q_D(ShiftHandler);
diff --git a/src/virtualkeyboard/shifthandler_p.h b/src/virtualkeyboard/shifthandler_p.h
index d7a31d14..437b52fa 100644
--- a/src/virtualkeyboard/shifthandler_p.h
+++ b/src/virtualkeyboard/shifthandler_p.h
@@ -58,8 +58,12 @@ class QVIRTUALKEYBOARD_EXPORT ShiftHandler : public QObject
Q_PROPERTY(QString sentenceEndingCharacters READ sentenceEndingCharacters WRITE setSentenceEndingCharacters NOTIFY sentenceEndingCharactersChanged)
Q_PROPERTY(bool autoCapitalizationEnabled READ autoCapitalizationEnabled NOTIFY autoCapitalizationEnabledChanged)
Q_PROPERTY(bool toggleShiftEnabled READ toggleShiftEnabled NOTIFY toggleShiftEnabledChanged)
+ Q_PROPERTY(bool shift READ shift WRITE setShift NOTIFY shiftChanged)
+ Q_PROPERTY(bool capsLock READ capsLock WRITE setCapsLock NOTIFY capsLockChanged)
+ Q_PROPERTY(bool uppercase READ uppercase NOTIFY uppercaseChanged)
explicit ShiftHandler(InputContext *parent = nullptr);
+ void init();
public:
~ShiftHandler();
@@ -68,6 +72,11 @@ public:
void setSentenceEndingCharacters(const QString &value);
bool autoCapitalizationEnabled() const;
bool toggleShiftEnabled() const;
+ bool shift() const;
+ void setShift(bool enable);
+ bool capsLock() const;
+ void setCapsLock(bool enable);
+ bool uppercase() const;
Q_INVOKABLE void toggleShift();
Q_INVOKABLE void clearToggleShiftTimer();
@@ -76,13 +85,15 @@ signals:
void sentenceEndingCharactersChanged();
void toggleShiftEnabledChanged();
void autoCapitalizationEnabledChanged();
+ void shiftChanged();
+ void capsLockChanged();
+ void uppercaseChanged();
private slots:
void reset();
void autoCapitalize();
void restart();
void localeChanged();
- void shiftChanged();
void inputMethodVisibleChanged();
private:
@@ -91,6 +102,7 @@ private:
private:
friend class InputContext;
+ friend class InputContextPrivate;
};
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/virtualkeyboard.pro b/src/virtualkeyboard/virtualkeyboard.pro
index 48fb5082..a45d25eb 100644
--- a/src/virtualkeyboard/virtualkeyboard.pro
+++ b/src/virtualkeyboard/virtualkeyboard.pro
@@ -15,6 +15,7 @@ include(../config.pri)
SOURCES += \
platforminputcontext.cpp \
inputcontext.cpp \
+ inputcontext_p.cpp \
abstractinputmethod.cpp \
plaininputmethod.cpp \
inputengine.cpp \
@@ -39,6 +40,7 @@ SOURCES += \
HEADERS += \
platforminputcontext_p.h \
inputcontext.h \
+ inputcontext_p.h \
abstractinputmethod.h \
plaininputmethod_p.h \
inputengine.h \
diff --git a/tests/auto/inputpanel/data/inputpanel/inputpanel.qml b/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
index c3682b8a..01fc2ede 100644
--- a/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
+++ b/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
@@ -47,8 +47,8 @@ InputPanel {
readonly property int cursorPosition: InputContext.cursorPosition
readonly property string preeditText: InputContext.preeditText
readonly property string surroundingText: InputContext.surroundingText
- readonly property bool autoCapitalizationEnabled: InputContext.shiftHandler.autoCapitalizationEnabled
- readonly property bool toggleShiftEnabled: InputContext.shiftHandler.toggleShiftEnabled
+ readonly property bool autoCapitalizationEnabled: InputContext.priv.shiftHandler.autoCapitalizationEnabled
+ readonly property bool toggleShiftEnabled: InputContext.priv.shiftHandler.toggleShiftEnabled
readonly property string locale: keyboard.locale
readonly property string defaultLocale: VirtualKeyboardSettings.locale
readonly property var availableLocales: VirtualKeyboardSettings.availableLocales
@@ -384,12 +384,12 @@ InputPanel {
} else if (typeof key != "number" || key !== Qt.Key_Shift) {
// Some layouts (such as Arabic, Hindi) may have a second layout
virtualKeyClick(Qt.Key_Shift)
- InputContext.shiftHandler.clearToggleShiftTimer()
+ InputContext.priv.shiftHandler.clearToggleShiftTimer()
testcase.waitForRendering(inputPanel)
success = keyActionOnCurrentLayoutCb(key)
if (!success) {
virtualKeyClick(Qt.Key_Shift)
- InputContext.shiftHandler.clearToggleShiftTimer()
+ InputContext.priv.shiftHandler.clearToggleShiftTimer()
testcase.waitForRendering(inputPanel)
}
}
@@ -534,15 +534,15 @@ InputPanel {
}
function toggleShift() {
- InputContext.shiftHandler.toggleShift()
+ InputContext.priv.shiftHandler.toggleShift()
}
function setShift(shift) {
- InputContext.shift = shift
+ InputContext.priv.shiftHandler.shift = shift
}
function setCapsLock(capsLock) {
- InputContext.capsLock = capsLock
+ InputContext.priv.shiftHandler.capsLock = capsLock
}
function style() {