aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Koivikko <jarkko.koivikko@code-q.fi>2018-08-21 12:24:35 +0300
committerJarkko Koivikko <jarkko.koivikko@code-q.fi>2018-08-27 12:43:11 +0000
commitd16972ea958dcf47e9ccd8255d0d83861ba01aae (patch)
tree1216a6650ac1fba474ee06fe53521cff46576026
parent334116f863bd548532b51ed6f8d71617500fd7b0 (diff)
Trim InputContext API
The purpose of this change is to reduce the number of public API in the virtual keyboard. This change moves a lot of stuff from InputContext to ShiftHandler and InputContextPrivate and exposes the private API to QML through InputContext.priv property. Almost all the unrelevant APIs were moved away, except some properties and methods needed by selection control. These were left intact because moving them is not trivial. Change-Id: I1f23f5f54bc21c68996cb220a66d16d34b5d14ce Reviewed-by: Jarkko Koivikko <jarkko.koivikko@code-q.fi> Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
-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() {