aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.qmake.conf2
-rw-r--r--src/virtualkeyboard/3rdparty/t9write/unpack.py1
-rw-r--r--src/virtualkeyboard/content/InputPanel.qml46
-rw-r--r--src/virtualkeyboard/content/components/ChangeLanguageKey.qml2
-rw-r--r--src/virtualkeyboard/content/components/Keyboard.qml22
-rw-r--r--src/virtualkeyboard/doc/snippets/qtvirtualkeyboard-custom-language-popup.qml128
-rw-r--r--src/virtualkeyboard/doc/src/user-guide.qdoc1
-rw-r--r--src/virtualkeyboard/hunspellinputmethod.cpp2
-rw-r--r--src/virtualkeyboard/inputcontext.cpp1
-rw-r--r--src/virtualkeyboard/inputselectionhandle.h4
-rw-r--r--src/virtualkeyboard/lipiinputmethod.cpp3
-rw-r--r--src/virtualkeyboard/openwnninputmethod.cpp1
-rw-r--r--src/virtualkeyboard/plugin.cpp1
-rw-r--r--src/virtualkeyboard/t9write.h1
-rw-r--r--src/virtualkeyboard/t9writeinputmethod.cpp431
-rw-r--r--src/virtualkeyboard/t9writeinputmethod.h4
-rw-r--r--src/virtualkeyboard/t9writeworker.cpp112
-rw-r--r--src/virtualkeyboard/t9writeworker.h15
-rw-r--r--tests/auto/inputpanel/data/inputpanel/inputpanel.qml11
-rw-r--r--tests/auto/inputpanel/data/tst_inputpanel.qml18
21 files changed, 596 insertions, 212 deletions
diff --git a/.gitignore b/.gitignore
index 60fd4717..8f13f03c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
# This file is used to ignore files that should not be committed
# --------------------------------------------------------------
-examples/virtualkeyboard/basic
+examples/virtualkeyboard/basic/basic
!src/virtualkeyboard/3rdparty/hunspell/hunspell.pro
src/virtualkeyboard/3rdparty/hunspell/*
src/virtualkeyboard/3rdparty/hunspell/doc/html
diff --git a/.qmake.conf b/.qmake.conf
index 0338efe0..dc68d388 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,3 @@
load(qt_build_config)
-MODULE_VERSION = 5.10.1
+MODULE_VERSION = 5.11.0
diff --git a/src/virtualkeyboard/3rdparty/t9write/unpack.py b/src/virtualkeyboard/3rdparty/t9write/unpack.py
index e6a3e7a1..d3a67923 100644
--- a/src/virtualkeyboard/3rdparty/t9write/unpack.py
+++ b/src/virtualkeyboard/3rdparty/t9write/unpack.py
@@ -87,6 +87,7 @@ UNPACK_RULES = [
'*/decumaFunctionalSupportCheck.h',
'*/decumaLanguages.h',
'*/decumaLiteFunctionalSupport.h',
+ '*/decumaPlusFunctionalSupport.h',
'*/decumaRuntimeMallocData.h',
'*/decumaStatus.h',
'*/decumaStorageSpecifiers.h',
diff --git a/src/virtualkeyboard/content/InputPanel.qml b/src/virtualkeyboard/content/InputPanel.qml
index f9d25a02..3f88bb30 100644
--- a/src/virtualkeyboard/content/InputPanel.qml
+++ b/src/virtualkeyboard/content/InputPanel.qml
@@ -61,6 +61,52 @@ Item {
*/
property alias active: keyboard.active
+ /*!
+ \qmlproperty bool InputPanel::externalLanguageSwitchEnabled
+ \since QtQuick.VirtualKeyboard 2.4
+
+ This property enables the external language switch mechanism.
+ When this property is \c true, the virtual keyboard will not show
+ the built-in language popup, but will emit the \l externalLanguageSwitch
+ signal instead. The application can handle this signal and show a
+ custom language selection dialog instead.
+ */
+ property bool externalLanguageSwitchEnabled
+
+ /*!
+ \qmlsignal InputPanel::externalLanguageSwitch(var localeList, int currentIndex)
+ \since QtQuick.VirtualKeyboard 2.4
+
+ This signal is emitted when \l externalLanguageSwitchEnabled is \c true
+ and the \l {user-guide-language}{language switch key} is pressed by the user.
+
+ It serves as a hook to display a custom language dialog instead of
+ the built-in language popup in the virtual keyboard.
+
+ The \a localeList parameter contains a list of locale names to choose
+ from. To get more information about a particular language, use the \l Qt.locale()
+ function. The \a currentIndex is the index of current locale in the
+ \a localeList. This item should be highlighted as the current item in the UI.
+
+ To select a new language, use the \l {VirtualKeyboardSettings::locale}
+ {VirtualKeyboardSettings.locale} property.
+
+ Below is an example that demonstrates a custom language dialog implementation:
+
+ \snippet qtvirtualkeyboard-custom-language-popup.qml popup
+
+ The dialog would then be declared:
+
+ \snippet qtvirtualkeyboard-custom-language-popup.qml declaring
+
+ In the application's InputPanel, add the following code:
+
+ \snippet qtvirtualkeyboard-custom-language-popup.qml using
+
+ The custom dialog will now be shown when the language switch key is pressed.
+ */
+ signal externalLanguageSwitch(var localeList, int currentIndex)
+
/*! \internal */
property alias keyboard: keyboard
diff --git a/src/virtualkeyboard/content/components/ChangeLanguageKey.qml b/src/virtualkeyboard/content/components/ChangeLanguageKey.qml
index b14e70f4..70e12fa4 100644
--- a/src/virtualkeyboard/content/components/ChangeLanguageKey.qml
+++ b/src/virtualkeyboard/content/components/ChangeLanguageKey.qml
@@ -71,7 +71,7 @@ BaseKey {
keyPanelDelegate: keyboard.style ? keyboard.style.languageKeyPanel : undefined
onClicked: {
if (keyboard.style.languagePopupListEnabled)
- keyboard.showLanguagePopup(changeLanguageKey, customLayoutsOnly)
+ keyboard.showLanguagePopup(changeLanguageKey, false)
else
keyboard.changeInputLanguage(customLayoutsOnly)
}
diff --git a/src/virtualkeyboard/content/components/Keyboard.qml b/src/virtualkeyboard/content/components/Keyboard.qml
index 22378b44..5a2e76eb 100644
--- a/src/virtualkeyboard/content/components/Keyboard.qml
+++ b/src/virtualkeyboard/content/components/Keyboard.qml
@@ -1069,9 +1069,20 @@ Item {
function showLanguagePopup(parentItem, customLayoutsOnly) {
if (!languagePopupList.enabled) {
- var locales = keyboard.listLocales(customLayoutsOnly)
+ var locales = keyboard.listLocales(customLayoutsOnly, parent.externalLanguageSwitchEnabled)
+ if (parent.externalLanguageSwitchEnabled) {
+ var currentIndex = 0
+ for (var i = 0; i < locales.length; i++) {
+ if (locales[i] === keyboard.locale) {
+ currentIndex = i
+ break
+ }
+ }
+ parent.externalLanguageSwitch(locales, currentIndex)
+ return
+ }
languageListModel.clear()
- for (var i = 0; i < locales.length; i++) {
+ for (i = 0; i < locales.length; i++) {
languageListModel.append({localeName: locales[i].name, displayName: locales[i].locale.nativeLanguageName, localeIndex: locales[i].index})
if (locales[i].index === keyboard.localeIndex)
languagePopupList.currentIndex = i
@@ -1269,12 +1280,15 @@ Item {
availableCustomLocaleIndices = newIndices
}
- function listLocales(customLayoutsOnly) {
+ function listLocales(customLayoutsOnly, localeNameOnly) {
var locales = []
var localeIndices = customLayoutsOnly ? availableCustomLocaleIndices : availableLocaleIndices
for (var i = 0; i < localeIndices.length; i++) {
var layoutFolder = layoutsModel.get(localeIndices[i], "fileName")
- locales.push({locale:Qt.locale(layoutFolder), index:localeIndices[i], name:layoutFolder})
+ if (localeNameOnly)
+ locales.push(layoutFolder)
+ else
+ locales.push({locale:Qt.locale(layoutFolder), index:localeIndices[i], name:layoutFolder})
}
return locales
}
diff --git a/src/virtualkeyboard/doc/snippets/qtvirtualkeyboard-custom-language-popup.qml b/src/virtualkeyboard/doc/snippets/qtvirtualkeyboard-custom-language-popup.qml
new file mode 100644
index 00000000..261ad9be
--- /dev/null
+++ b/src/virtualkeyboard/doc/snippets/qtvirtualkeyboard-custom-language-popup.qml
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// ![popup]
+Dialog {
+ id: languageDialog
+ title: "Select Input Language"
+ modality: Qt.ApplicationModal
+
+ function show(localeList, currentIndex) {
+ languageListModel.clear()
+ for (var i = 0; i < localeList.length; i++) {
+ languageListModel.append({localeName: localeList[i], displayName: Qt.locale(localeList[i]).nativeLanguageName})
+ }
+ languageListView.currentIndex = currentIndex
+ languageListView.positionViewAtIndex(currentIndex, ListView.Center)
+ languageDialog.visible = true
+ }
+
+ contentItem: ListView {
+ id: languageListView
+ model: ListModel {
+ id: languageListModel
+ function selectItem(index) {
+ VirtualKeyboardSettings.locale = languageListModel.get(index).localeName
+ languageDialog.visible = false
+ }
+ }
+ delegate: Item {
+ id: languageListItem
+ width: languageNameTextMetrics.width * 17
+ height: languageNameTextMetrics.height + languageListLabel.anchors.topMargin + languageListLabel.anchors.bottomMargin
+ Text {
+ id: languageListLabel
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.leftMargin: languageNameTextMetrics.height / 2
+ anchors.rightMargin: anchors.leftMargin
+ anchors.topMargin: languageNameTextMetrics.height / 3
+ anchors.bottomMargin: anchors.topMargin
+ text: languageNameFormatter.elidedText
+ color: "#5CAA15"
+ font {
+ weight: Font.Normal
+ pixelSize: 28
+ }
+ }
+ TextMetrics {
+ id: languageNameTextMetrics
+ font {
+ weight: Font.Normal
+ pixelSize: 28
+ }
+ text: "X"
+ }
+ TextMetrics {
+ id: languageNameFormatter
+ font {
+ weight: Font.Normal
+ pixelSize: 28
+ }
+ elide: Text.ElideRight
+ elideWidth: languageListItem.width - languageListLabel.anchors.leftMargin - languageListLabel.anchors.rightMargin
+ text: displayName
+ }
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: {
+ if (index === -1)
+ return
+ parent.ListView.view.currentIndex = index
+ parent.ListView.view.model.selectItem(index)
+ }
+ }
+ states: State {
+ name: "current"
+ when: languageListItem.ListView.isCurrentItem
+ PropertyChanges {
+ target: languageListLabel
+ color: "black"
+ }
+ }
+ }
+ }
+}
+// ![popup]
+
+// ![declaring]
+LanguageDialog {
+ id: languageDialog
+ width: 400
+ height: 400
+}
+// ![declaring]
+
+// ![using]
+InputPanel {
+ id: inputPanel
+ externalLanguageSwitchEnabled: true
+ onExternalLanguageSwitch: languageDialog.show(localeList, currentIndex)
+ // ...
+}
+// ![using]
diff --git a/src/virtualkeyboard/doc/src/user-guide.qdoc b/src/virtualkeyboard/doc/src/user-guide.qdoc
index c2d9d9f0..67ea6747 100644
--- a/src/virtualkeyboard/doc/src/user-guide.qdoc
+++ b/src/virtualkeyboard/doc/src/user-guide.qdoc
@@ -44,6 +44,7 @@ Once \l {Deployment Guide}{properly installed}, the virtual keyboard can be
opened by clicking on a text input field.
\section1 Language
+\target user-guide-language
The language can be changed by pressing the language key, which is illustrated
with a "globe" icon:
diff --git a/src/virtualkeyboard/hunspellinputmethod.cpp b/src/virtualkeyboard/hunspellinputmethod.cpp
index 76b5f654..87134162 100644
--- a/src/virtualkeyboard/hunspellinputmethod.cpp
+++ b/src/virtualkeyboard/hunspellinputmethod.cpp
@@ -90,7 +90,6 @@ bool HunspellInputMethod::setTextCase(InputEngine::TextCase textCase)
bool HunspellInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers)
{
- Q_UNUSED(modifiers)
Q_D(HunspellInputMethod);
InputContext *ic = inputContext();
Qt::InputMethodHints inputMethodHints = ic->inputMethodHints();
@@ -196,7 +195,6 @@ int HunspellInputMethod::selectionListItemCount(SelectionListModel::Type type)
QVariant HunspellInputMethod::selectionListData(SelectionListModel::Type type, int index, int role)
{
QVariant result;
- Q_UNUSED(type)
Q_D(HunspellInputMethod);
switch (role) {
case SelectionListModel::DisplayRole:
diff --git a/src/virtualkeyboard/inputcontext.cpp b/src/virtualkeyboard/inputcontext.cpp
index e23f6e46..2c2c8fcf 100644
--- a/src/virtualkeyboard/inputcontext.cpp
+++ b/src/virtualkeyboard/inputcontext.cpp
@@ -719,7 +719,6 @@ void InputContext::externalCommit()
void InputContext::update(Qt::InputMethodQueries queries)
{
Q_D(InputContext);
- Q_UNUSED(queries);
// No need to fetch input clip rectangle during animation
if (!(queries & ~Qt::ImInputItemClipRectangle) && d->animating)
diff --git a/src/virtualkeyboard/inputselectionhandle.h b/src/virtualkeyboard/inputselectionhandle.h
index e4c3e910..5d70df2b 100644
--- a/src/virtualkeyboard/inputselectionhandle.h
+++ b/src/virtualkeyboard/inputselectionhandle.h
@@ -49,8 +49,8 @@ public:
void applyImage(const QSize &windowSize);
protected:
- void paintEvent(QPaintEvent *pe) Q_DECL_OVERRIDE;
- bool event(QEvent *event) Q_DECL_OVERRIDE;
+ void paintEvent(QPaintEvent *pe) override;
+ bool event(QEvent *event) override;
private:
DesktopInputSelectionControl *m_control;
diff --git a/src/virtualkeyboard/lipiinputmethod.cpp b/src/virtualkeyboard/lipiinputmethod.cpp
index 10dcb4ae..5bb1d46c 100644
--- a/src/virtualkeyboard/lipiinputmethod.cpp
+++ b/src/virtualkeyboard/lipiinputmethod.cpp
@@ -500,10 +500,11 @@ QList<InputEngine::InputMode> LipiInputMethod::inputModes(const QString &locale)
bool LipiInputMethod::setInputMode(const QString &locale, InputEngine::InputMode inputMode)
{
- Q_UNUSED(locale)
Q_D(LipiInputMethod);
#ifdef HAVE_HUNSPELL
HunspellInputMethod::setInputMode(locale, inputMode);
+#else
+ Q_UNUSED(locale)
#endif
bool result = d->recognizer.setModel(QStringLiteral("SHAPEREC_ALPHANUM"));
if (!result)
diff --git a/src/virtualkeyboard/openwnninputmethod.cpp b/src/virtualkeyboard/openwnninputmethod.cpp
index edba99c0..d94f212a 100644
--- a/src/virtualkeyboard/openwnninputmethod.cpp
+++ b/src/virtualkeyboard/openwnninputmethod.cpp
@@ -784,7 +784,6 @@ int OpenWnnInputMethod::selectionListItemCount(SelectionListModel::Type type)
QVariant OpenWnnInputMethod::selectionListData(SelectionListModel::Type type, int index, int role)
{
QVariant result;
- Q_UNUSED(type)
Q_D(OpenWnnInputMethod);
switch (role) {
case SelectionListModel::DisplayRole:
diff --git a/src/virtualkeyboard/plugin.cpp b/src/virtualkeyboard/plugin.cpp
index 136bba80..b0571116 100644
--- a/src/virtualkeyboard/plugin.cpp
+++ b/src/virtualkeyboard/plugin.cpp
@@ -85,7 +85,6 @@ static QPointer<PlatformInputContext> platformInputContext;
static QObject *createInputContextModule(QQmlEngine *engine, QJSEngine *scriptEngine)
{
- Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
QQmlContext *rootContext = engine->rootContext();
QStringList inputMethodList = QStringList()
diff --git a/src/virtualkeyboard/t9write.h b/src/virtualkeyboard/t9write.h
index 621d2312..beebbaa2 100644
--- a/src/virtualkeyboard/t9write.h
+++ b/src/virtualkeyboard/t9write.h
@@ -37,6 +37,7 @@
#ifdef HAVE_T9WRITE_CJK
#include "decuma_hwr_cjk.h"
#endif
+#include "decumaFunctionalSupport.h"
#if defined(HAVE_T9WRITE_CJK) && defined(HAVE_T9WRITE_ALPHABETIC)
#define DECUMA_API(FUNC_NAME) (cjk ? decumaCJK ## FUNC_NAME : decuma ## FUNC_NAME)
diff --git a/src/virtualkeyboard/t9writeinputmethod.cpp b/src/virtualkeyboard/t9writeinputmethod.cpp
index 14b6508b..329bdbd3 100644
--- a/src/virtualkeyboard/t9writeinputmethod.cpp
+++ b/src/virtualkeyboard/t9writeinputmethod.cpp
@@ -130,6 +130,7 @@ public:
attachedDictionary(0),
traceListHardLimit(32),
resultId(0),
+ lastResultId(0),
resultTimer(0),
decumaSession(0),
activeWordIndex(-1),
@@ -166,7 +167,6 @@ public:
static QMutex s_logMutex;
static QByteArray s_logString;
Q_UNUSED(pUserData)
- Q_UNUSED(nLogStringLength)
QMutexLocker guard(&s_logMutex);
s_logString.append(pLogString, nLogStringLength);
if (s_logString.endsWith('\n')) {
@@ -231,7 +231,6 @@ public:
languageCategories.append(DECUMA_LANG_EN);
sessionSettings.recognitionMode = mcrMode;
- sessionSettings.bMinimizeAddArcPreProcessing = 1;
sessionSettings.writingDirection = unknownWriting;
sessionSettings.charSet.pSymbolCategories = symbolCategories.data();
sessionSettings.charSet.nSymbolCategories = symbolCategories.size();
@@ -256,6 +255,9 @@ public:
worker.reset(new T9WriteWorker(decumaSession, cjk));
worker->start();
+ Q_Q(T9WriteInputMethod);
+ processResultConnection = QObject::connect(q, &T9WriteInputMethod::resultListChanged, q, &T9WriteInputMethod::processResult, Qt::QueuedConnection);
+
return true;
}
@@ -263,6 +265,9 @@ public:
{
VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::exitEngine()";
+ if (processResultConnection)
+ QObject::disconnect(processResultConnection);
+
worker.reset();
if (sessionSettings.pStaticDB) {
@@ -449,7 +454,7 @@ public:
updateDictionary(language, locale, languageChanged);
static const QList<DECUMA_UINT32> rtlLanguages = QList<DECUMA_UINT32>()
<< DECUMA_LANG_AR << DECUMA_LANG_IW << DECUMA_LANG_FA << DECUMA_LANG_UR;
- sessionSettings.writingDirection = rtlLanguages.contains(language) ? rightToLeft : unknownWriting;
+ sessionSettings.writingDirection = rtlLanguages.contains(language) ? rightToLeft : leftToRight;
// Enable multi-threaded recognition if available.
#ifdef DECUMA_USE_MULTI_THREAD
@@ -686,13 +691,38 @@ public:
Q_Q(T9WriteInputMethod);
Q_UNUSED(language)
Q_UNUSED(locale)
- Q_UNUSED(inputMode)
// Select recognition mode
// Note: MCR mode is preferred, as it does not require recognition
// timer and provides better user experience.
sessionSettings.recognitionMode = mcrMode;
+ // T9 Write Alphabetic v8.0.0 supports UCR mode for specific languages
+#if T9WRITEAPIMAJORVERNUM >= 21
+ if (!cjk) {
+ switch (inputMode) {
+ case InputEngine::Latin:
+ switch (language) {
+ case DECUMA_LANG_EN:
+ case DECUMA_LANG_FR:
+ case DECUMA_LANG_IT:
+ case DECUMA_LANG_DE:
+ case DECUMA_LANG_ES:
+ sessionSettings.recognitionMode = ucrMode;
+ break;
+ default:
+ break;
+ }
+ break;
+ case InputEngine::Arabic:
+ sessionSettings.recognitionMode = ucrMode;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+
// Use scrMode with hidden text or with no predictive mode
if (inputMode != InputEngine::ChineseHandwriting &&
inputMode != InputEngine::JapaneseHandwriting &&
@@ -800,7 +830,6 @@ public:
bool updateSymbolCategoriesCjk(DECUMA_UINT32 language, const QLocale &locale,
InputEngine::InputMode inputMode)
{
- Q_UNUSED(language)
Q_ASSERT(cjk);
symbolCategories.clear();
@@ -944,7 +973,7 @@ public:
}
// Attach existing dictionary, if available
- if (sessionSettings.recognitionMode == mcrMode && !inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
+ if (sessionSettings.recognitionMode != scrMode && !inputMethodHints.testFlag(Qt::ImhNoPredictiveText) &&
loadedDictionary && !attachedDictionary) {
if (attachDictionary(loadedDictionary))
attachedDictionary = loadedDictionary;
@@ -970,9 +999,10 @@ public:
void setContext(InputEngine::PatternRecognitionMode patternRecognitionMode,
const QVariantMap &traceCaptureDeviceInfo,
- const QVariantMap &traceScreenInfo)
+ const QVariantMap &traceScreenInfo,
+ const QByteArray &context)
{
- QByteArray context = getContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo);
+ Q_UNUSED(patternRecognitionMode)
if (context == currentContext)
return;
currentContext = context;
@@ -1025,13 +1055,13 @@ public:
Trace *traceBegin(int traceId, InputEngine::PatternRecognitionMode patternRecognitionMode,
const QVariantMap &traceCaptureDeviceInfo, const QVariantMap &traceScreenInfo)
{
- Q_UNUSED(traceId)
- Q_UNUSED(patternRecognitionMode)
- Q_UNUSED(traceScreenInfo)
-
if (!worker)
return 0;
+ // The result id follows the trace id so that the (previous)
+ // results completed during the handwriting can be rejected.
+ resultId = traceId;
+
stopResultTimer();
// Dictionary must be completed before the arc addition can begin
@@ -1042,10 +1072,9 @@ public:
// Cancel the current recognition task
worker->removeAllTasks<T9WriteRecognitionResultsTask>();
+ worker->removeAllTasks<T9WriteRecognitionTask>();
if (recognitionTask) {
recognitionTask->cancelRecognition();
- recognitionTask->wait();
- worker->removeTask(recognitionTask);
recognitionTask.reset();
}
@@ -1054,25 +1083,21 @@ public:
unipenTrace.reset(new UnipenTrace(traceCaptureDeviceInfo, traceScreenInfo));
#endif
- setContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo);
+ QByteArray context = getContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo);
+ if (context != currentContext) {
+ worker->waitForAllTasks();
+ setContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo, context);
+ }
DECUMA_STATUS status;
if (!arcAdditionStarted) {
+ worker->waitForAllTasks();
status = DECUMA_API(BeginArcAddition)(decumaSession);
Q_ASSERT(status == decumaNoError);
arcAdditionStarted = true;
}
- DECUMA_UINT32 arcID = (DECUMA_UINT32)traceId;
- status = DECUMA_API(StartNewArc)(decumaSession, arcID);
- Q_ASSERT(status == decumaNoError);
- if (status != decumaNoError) {
- DECUMA_API(EndArcAddition)(decumaSession);
- arcAdditionStarted = false;
- return NULL;
- }
-
Trace *trace = new Trace();
#ifdef QT_VIRTUALKEYBOARD_RECORD_TRACE_INPUT
trace->setChannels(QStringList("t"));
@@ -1085,25 +1110,21 @@ public:
void traceEnd(Trace *trace)
{
if (trace->isCanceled()) {
- DECUMA_API(CancelArc)(decumaSession, trace->traceId());
traceList.removeOne(trace);
delete trace;
} else {
- addPointsToTraceGroup(trace);
+ if (cjk && countActiveTraces() == 0) {
+ // For some reason gestures don't seem to work in CJK mode
+ // Using our own gesture recognizer as fallback
+ if (handleGesture())
+ return;
+ }
+ worker->addTask(QSharedPointer<T9WriteAddArcTask>(new T9WriteAddArcTask(trace)));
}
if (!traceList.isEmpty()) {
Q_ASSERT(arcAdditionStarted);
- if (countActiveTraces() == 0) {
+ if (countActiveTraces() == 0)
restartRecognition();
- if (cjk) {
- // For some reason gestures don't seem to work in CJK mode
- // Using our own gesture recognizer as fallback
- handleGesture();
- }
- }
- } else if (arcAdditionStarted) {
- DECUMA_API(EndArcAddition)(decumaSession);
- arcAdditionStarted = false;
}
}
@@ -1119,37 +1140,11 @@ public:
void clearTraces()
{
+ worker->waitForAllTasks();
qDeleteAll(traceList);
traceList.clear();
}
- void addPointsToTraceGroup(Trace *trace)
- {
- Q_ASSERT(decumaSession != 0);
-
- const QVariantList points = trace->points();
- Q_ASSERT(!points.isEmpty());
- DECUMA_UINT32 arcID = (DECUMA_UINT32)trace->traceId();
- DECUMA_STATUS status;
-
- for (const QVariant &p : points) {
- const QPoint pt(p.toPointF().toPoint());
- status = DECUMA_API(AddPoint)(decumaSession, (DECUMA_COORD)pt.x(),(DECUMA_COORD)pt.y(), arcID);
- if (status != decumaNoError) {
- VIRTUALKEYBOARD_DEBUG() << "decumaAddPoint failed" << status;
- finishRecognition();
- return;
- }
- }
-
- status = DECUMA_API(CommitArc)(decumaSession, arcID);
- if (status != decumaNoError) {
- VIRTUALKEYBOARD_DEBUG() << "decumaCommitArc failed" << status;
- finishRecognition();
- return;
- }
- }
-
void noteSelected(int index)
{
if (wordCandidatesHwrResultIndex.isEmpty())
@@ -1169,10 +1164,24 @@ public:
Q_Q(T9WriteInputMethod);
- QSharedPointer<T9WriteRecognitionResult> recognitionResult(new T9WriteRecognitionResult(++resultId, 9, 64));
+ worker->removeAllTasks<T9WriteRecognitionResultsTask>();
+ if (recognitionTask) {
+ recognitionTask->cancelRecognition();
+ recognitionTask.reset();
+ }
+
+ // Boost dictionary words by default
+ BOOST_LEVEL boostLevel = attachedDictionary ? boostDictWords : noBoost;
+
+ // Disable dictionary boost in UCR mode for URL and E-mail input
+ // Otherwise it will completely mess input
+ const Qt::InputMethodHints inputMethodHints = q->inputContext()->inputMethodHints();
+ if (sessionSettings.recognitionMode == ucrMode && (inputMethodHints & (Qt::ImhUrlCharactersOnly | Qt::ImhEmailCharactersOnly)))
+ boostLevel = noBoost;
+
+ QSharedPointer<T9WriteRecognitionResult> recognitionResult(new T9WriteRecognitionResult(resultId, 9, 64));
recognitionTask.reset(new T9WriteRecognitionTask(recognitionResult, instantGestureSettings,
- attachedDictionary ? boostDictWords : noBoost,
- stringStart));
+ boostLevel, stringStart));
worker->addTask(recognitionTask);
QSharedPointer<T9WriteRecognitionResultsTask> resultsTask(new T9WriteRecognitionResultsTask(recognitionResult));
@@ -1182,6 +1191,16 @@ public:
resetResultTimer();
}
+ void waitForRecognitionResults()
+ {
+ if (!worker)
+ return;
+
+ VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::waitForRecognitionResults()";
+ worker->waitForAllTasks();
+ processResult();
+ }
+
bool finishRecognition(bool emitSelectionListChanged = true)
{
VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::finishRecognition()";
@@ -1194,17 +1213,16 @@ public:
stopResultTimer();
- clearTraces();
-
+ worker->removeAllTasks<T9WriteAddArcTask>();
worker->removeAllTasks<T9WriteRecognitionResultsTask>();
if (recognitionTask) {
recognitionTask->cancelRecognition();
- recognitionTask->wait();
- worker->removeTask(recognitionTask);
recognitionTask.reset();
result = true;
}
+ clearTraces();
+
if (arcAdditionStarted) {
DECUMA_API(EndArcAddition)(decumaSession);
arcAdditionStarted = false;
@@ -1238,7 +1256,7 @@ public:
if (!worker)
return false;
- if (sessionSettings.recognitionMode == mcrMode && wordCandidates.isEmpty()) {
+ if (sessionSettings.recognitionMode != scrMode && wordCandidates.isEmpty()) {
finishRecognition();
return false;
}
@@ -1250,7 +1268,7 @@ public:
VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::select():" << index;
Q_Q(T9WriteInputMethod);
- if (sessionSettings.recognitionMode == mcrMode) {
+ if (sessionSettings.recognitionMode != scrMode) {
index = index >= 0 ? index : activeWordIndex;
noteSelected(index);
QString finalWord = wordCandidates.at(index);
@@ -1274,7 +1292,11 @@ public:
#endif
finishRecognition();
+ QChar gesture = T9WriteInputMethodPrivate::mapSymbolToGesture(finalWord.right(1).at(0));
+ if (!gesture.isNull())
+ finalWord.chop(1);
q->inputContext()->commit(finalWord);
+ applyGesture(gesture);
} else if (sessionSettings.recognitionMode == scrMode) {
QString finalWord = scrResult;
finishRecognition();
@@ -1284,12 +1306,12 @@ public:
return true;
}
- void resetResultTimer()
+ void resetResultTimer(int interval = 500)
{
- VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::resetResultTimer()";
+ VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::resetResultTimer():" << interval;
Q_Q(T9WriteInputMethod);
stopResultTimer();
- resultTimer = q->startTimer(500);
+ resultTimer = q->startTimer(interval);
}
void stopResultTimer()
@@ -1302,24 +1324,9 @@ public:
}
}
- void resultsAvailable(const QVariantList &resultList)
+ void processResult()
{
- if (!resultList.isEmpty()) {
- if (recognitionTask && recognitionTask->resultId() == resultList.first().toMap()["resultId"].toInt())
- processResult(resultList);
- }
- }
-
- void processResult(const QVariantList &resultList)
- {
- if (resultList.isEmpty())
- return;
-
- if (resultList.first().toMap()["resultId"] != resultId)
- return;
-
VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult()";
-
Q_Q(T9WriteInputMethod);
InputContext *ic = q->inputContext();
if (!ic)
@@ -1330,49 +1337,100 @@ public:
QString resultString;
QString gesture;
QVariantList symbolStrokes;
- for (int i = 0; i < resultList.size(); i++) {
- QVariantMap result = resultList.at(i).toMap();
- QString resultChars = result["chars"].toString();
- if (i == 0)
- caseFormatter.ensureLength(resultChars.length(), textCase);
- if (!resultChars.isEmpty()) {
- resultChars = caseFormatter.formatString(resultChars);
- if (sessionSettings.recognitionMode == mcrMode) {
- newWordCandidates.append(resultChars);
- newWordCandidatesHwrResultIndex.append(i);
- }
+ {
+ QMutexLocker resultListGuard(&resultListLock);
+ if (resultList.isEmpty())
+ return;
+
+ if (resultList.first().toMap()["resultId"] != resultId) {
+ VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult(): resultId mismatch" << resultList.first().toMap()["resultId"] << "(" << resultId << ")";
+ resultList.clear();
+ return;
}
- if (i == 0) {
- resultString = resultChars;
- if (result.contains("gesture"))
- gesture = result["gesture"].toString();
- if (sessionSettings.recognitionMode == mcrMode && result.contains("symbolStrokes"))
- symbolStrokes = result["symbolStrokes"].toList();
- if (sessionSettings.recognitionMode == scrMode)
- break;
+ lastResultId = resultId;
+
+ for (int i = 0; i < resultList.size(); i++) {
+ QVariantMap result = resultList.at(i).toMap();
+ QString resultChars = result["chars"].toString();
+ if (i == 0) {
+ if (ic->shift()) {
+ caseFormatter.ensureLength(1, textCase);
+ caseFormatter.ensureLength(resultChars.length(), InputEngine::Lower);
+ } else {
+ caseFormatter.ensureLength(resultChars.length(), textCase);
+ }
+ }
+ if (!resultChars.isEmpty()) {
+ resultChars = caseFormatter.formatString(resultChars);
+ if (sessionSettings.recognitionMode != scrMode) {
+ newWordCandidates.append(resultChars);
+ newWordCandidatesHwrResultIndex.append(i);
+ }
+ }
+ if (i == 0) {
+ resultString = resultChars;
+ if (result.contains("gesture"))
+ gesture = result["gesture"].toString();
+ if (sessionSettings.recognitionMode != scrMode && result.contains("symbolStrokes"))
+ symbolStrokes = result["symbolStrokes"].toList();
+ if (sessionSettings.recognitionMode == scrMode)
+ break;
+ } else {
+ // Add a gesture symbol to the secondary candidate
+ if (sessionSettings.recognitionMode != scrMode && result.contains("gesture")) {
+ QString gesture2 = result["gesture"].toString();
+ if (gesture2.length() == 1) {
+ QChar symbol = T9WriteInputMethodPrivate::mapGestureToSymbol(gesture2.at(0).unicode());
+ if (!symbol.isNull()) {
+ // Check for duplicates
+ bool duplicateFound = false;
+ for (const QString &wordCandidate : newWordCandidates) {
+ duplicateFound = wordCandidate.size() == 1 && wordCandidate.at(0) == symbol;
+ if (duplicateFound)
+ break;
+ }
+ if (!duplicateFound) {
+ if (!resultChars.isEmpty()) {
+ newWordCandidates.last().append(symbol);
+ } else {
+ newWordCandidates.append(symbol);
+ newWordCandidatesHwrResultIndex.append(i);
+ }
+ }
+ }
+ }
+ }
+ }
}
+
+ resultList.clear();
}
bool wordCandidatesChanged = wordCandidates != newWordCandidates;
#ifndef QT_VIRTUALKEYBOARD_RECORD_TRACE_INPUT
// Delete trace history
- const InputEngine::InputMode inputMode = q->inputEngine()->inputMode();
- if (sessionSettings.recognitionMode == mcrMode && !symbolStrokes.isEmpty() &&
- inputMode != InputEngine::ChineseHandwriting &&
- inputMode != InputEngine::JapaneseHandwriting &&
- inputMode != InputEngine::KoreanHandwriting) {
- int activeTraces = symbolStrokes.at(symbolStrokes.count() - 1).toInt();
- if (symbolStrokes.count() > 1)
- activeTraces += symbolStrokes.at(symbolStrokes.count() - 2).toInt();
- while (activeTraces < traceList.count())
- delete traceList.takeFirst();
- }
+ // Note: We have to be sure there are no background tasks
+ // running since the Trace objects consumed there.
+ if (worker->numberOfPendingTasks() == 0) {
+
+ const InputEngine::InputMode inputMode = q->inputEngine()->inputMode();
+ if (sessionSettings.recognitionMode == mcrMode && !symbolStrokes.isEmpty() &&
+ inputMode != InputEngine::ChineseHandwriting &&
+ inputMode != InputEngine::JapaneseHandwriting &&
+ inputMode != InputEngine::KoreanHandwriting) {
+ int activeTraces = symbolStrokes.at(symbolStrokes.count() - 1).toInt();
+ if (symbolStrokes.count() > 1)
+ activeTraces += symbolStrokes.at(symbolStrokes.count() - 2).toInt();
+ while (activeTraces < traceList.count())
+ delete traceList.takeFirst();
+ }
- // Enforce hard limit for number of traces
- if (traceList.count() >= traceListHardLimit) {
- VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult(): Clearing traces (hard limit):" << traceList.count();
- clearTraces();
+ // Enforce hard limit for number of traces
+ if (traceList.count() >= traceListHardLimit) {
+ VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult(): Clearing traces (hard limit):" << traceList.count();
+ clearTraces();
+ }
}
#endif
@@ -1380,37 +1438,20 @@ public:
if (!gesture.isEmpty()) {
DECUMA_UNICODE gestureSymbol = gesture.at(0).unicode();
- switch (gestureSymbol) {
- case '\b':
- ic->inputEngine()->virtualKeyClick(Qt::Key_Backspace, QString(), Qt::NoModifier);
- break;
-
- case '\r':
- ic->inputEngine()->virtualKeyClick(Qt::Key_Return, QLatin1String("\n"), Qt::NoModifier);
- break;
-
- case ' ':
- ic->inputEngine()->virtualKeyClick(Qt::Key_Space, QLatin1String(" "), Qt::NoModifier);
- break;
-
- default:
+ if (!applyGesture(gestureSymbol)) {
ic->commit(ic->preeditText());
finishRecognition();
- break;
}
return;
}
- if (sessionSettings.recognitionMode == mcrMode) {
+ if (sessionSettings.recognitionMode != scrMode) {
ignoreUpdate = true;
ic->setPreeditText(resultString);
ignoreUpdate = false;
- } else if (sessionSettings.recognitionMode == scrMode) {
- if (resultTimer == 0 && !resultString.isEmpty())
- ic->inputEngine()->virtualKeyClick((Qt::Key)resultString.at(0).unicode(), resultString, Qt::NoModifier);
- else
- scrResult = resultString;
+ } else {
+ scrResult = resultString;
}
if (wordCandidatesChanged) {
@@ -1420,6 +1461,51 @@ public:
emit q->selectionListChanged(SelectionListModel::WordCandidateList);
emit q->selectionListActiveItemChanged(SelectionListModel::WordCandidateList, activeWordIndex);
}
+
+ if (arcAdditionStarted && traceList.isEmpty() && worker->numberOfPendingTasks() == 0) {
+ DECUMA_API(EndArcAddition)(decumaSession);
+ arcAdditionStarted = false;
+ }
+ }
+
+ static QChar mapGestureToSymbol(const QChar &gesture)
+ {
+ switch (gesture.unicode()) {
+ case '\r':
+ return QChar(0x23CE);
+ case ' ':
+ return QChar(0x2423);
+ default:
+ return QChar();
+ }
+ }
+
+ static QChar mapSymbolToGesture(const QChar &symbol)
+ {
+ switch (symbol.unicode()) {
+ case 0x23CE:
+ return QChar('\r');
+ case 0x2423:
+ return QChar(' ');
+ default:
+ return QChar();
+ }
+ }
+
+ bool applyGesture(const QChar &gesture)
+ {
+ Q_Q(T9WriteInputMethod);
+ InputContext *ic = q->inputContext();
+ switch (gesture.unicode()) {
+ case '\b':
+ return ic->inputEngine()->virtualKeyClick(Qt::Key_Backspace, QString(), Qt::NoModifier);
+ case '\r':
+ return ic->inputEngine()->virtualKeyClick(Qt::Key_Return, QLatin1String("\n"), Qt::NoModifier);
+ case ' ':
+ return ic->inputEngine()->virtualKeyClick(Qt::Key_Space, QLatin1String(" "), Qt::NoModifier);
+ default:
+ return false;
+ }
}
bool handleGesture()
@@ -1550,8 +1636,12 @@ public:
QSharedPointer<T9WriteDictionary> attachedDictionary;
QSharedPointer<T9WriteDictionaryTask> dictionaryTask;
QSharedPointer<T9WriteRecognitionTask> recognitionTask;
+ QMutex resultListLock;
+ QVariantList resultList;
int resultId;
+ int lastResultId;
int resultTimer;
+ QMetaObject::Connection processResultConnection;
QByteArray session;
DECUMA_SESSION *decumaSession;
QStringList wordCandidates;
@@ -1693,7 +1783,6 @@ bool T9WriteInputMethod::setTextCase(InputEngine::TextCase textCase)
bool T9WriteInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers)
{
- Q_UNUSED(text)
Q_UNUSED(modifiers)
Q_D(T9WriteInputMethod);
switch (key) {
@@ -1715,6 +1804,7 @@ bool T9WriteInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboard
// WA: T9Write CJK may crash in some cases with long stringStart.
// Therefore we commit the current input and finish the recognition.
if (d->cjk) {
+ d->waitForRecognitionResults();
ic->commit();
d->finishRecognition();
return true;
@@ -1742,7 +1832,8 @@ bool T9WriteInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboard
}
default:
- if (d->sessionSettings.recognitionMode == mcrMode && text.length() > 0) {
+ if (d->sessionSettings.recognitionMode != scrMode && text.length() > 0) {
+ d->waitForRecognitionResults();
InputContext *ic = inputContext();
QString preeditText = ic->preeditText();
QChar c = text.at(0);
@@ -1761,7 +1852,7 @@ bool T9WriteInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboard
emit selectionListActiveItemChanged(SelectionListModel::WordCandidateList, d->activeWordIndex);
return true;
} else {
- ic->clear();
+ ic->commit();
d->finishRecognition();
}
break;
@@ -1802,7 +1893,6 @@ int T9WriteInputMethod::selectionListItemCount(SelectionListModel::Type type)
QVariant T9WriteInputMethod::selectionListData(SelectionListModel::Type type, int index, int role)
{
QVariant result;
- Q_UNUSED(type)
Q_D(T9WriteInputMethod);
switch (role) {
case SelectionListModel::DisplayRole:
@@ -1934,9 +2024,25 @@ void T9WriteInputMethod::timerEvent(QTimerEvent *timerEvent)
int timerId = timerEvent->timerId();
VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethod::timerEvent():" << timerId;
if (timerId == d->resultTimer) {
- if (d->sessionSettings.recognitionMode == mcrMode) {
- d->stopResultTimer();
+ d->stopResultTimer();
+
+ // Ignore if the result is not yet available
+ if (d->resultId != d->lastResultId) {
+ VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethod::timerEvent(): Result not yet available";
+ return;
+ }
+
+ if (d->sessionSettings.recognitionMode != scrMode) {
#ifndef QT_VIRTUALKEYBOARD_RECORD_TRACE_INPUT
+ // Don't clear traces in UCR mode if dictionary is loaded.
+ // In UCR mode the whole purpose is to write the word with
+ // one or few strokes.
+ if (d->sessionSettings.recognitionMode == ucrMode) {
+ QMutexLocker dictionaryGuard(&d->dictionaryLock);
+ if (d->attachedDictionary)
+ return;
+ }
+
const InputEngine::InputMode inputMode = inputEngine()->inputMode();
if (inputMode != InputEngine::ChineseHandwriting &&
inputMode != InputEngine::JapaneseHandwriting &&
@@ -1944,7 +2050,7 @@ void T9WriteInputMethod::timerEvent(QTimerEvent *timerEvent)
d->clearTraces();
}
#endif
- } else if (d->sessionSettings.recognitionMode == scrMode) {
+ } else {
d->select();
}
}
@@ -1965,7 +2071,7 @@ void T9WriteInputMethod::dictionaryLoadCompleted(QSharedPointer<T9WriteDictionar
InputContext *ic = inputContext();
if (ic && dictionary->fileName() == d->dictionaryFileName) {
d->loadedDictionary = dictionary;
- if (d->sessionSettings.recognitionMode == mcrMode &&
+ if (d->sessionSettings.recognitionMode != scrMode &&
!ic->inputMethodHints().testFlag(Qt::ImhNoPredictiveText) &&
!d->attachedDictionary) {
if (d->attachDictionary(d->loadedDictionary))
@@ -1996,7 +2102,22 @@ void T9WriteInputMethod::resultsAvailable(const QVariantList &resultList)
}
#endif
Q_D(T9WriteInputMethod);
- d->resultsAvailable(resultList);
+ QMutexLocker resultListGuard(&d->resultListLock);
+ d->resultList = resultList;
+ emit resultListChanged();
+}
+
+void T9WriteInputMethod::processResult()
+{
+ Q_D(T9WriteInputMethod);
+ bool resultTimerWasRunning = d->resultTimer != 0;
+
+ d->processResult();
+
+ // Restart the result timer now if it stopped before the results were completed
+ if (!resultTimerWasRunning && (!d->scrResult.isEmpty() || !d->wordCandidates.isEmpty()))
+ d->resetResultTimer(0);
+
}
void T9WriteInputMethod::recognitionError(int status)
diff --git a/src/virtualkeyboard/t9writeinputmethod.h b/src/virtualkeyboard/t9writeinputmethod.h
index 173abd99..9d922537 100644
--- a/src/virtualkeyboard/t9writeinputmethod.h
+++ b/src/virtualkeyboard/t9writeinputmethod.h
@@ -68,12 +68,16 @@ public:
bool reselect(int cursorPosition, const InputEngine::ReselectFlags &reselectFlags);
+signals:
+ void resultListChanged();
+
protected:
void timerEvent(QTimerEvent *timerEvent);
protected slots:
void dictionaryLoadCompleted(QSharedPointer<T9WriteDictionary> dictionary);
void resultsAvailable(const QVariantList &resultList);
+ void processResult();
void recognitionError(int status);
};
diff --git a/src/virtualkeyboard/t9writeworker.cpp b/src/virtualkeyboard/t9writeworker.cpp
index adbdcedb..cc4564dd 100644
--- a/src/virtualkeyboard/t9writeworker.cpp
+++ b/src/virtualkeyboard/t9writeworker.cpp
@@ -93,6 +93,47 @@ void T9WriteDictionaryTask::run()
emit completed(dictionary);
}
+T9WriteAddArcTask::T9WriteAddArcTask(Trace *trace) :
+ trace(trace)
+{
+}
+
+void T9WriteAddArcTask::run()
+{
+#ifdef QT_VIRTUALKEYBOARD_DEBUG
+ QTime perf;
+ perf.start();
+#endif
+ DECUMA_UINT32 arcID = (DECUMA_UINT32)trace->traceId();
+ DECUMA_STATUS status = DECUMA_API(StartNewArc)(decumaSession, arcID);
+ Q_ASSERT(status == decumaNoError);
+ if (status != decumaNoError) {
+ qWarning() << "T9WriteAddArcTask::run(): Failed to start new arc, status:" << status;
+ return;
+ }
+
+ const QVariantList points = trace->points();
+ Q_ASSERT(!points.isEmpty());
+
+ for (const QVariant &p : points) {
+ const QPoint pt(p.toPointF().toPoint());
+ status = DECUMA_API(AddPoint)(decumaSession, (DECUMA_COORD)pt.x(),(DECUMA_COORD)pt.y(), arcID);
+ if (status != decumaNoError) {
+ qWarning() << "T9WriteAddArcTask::run(): Failed to add point, status:" << status;
+ DECUMA_API(CancelArc)(decumaSession, arcID);
+ return;
+ }
+ }
+
+ status = DECUMA_API(CommitArc)(decumaSession, arcID);
+ if (status != decumaNoError)
+ qWarning() << "T9WriteAddArcTask::run(): Failed to commit arc, status:" << status;
+#ifdef QT_VIRTUALKEYBOARD_DEBUG
+ else
+ VIRTUALKEYBOARD_DEBUG() << "T9WriteAddArcTask::run(): time:" << perf.elapsed() << "ms";
+#endif
+}
+
/*!
\class QtVirtualKeyboard::T9WriteRecognitionResult
\internal
@@ -142,8 +183,6 @@ T9WriteRecognitionTask::T9WriteRecognitionTask(QSharedPointer<T9WriteRecognition
void T9WriteRecognitionTask::run()
{
- VIRTUALKEYBOARD_DEBUG() << "T9WriteRecognitionTask::run()";
-
if (!decumaSession)
return;
@@ -167,40 +206,17 @@ void T9WriteRecognitionTask::run()
perf.start();
#endif
- DECUMA_STATUS status;
- if (!cjk) {
- status = DECUMA_API(IndicateInstantGesture)(decumaSession, &result->instantGesture, &instantGestureSettings);
- Q_ASSERT(status == decumaNoError);
- }
-
+#if SUPPORTS_ABORTRECOGNITION
DECUMA_INTERRUPT_FUNCTIONS interruptFunctions;
interruptFunctions.pShouldAbortRecognize = shouldAbortRecognize;
interruptFunctions.pUserData = (void *)this;
- result->status = DECUMA_API(Recognize)(decumaSession, result->results.data(), result->results.size(), &result->numResults, result->maxCharsPerWord, &recSettings, &interruptFunctions);
- if (result->status == decumaAbortRecognitionUnsupported)
- result->status = DECUMA_API(Recognize)(decumaSession, result->results.data(), result->results.size(), &result->numResults, result->maxCharsPerWord, &recSettings, NULL);
-
- QStringList resultList;
- QString gesture;
- for (int i = 0; i < result->numResults; i++)
- {
- QString resultString;
- resultString.reserve(result->results[i].nChars);
- int charPos = 0;
- for (int symbolIndex = 0; symbolIndex < result->results[i].nSymbols; symbolIndex++) {
- int symbolLength = result->results[i].pSymbolChars[symbolIndex];
- QString symbol(QString::fromUtf16(&result->results[i].pChars[charPos], symbolLength));
- // Do not append gesture symbol to result string
- if (result->results[i].bGesture && symbolIndex == (result->results[i].nSymbols - 1)) {
- if (i == 0 && (result->instantGesture || (symbol != QLatin1String(" ") && symbol != QLatin1String("\b"))))
- gesture = symbol;
- } else {
- resultString.append(symbol);
- }
- charPos += symbolLength;
- }
- resultList.append(resultString);
- }
+ DECUMA_INTERRUPT_FUNCTIONS *pInterruptFunctions = &interruptFunctions;
+#else
+ DECUMA_INTERRUPT_FUNCTIONS *pInterruptFunctions = NULL;
+#endif
+ result->status = DECUMA_API(Recognize)(decumaSession, result->results.data(), result->results.size(), &result->numResults, result->maxCharsPerWord, &recSettings, pInterruptFunctions);
+ if (result->status != decumaNoError)
+ qWarning() << "T9WriteRecognitionTask::run(): Recognition failed, status:" << result->status;
#ifdef QT_VIRTUALKEYBOARD_DEBUG
int perfElapsed = perf.elapsed();
@@ -273,12 +289,11 @@ void T9WriteRecognitionResultsTask::run()
int symbolLength = hwrResult.pSymbolChars[symbolIndex];
QString symbol(QString::fromUtf16(&hwrResult.pChars[charPos], symbolLength));
// Do not append gesture symbol to result string
- if (hwrResult.bGesture && symbolIndex == (hwrResult.nSymbols - 1)) {
- if (result->instantGesture || (symbol != QLatin1String(" ") && symbol != QLatin1String("\b")))
- gesture = symbol;
- } else {
- resultString.append(symbol);
+ if (hwrResult.bGesture) {
+ gesture = symbol.right(1);
+ symbol.chop(1);
}
+ resultString.append(symbol);
charPos += symbolLength;
if (hwrResult.pSymbolStrokes)
symbolStrokes.append(QVariant((int)hwrResult.pSymbolStrokes[symbolIndex]));
@@ -352,12 +367,33 @@ int T9WriteWorker::removeAllTasks()
return count;
}
+void T9WriteWorker::waitForAllTasks()
+{
+ while (isRunning()) {
+ idleSema.acquire();
+ QMutexLocker guard(&taskLock);
+ if (taskList.isEmpty()) {
+ idleSema.release();
+ break;
+ }
+ idleSema.release();
+ }
+}
+
+int T9WriteWorker::numberOfPendingTasks()
+{
+ QMutexLocker guard(&taskLock);
+ return taskList.count() + !idleSema.available() ? 1 : 0;
+}
+
void T9WriteWorker::run()
{
while (!abort) {
+ idleSema.release();
taskSema.acquire();
if (abort)
break;
+ idleSema.acquire();
QSharedPointer<T9WriteTask> currentTask;
{
QMutexLocker guard(&taskLock);
diff --git a/src/virtualkeyboard/t9writeworker.h b/src/virtualkeyboard/t9writeworker.h
index 437a84f5..f34eef67 100644
--- a/src/virtualkeyboard/t9writeworker.h
+++ b/src/virtualkeyboard/t9writeworker.h
@@ -86,6 +86,18 @@ signals:
void completed(QSharedPointer<T9WriteDictionary> dictionary);
};
+class T9WriteAddArcTask : public T9WriteTask
+{
+ Q_OBJECT
+public:
+ explicit T9WriteAddArcTask(Trace *trace);
+
+ void run();
+
+private:
+ Trace *trace;
+};
+
class T9WriteRecognitionResult
{
Q_DISABLE_COPY(T9WriteRecognitionResult)
@@ -159,6 +171,8 @@ public:
void addTask(QSharedPointer<T9WriteTask> task);
int removeTask(QSharedPointer<T9WriteTask> task);
int removeAllTasks();
+ void waitForAllTasks();
+ int numberOfPendingTasks();
template <class X>
int removeAllTasks() {
@@ -181,6 +195,7 @@ protected:
private:
QList<QSharedPointer<T9WriteTask> > taskList;
+ QSemaphore idleSema;
QSemaphore taskSema;
QMutex taskLock;
DECUMA_SESSION *decumaSession;
diff --git a/tests/auto/inputpanel/data/inputpanel/inputpanel.qml b/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
index dfdb941b..ded8aee3 100644
--- a/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
+++ b/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
@@ -91,6 +91,7 @@ InputPanel {
property alias wordCandidateListVisibleSpy: wordCandidateListVisibleSpy
property alias shiftStateSpy: shiftStateSpy
property alias shadowInputControlVisibleSpy: shadowInputControlVisibleSpy
+ property alias externalLanguageSwitchSpy: externalLanguageSwitchSpy
signal inputMethodResult(var text)
@@ -188,6 +189,12 @@ InputPanel {
signalName: "onVisibleChanged"
}
+ SignalSpy {
+ id: externalLanguageSwitchSpy
+ target: inputPanel
+ signalName: "onExternalLanguageSwitch"
+ }
+
function findChildByProperty(parent, propertyName, propertyValue, compareCb) {
var obj = null
if (parent === null)
@@ -293,6 +300,10 @@ InputPanel {
return true
}
+ function setExternalLanguageSwitchEnabled(enabled) {
+ externalLanguageSwitchEnabled = enabled
+ }
+
function findVirtualKey(key) {
return Utils.findChild(keyboardLayoutLoader, key, function(obj, param) {
if (!obj.hasOwnProperty("key") || !obj.hasOwnProperty("text"))
diff --git a/tests/auto/inputpanel/data/tst_inputpanel.qml b/tests/auto/inputpanel/data/tst_inputpanel.qml
index e505d36c..0b9f11ff 100644
--- a/tests/auto/inputpanel/data/tst_inputpanel.qml
+++ b/tests/auto/inputpanel/data/tst_inputpanel.qml
@@ -82,6 +82,7 @@ Rectangle {
inputPanel.setWclAlwaysVisible(data !== undefined && data.hasOwnProperty("wclAlwaysVisible") && data.wclAlwaysVisible)
inputPanel.setWclAutoCommitWord(data !== undefined && data.hasOwnProperty("wclAutoCommitWord") && data.wclAutoCommitWord)
inputPanel.setFullScreenMode(data !== undefined && data.hasOwnProperty("fullScreenMode") && data.fullScreenMode)
+ inputPanel.setExternalLanguageSwitchEnabled(data !== undefined && data.hasOwnProperty("externalLanguageSwitchEnabled") && data.externalLanguageSwitchEnabled)
container.forceActiveFocus()
if (data !== undefined && data.hasOwnProperty("initText")) {
textInput.text = data.initText
@@ -1048,7 +1049,7 @@ Rectangle {
// Remove Jamos one by one.
// The number of removed characters must match to the number of Jamos entered.
- for (; inputIndex >= 0; inputIndex--) {
+ for (inputIndex = data.inputSequence.length - 1; inputIndex >= 0; inputIndex--) {
compare(textInput.text, intermediateResult.pop())
inputPanel.virtualKeyClick(Qt.Key_Backspace)
}
@@ -1531,14 +1532,23 @@ Rectangle {
}
}
- function test_languagePopupListToggle() {
- prepareTest()
+ function test_languagePopupListToggle_data() {
+ return [
+ { externalLanguageSwitchEnabled: true },
+ { externalLanguageSwitchEnabled: false },
+ ]
+ }
+
+ function test_languagePopupListToggle(data) {
+ prepareTest(data)
if (inputPanel.availableLocales.length < 2)
skip("Input language can not be changed")
var changeLanguageKey = inputPanel.findObjectByName("changeLanguageKey")
var languagePopupList = inputPanel.findObjectByName("languagePopupList")
+ inputPanel.externalLanguageSwitchSpy.clear()
inputPanel.virtualKeyClick(changeLanguageKey)
- compare(languagePopupList.visible, true)
+ compare(languagePopupList.visible, !data.externalLanguageSwitchEnabled)
+ compare(inputPanel.externalLanguageSwitchSpy.count, data.externalLanguageSwitchEnabled ? 1 : 0)
inputPanel.virtualKeyClick(changeLanguageKey)
compare(languagePopupList.visible, false)
}