aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Koivikko <jarkko.koivikko@code-q.fi>2014-06-04 13:01:40 +0300
committerJarkko Koivikko <jarkko.koivikko@code-q.fi>2014-06-19 14:01:48 +0300
commit4a66c5293fd560daed88e817ad14241adfb7acd6 (patch)
treedb3ab601ff11b09bce05902150309d4cec42b7a8
parent16d6563f54f4dad947a645c23048eea8ddef3b35 (diff)
Add PinyinInputMethod
Added new PinyinInputMethod which is using the PinyinIME engine as backend. The PinyinIME is Apache 2.0 licensed. https://android.googlesource.com/platform/packages/inputmethods/PinyinIME/ The pinyin input method is enabled by using CONFIG+=pinyin configuration flag on the qmake command line. Dictionaries ============ The pinyin engine uses two kinds of dictionaries: sys_dict and usr_dict. The sys_dict is a pre-built dictionary containing a search model for Chinese words. The sys_dict is built using the dictionary tool included in the source tree. The sys_dict is deployed in to the $$[QT_INSTALL_DATA]/qtvirtualkeyboard/pinyin directory on the target system. This path will become the default location where the dictionary is searched in. The default location can be overridden by specifying an alternative path to the dictionary file in an environment variable QT_VIRTUALKEYBOARD_PINYIN_DICTIONARY. The usr_dict contains custom lemmas which the user is most frequently using. Initially, the usr_dict may not exist, in which case it is automatically created. The usr_dict is located at subdirectory qtvirtualkeyboard/pinyin under the location returned by QStandardPaths::writableLocation(QStandardPaths::ConfigLocation). Usage ===== The pinyin input mode is activated by changing the input locale to zh_CN. Chinese words are entered by typing the phonetic form of the Chinese words and then selecting words from the selection list. The first item in the selection list always contains the complete phrase. By selecting the first item, the pinyin completes the entire phrase and ends the current input. The user can also select the entire phrase by pressing the space key. The subsequent items in the selection list are the segments comprising one or more Chinese words. By selecting segments of previously unknown lemma, the input method learns this by adding a new entry to the usr_dict. Once the user enters the same pinyin sequence again, the input method can suggest the same phrase as the first or the second item in the selection list. The characters sequences, which are not valid pinyin spellings, are displayed in lower case letters. The user can either delete these characters by pressing the backspace key, or select and accept them as input from the selection list. After the user completes the phrase, or moves the cursor in the text, the pinyin input can predict words by looking at text up to 3 characters in history. In prediction mode the user is not required to select any items from the prediction list. The user can enter plain latin characters by accepting the input sequence with the return key. Change-Id: I46bfc0df112a4d9c892222916cb7455132dd5059 Reviewed-by: Mitch Curtis <mitch.curtis@digia.com> Reviewed-by: Liang Qi <liang.qi@digia.com>
-rw-r--r--src/src.pro5
-rw-r--r--src/virtualkeyboard/content/layouts/zh_CN/main.qml187
-rw-r--r--src/virtualkeyboard/content/layouts/zh_CN/symbols.qml268
-rw-r--r--src/virtualkeyboard/content/styles/default/style.qml3
-rw-r--r--src/virtualkeyboard/content/styles/retro/style.qml3
-rw-r--r--src/virtualkeyboard/declarativeinputengine.cpp2
-rw-r--r--src/virtualkeyboard/declarativeinputengine.h3
-rw-r--r--src/virtualkeyboard/doc/src/build.qdoc3
-rw-r--r--src/virtualkeyboard/pinyindecoderservice.cpp190
-rw-r--r--src/virtualkeyboard/pinyindecoderservice.h56
-rw-r--r--src/virtualkeyboard/pinyininputmethod.cpp438
-rw-r--r--src/virtualkeyboard/pinyininputmethod.h50
-rw-r--r--src/virtualkeyboard/plaininputmethod.cpp7
-rw-r--r--src/virtualkeyboard/plugin.cpp6
-rw-r--r--src/virtualkeyboard/virtualkeyboard.pro35
15 files changed, 1250 insertions, 6 deletions
diff --git a/src/src.pro b/src/src.pro
index fedd52f3..5ce2df6d 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -8,3 +8,8 @@ SUBDIRS += \
SUBDIRS += virtualkeyboard/3rdparty/hunspell
virtualkeyboard.depends += sub-virtualkeyboard-3rdparty-hunspell
}
+
+pinyin {
+ SUBDIRS += virtualkeyboard/3rdparty/pinyin
+ virtualkeyboard.depends += sub-virtualkeyboard-3rdparty-pinyin
+}
diff --git a/src/virtualkeyboard/content/layouts/zh_CN/main.qml b/src/virtualkeyboard/content/layouts/zh_CN/main.qml
new file mode 100644
index 00000000..89e9eef0
--- /dev/null
+++ b/src/virtualkeyboard/content/layouts/zh_CN/main.qml
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the Qt Quick Enterprise Controls add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Layouts 1.0
+import QtQuick.Enterprise.VirtualKeyboard 1.0
+
+KeyboardLayout {
+ inputMethod: PinyinInputMethod {}
+ keyWeight: 160
+ KeyboardRow {
+ Key {
+ key: Qt.Key_Q
+ text: "q"
+ }
+ Key {
+ key: Qt.Key_W
+ text: "w"
+ }
+ Key {
+ key: Qt.Key_E
+ text: "e"
+ }
+ Key {
+ key: Qt.Key_R
+ text: "r"
+ }
+ Key {
+ key: Qt.Key_T
+ text: "t"
+ }
+ Key {
+ key: Qt.Key_Y
+ text: "y"
+ }
+ Key {
+ key: Qt.Key_U
+ text: "u"
+ }
+ Key {
+ key: Qt.Key_I
+ text: "i"
+ }
+ Key {
+ key: Qt.Key_O
+ text: "o"
+ }
+ Key {
+ key: Qt.Key_P
+ text: "p"
+ }
+ BackspaceKey {}
+ }
+ KeyboardRow {
+ FillerKey {
+ weight: 56
+ }
+ Key {
+ key: Qt.Key_A
+ text: "a"
+ }
+ Key {
+ key: Qt.Key_S
+ text: "s"
+ }
+ Key {
+ key: Qt.Key_D
+ text: "d"
+ }
+ Key {
+ key: Qt.Key_F
+ text: "f"
+ }
+ Key {
+ key: Qt.Key_G
+ text: "g"
+ }
+ Key {
+ key: Qt.Key_H
+ text: "h"
+ }
+ Key {
+ key: Qt.Key_J
+ text: "j"
+ }
+ Key {
+ key: Qt.Key_K
+ text: "k"
+ }
+ Key {
+ key: Qt.Key_L
+ text: "l"
+ }
+ EnterKey {
+ weight: 283
+ }
+ }
+ KeyboardRow {
+ keyWeight: 156
+ Key {
+ enabled: InputContext.preeditText.length > 0
+ key: Qt.Key_Apostrophe
+ text: "'"
+ }
+ Key {
+ key: Qt.Key_Z
+ text: "z"
+ }
+ Key {
+ key: Qt.Key_X
+ text: "x"
+ }
+ Key {
+ key: Qt.Key_C
+ text: "c"
+ }
+ Key {
+ key: Qt.Key_V
+ text: "v"
+ }
+ Key {
+ key: Qt.Key_B
+ text: "b"
+ }
+ Key {
+ key: Qt.Key_N
+ text: "n"
+ }
+ Key {
+ key: Qt.Key_M
+ text: "m"
+ }
+ Key {
+ key: Qt.Key_Comma
+ text: "\uFF0C"
+ alternativeKeys: "\uFF0C\uFF1B\u3001"
+ }
+ Key {
+ key: Qt.Key_Period
+ text: "\uFF0E"
+ alternativeKeys: "\uFF0E\uFF1A\u3002"
+ }
+ ShiftKey {
+ weight: 204
+ }
+ }
+ KeyboardRow {
+ keyWeight: 154
+ SymbolModeKey {
+ weight: 217
+ }
+ ChangeLanguageKey {
+ weight: 154
+ }
+ SpaceKey {
+ weight: 864
+ }
+ Key {
+ key: Qt.Key_Question
+ text: "?"
+ alternativeKeys: "?!"
+ }
+ Key {
+ key: 0xE000
+ text: ":-)"
+ alternativeKeys: [ ";-)", ":-)", ":-D", ":-(", "<3" ]
+ }
+ HideKeyboardKey {
+ weight: 204
+ }
+ }
+}
diff --git a/src/virtualkeyboard/content/layouts/zh_CN/symbols.qml b/src/virtualkeyboard/content/layouts/zh_CN/symbols.qml
new file mode 100644
index 00000000..02422a07
--- /dev/null
+++ b/src/virtualkeyboard/content/layouts/zh_CN/symbols.qml
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the Qt Quick Enterprise Controls add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Layouts 1.0
+import QtQuick.Enterprise.VirtualKeyboard 1.0
+
+KeyboardLayout {
+ inputMethod: PlainInputMethod {}
+ property int page
+ readonly property int numPages: 3
+ property var keysPage1: [
+ "1234567890",
+ "@#$%^&*()",
+ "“”、=:;!?~"
+ ]
+ property var keysPage2: [
+ "-+/\\|[]{}·",
+ "<>,.:;!?~",
+ "/\"'_§¥€£¢"
+ ]
+ property var keysPage3: [
+ "()〔〕〈〉《》【】",
+ "→←↑↓↔■□●○",
+ "\『』「」★☆◆◇"
+ ]
+ keyWeight: 160
+ KeyboardColumn {
+ anchors.fill: parent
+ visible: page == 0
+ KeyboardRow {
+ Repeater {
+ model: keysPage1[0].length
+ Key {
+ key: keysPage1[0][index].charCodeAt(0)
+ text: keysPage1[0][index]
+ }
+ }
+ BackspaceKey {}
+ }
+ KeyboardRow {
+ FillerKey {
+ weight: 56
+ }
+ Repeater {
+ model: keysPage1[1].length
+ Key {
+ key: keysPage1[1][index].charCodeAt(0)
+ text: keysPage1[1][index]
+ }
+ }
+ EnterKey {
+ weight: 283
+ }
+ }
+ KeyboardRow {
+ keyWeight: 156
+ Key {
+ displayText: (page + 1) + "/" + numPages
+ functionKey: true
+ onClicked: page = (page + 1) % numPages
+ }
+ Repeater {
+ model: keysPage1[2].length
+ Key {
+ key: keysPage1[2][index].charCodeAt(0)
+ text: keysPage1[2][index]
+ }
+ }
+ Key {
+ weight: 204
+ displayText: (page + 1) + "/" + numPages
+ functionKey: true
+ onClicked: page = (page + 1) % numPages
+ }
+ }
+ KeyboardRow {
+ keyWeight: 154
+ SymbolModeKey {
+ weight: 217
+ displayText: "ABC"
+ }
+ ChangeLanguageKey {
+ weight: 154
+ }
+ SpaceKey {
+ weight: 864
+ }
+ Key {
+ key: 0x2014
+ text: "—"
+ }
+ Key {
+ key: 0xE000
+ text: ":-)"
+ alternativeKeys: [ ";-)", ":-)", ":-D", ":-(", "<3" ]
+ }
+ HideKeyboardKey {
+ weight: 204
+ }
+ }
+ }
+ KeyboardColumn {
+ anchors.fill: parent
+ visible: page == 1
+ KeyboardRow {
+ Repeater {
+ model: keysPage2[0].length
+ Key {
+ key: keysPage2[0][index].charCodeAt(0)
+ text: keysPage2[0][index]
+ }
+ }
+ BackspaceKey {}
+ }
+ KeyboardRow {
+ FillerKey {
+ weight: 56
+ }
+ Repeater {
+ model: keysPage2[1].length
+ Key {
+ key: keysPage2[1][index].charCodeAt(0)
+ text: keysPage2[1][index]
+ }
+ }
+ EnterKey {
+ weight: 283
+ }
+ }
+ KeyboardRow {
+ keyWeight: 156
+ Key {
+ displayText: (page + 1) + "/" + numPages
+ functionKey: true
+ onClicked: page = (page + 1) % numPages
+ }
+ Repeater {
+ model: keysPage2[2].length
+ Key {
+ key: keysPage2[2][index].charCodeAt(0)
+ text: keysPage2[2][index]
+ }
+ }
+ Key {
+ weight: 204
+ displayText: (page + 1) + "/" + numPages
+ functionKey: true
+ onClicked: page = (page + 1) % numPages
+ }
+ }
+ KeyboardRow {
+ keyWeight: 154
+ SymbolModeKey {
+ weight: 217
+ displayText: "ABC"
+ }
+ ChangeLanguageKey {
+ weight: 154
+ }
+ SpaceKey {
+ weight: 864
+ }
+ Key {
+ key: 0x3002
+ text: "。"
+ }
+ Key {
+ key: 0xE000
+ text: ":-)"
+ alternativeKeys: [ ";-)", ":-)", ":-D", ":-(", "<3" ]
+ }
+ HideKeyboardKey {
+ weight: 204
+ }
+ }
+ }
+ KeyboardColumn {
+ anchors.fill: parent
+ visible: page == 2
+ KeyboardRow {
+ Repeater {
+ model: keysPage3[0].length
+ Key {
+ key: keysPage3[0][index].charCodeAt(0)
+ text: keysPage3[0][index]
+ }
+ }
+ BackspaceKey {}
+ }
+ KeyboardRow {
+ FillerKey {
+ weight: 56
+ }
+ Repeater {
+ model: keysPage3[1].length
+ Key {
+ key: keysPage3[1][index].charCodeAt(0)
+ text: keysPage3[1][index]
+ }
+ }
+ EnterKey {
+ weight: 283
+ }
+ }
+ KeyboardRow {
+ keyWeight: 156
+ Key {
+ displayText: (page + 1) + "/" + numPages
+ functionKey: true
+ onClicked: page = (page + 1) % numPages
+ }
+ Repeater {
+ model: keysPage3[2].length
+ Key {
+ key: keysPage3[2][index].charCodeAt(0)
+ text: keysPage3[2][index]
+ }
+ }
+ Key {
+ weight: 204
+ displayText: (page + 1) + "/" + numPages
+ functionKey: true
+ onClicked: page = (page + 1) % numPages
+ }
+ }
+ KeyboardRow {
+ keyWeight: 154
+ SymbolModeKey {
+ weight: 217
+ displayText: "ABC"
+ }
+ ChangeLanguageKey {
+ weight: 154
+ }
+ SpaceKey {
+ weight: 864
+ }
+ Key {
+ key: 0x2026
+ text: "…"
+ }
+ Key {
+ key: 0xE000
+ text: ":-)"
+ alternativeKeys: [ ";-)", ":-)", ":-D", ":-(", "<3" ]
+ }
+ HideKeyboardKey {
+ weight: 204
+ }
+ }
+ }
+}
diff --git a/src/virtualkeyboard/content/styles/default/style.qml b/src/virtualkeyboard/content/styles/default/style.qml
index 51d2c1df..6b3e058b 100644
--- a/src/virtualkeyboard/content/styles/default/style.qml
+++ b/src/virtualkeyboard/content/styles/default/style.qml
@@ -21,6 +21,7 @@ import QtQuick.Enterprise.VirtualKeyboard 1.0
import QtQuick.Enterprise.VirtualKeyboard.Styles 1.0
KeyboardStyle {
+ readonly property bool pinyinMode: InputContext.inputEngine.inputMode === InputEngine.Pinyin
readonly property string fontFamily: "Sans"
readonly property real keyBackgroundMargin: Math.round(13 * scaleHint)
readonly property real keyContentMargin: Math.round(45 * scaleHint)
@@ -517,7 +518,7 @@ KeyboardStyle {
Text {
id: selectionListLabel
anchors.left: parent.left
- anchors.leftMargin: Math.round(140 * scaleHint)
+ anchors.leftMargin: Math.round((pinyinMode ? 50 : 140) * scaleHint)
anchors.verticalCenter: parent.verticalCenter
text: decorateText(display, wordCompletionLength)
color: "#80c342"
diff --git a/src/virtualkeyboard/content/styles/retro/style.qml b/src/virtualkeyboard/content/styles/retro/style.qml
index 9b06d2d3..d8b7c586 100644
--- a/src/virtualkeyboard/content/styles/retro/style.qml
+++ b/src/virtualkeyboard/content/styles/retro/style.qml
@@ -21,6 +21,7 @@ import QtQuick.Enterprise.VirtualKeyboard 1.0
import QtQuick.Enterprise.VirtualKeyboard.Styles 1.0
KeyboardStyle {
+ readonly property bool pinyinMode: InputContext.inputEngine.inputMode === InputEngine.Pinyin
readonly property string fontFamily: "Courier"
readonly property real keyBackgroundMargin: Math.round(9 * scaleHint)
readonly property real keyContentMargin: Math.round(50 * scaleHint)
@@ -634,7 +635,7 @@ KeyboardStyle {
Text {
id: selectionListLabel
anchors.left: parent.left
- anchors.leftMargin: Math.round(140 * scaleHint)
+ anchors.leftMargin: Math.round((pinyinMode ? 50 : 140) * scaleHint)
anchors.verticalCenter: parent.verticalCenter
text: decorateText(display, wordCompletionLength)
color: "white"
diff --git a/src/virtualkeyboard/declarativeinputengine.cpp b/src/virtualkeyboard/declarativeinputengine.cpp
index 7d8b6e03..5921a389 100644
--- a/src/virtualkeyboard/declarativeinputengine.cpp
+++ b/src/virtualkeyboard/declarativeinputengine.cpp
@@ -598,6 +598,8 @@ void DeclarativeInputEngine::timerEvent(QTimerEvent *timerEvent)
Only numeric input is allowed.
\value Dialable
Only dialable input is allowed.
+ \value Pinyin
+ Pinyin input mode for Chinese.
*/
/*!
diff --git a/src/virtualkeyboard/declarativeinputengine.h b/src/virtualkeyboard/declarativeinputengine.h
index 15504013..ddf4c441 100644
--- a/src/virtualkeyboard/declarativeinputengine.h
+++ b/src/virtualkeyboard/declarativeinputengine.h
@@ -52,7 +52,8 @@ public:
enum InputMode {
Latin,
Numeric,
- Dialable
+ Dialable,
+ Pinyin
};
public:
diff --git a/src/virtualkeyboard/doc/src/build.qdoc b/src/virtualkeyboard/doc/src/build.qdoc
index cd3629d9..4a2e10fe 100644
--- a/src/virtualkeyboard/doc/src/build.qdoc
+++ b/src/virtualkeyboard/doc/src/build.qdoc
@@ -70,6 +70,9 @@ build targets.
\row
\li \e CONFIG += retro-style
\li Enables Retro style
+\row
+ \li \e CONFIG += pinyin
+ \li Enables the pinyin input method for Simplified Chinese.
\endtable
\section2 Building Documentation
diff --git a/src/virtualkeyboard/pinyindecoderservice.cpp b/src/virtualkeyboard/pinyindecoderservice.cpp
new file mode 100644
index 00000000..ccaa3910
--- /dev/null
+++ b/src/virtualkeyboard/pinyindecoderservice.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the Qt Quick Enterprise Controls add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "pinyindecoderservice.h"
+#include "pinyinime.h"
+#include "dictdef.h"
+#include <QStandardPaths>
+#include <QFileInfo>
+#include <QDir>
+#include "virtualkeyboarddebug.h"
+
+using namespace ime_pinyin;
+
+QScopedPointer<PinyinDecoderService> PinyinDecoderService::_instance;
+
+PinyinDecoderService::PinyinDecoderService(QObject *parent) :
+ QObject(parent),
+ initDone(false)
+{
+}
+
+PinyinDecoderService::~PinyinDecoderService()
+{
+ if (initDone) {
+ im_close_decoder();
+ initDone = false;
+ }
+}
+
+PinyinDecoderService *PinyinDecoderService::getInstance()
+{
+ if (!_instance)
+ _instance.reset(new PinyinDecoderService());
+ if (!_instance->init())
+ return 0;
+ return _instance.data();
+}
+
+bool PinyinDecoderService::init()
+{
+ if (initDone)
+ return true;
+
+ QString sysDict(QString::fromLatin1(qgetenv("QT_VIRTUALKEYBOARD_PINYIN_DICTIONARY").constData()));
+ if (sysDict.isEmpty())
+ sysDict = QT_VIRTUALKEYBOARD_PINYIN_DICTIONARY;
+
+ QString usrDictPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
+ QFileInfo usrDictInfo(usrDictPath + "/qtvirtualkeyboard/pinyin/usr_dict.dat");
+ if (!usrDictInfo.exists()) {
+ VIRTUALKEYBOARD_DEBUG() << "PinyinDecoderService::init(): creating directory for user dictionary" << usrDictInfo.absolutePath();
+ QDir().mkpath(usrDictInfo.absolutePath());
+ }
+
+ initDone = im_open_decoder(sysDict.toUtf8().constData(), usrDictInfo.absoluteFilePath().toUtf8().constData());
+ if (!initDone)
+ VIRTUALKEYBOARD_DEBUG() << "Could not initialize pinyin engine. sys_dict:" << sysDict << "usr_dict:" << usrDictInfo.absoluteFilePath();
+
+ return initDone;
+}
+
+void PinyinDecoderService::setLimits(int maxSpsLen, int maxHzsLen)
+{
+ if (maxSpsLen <= 0)
+ maxSpsLen = kMaxSearchSteps - 1;
+ if (maxHzsLen <= 0)
+ maxHzsLen = kMaxSearchSteps;
+ im_set_max_lens(size_t(maxSpsLen), size_t(maxHzsLen));
+}
+
+int PinyinDecoderService::search(const QString &spelling)
+{
+ QByteArray spellingBuf = spelling.toLatin1();
+ return int(im_search(spellingBuf.constData(), spellingBuf.length()));
+}
+
+int PinyinDecoderService::deleteSearch(int pos, bool isPosInSpellingId, bool clearFixedInThisStep)
+{
+ if (pos <= 0)
+ pos = 0;
+ return int(im_delsearch(size_t(pos), isPosInSpellingId, clearFixedInThisStep));
+}
+
+void PinyinDecoderService::resetSearch()
+{
+ im_reset_search();
+}
+
+QString PinyinDecoderService::pinyinString(bool decoded)
+{
+ size_t py_len;
+ const char *py = im_get_sps_str(&py_len);
+ if (!decoded)
+ py_len = strlen(py);
+
+ return QString(QLatin1String(py, py_len));
+}
+
+int PinyinDecoderService::pinyinStringLength(bool decoded)
+{
+ size_t py_len;
+ const char *py = im_get_sps_str(&py_len);
+ if (!decoded)
+ py_len = strlen(py);
+ return py_len;
+}
+
+QVector<int> PinyinDecoderService::spellingStartPositions()
+{
+ const unsigned short *spl_start;
+ size_t len;
+ // There will be len + 1 elements in the buffer when len > 0.
+ len = im_get_spl_start_pos(spl_start);
+
+ QVector<int> arr;
+ arr.resize(len + 2);
+ arr[0] = len; // element 0 is used to store the length of buffer.
+ for (size_t i = 0; i <= len; i++)
+ arr[i + 1] = spl_start[i];
+ return arr;
+}
+
+QString PinyinDecoderService::candidateAt(int index)
+{
+ Q_ASSERT(index >= 0);
+ QVector<QChar> candidateBuf;
+ candidateBuf.resize(kMaxSearchSteps + 1);
+ if (!im_get_candidate(size_t(index), (char16 *)candidateBuf.data(), candidateBuf.length() - 1))
+ return QString();
+ candidateBuf.last() = 0;
+ return QString(candidateBuf.data());
+}
+
+QList<QString> PinyinDecoderService::fetchCandidates(int index, int count, int sentFixedLen)
+{
+ QList<QString> candidatesList;
+ for (int i = index; i < index + count; i++) {
+ QString retStr = candidateAt(i);
+ if (0 == i)
+ retStr.remove(0, sentFixedLen);
+ candidatesList.append(retStr);
+ }
+ return candidatesList;
+}
+
+int PinyinDecoderService::chooceCandidate(int index)
+{
+ return int(im_choose(index));
+}
+
+int PinyinDecoderService::cancelLastChoice()
+{
+ return int(im_cancel_last_choice());
+}
+
+int PinyinDecoderService::fixedLength()
+{
+ return im_get_fixed_len();
+}
+
+void PinyinDecoderService::flushCache()
+{
+ im_flush_cache();
+}
+
+QList<QString> PinyinDecoderService::predictionList(const QString &history)
+{
+ QList<QString> predictList;
+ char16 (*predictItems)[kMaxPredictSize + 1] = 0;
+ int predictNum = int(im_get_predicts(history.utf16(), predictItems));
+ predictList.reserve(predictNum);
+ for (int i = 0; i < predictNum; i++)
+ predictList.append(QString((QChar *)predictItems[i]));
+ return predictList;
+}
diff --git a/src/virtualkeyboard/pinyindecoderservice.h b/src/virtualkeyboard/pinyindecoderservice.h
new file mode 100644
index 00000000..3da87855
--- /dev/null
+++ b/src/virtualkeyboard/pinyindecoderservice.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the Qt Quick Enterprise Controls add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef PINYINDECODERSERVICE_H
+#define PINYINDECODERSERVICE_H
+
+#include <QObject>
+
+class PinyinDecoderService : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(PinyinDecoderService)
+ explicit PinyinDecoderService(QObject *parent = 0);
+
+public:
+ ~PinyinDecoderService();
+
+ static PinyinDecoderService *getInstance();
+
+ bool init();
+ void setLimits(int maxSpelling, int maxHzsLen);
+ int search(const QString &spelling);
+ int deleteSearch(int pos, bool isPosInSpellingId, bool clearFixedInThisStep);
+ void resetSearch();
+ QString pinyinString(bool decoded);
+ int pinyinStringLength(bool decoded);
+ QVector<int> spellingStartPositions();
+ QString candidateAt(int index);
+ QList<QString> fetchCandidates(int index, int count, int sentFixedLen);
+ int chooceCandidate(int index);
+ int cancelLastChoice();
+ int fixedLength();
+ void flushCache();
+ QList<QString> predictionList(const QString &history);
+
+private:
+ static QScopedPointer<PinyinDecoderService> _instance;
+ bool initDone;
+};
+
+#endif // PINYINDECODERSERVICE_H
diff --git a/src/virtualkeyboard/pinyininputmethod.cpp b/src/virtualkeyboard/pinyininputmethod.cpp
new file mode 100644
index 00000000..9bb424f3
--- /dev/null
+++ b/src/virtualkeyboard/pinyininputmethod.cpp
@@ -0,0 +1,438 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the Qt Quick Enterprise Controls add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "pinyininputmethod.h"
+#include "pinyindecoderservice.h"
+#include "declarativeinputcontext.h"
+#include "virtualkeyboarddebug.h"
+
+class PinyinInputMethodPrivate : public AbstractInputMethodPrivate
+{
+ Q_DECLARE_PUBLIC(PinyinInputMethod)
+
+public:
+ enum State
+ {
+ Idle,
+ Input,
+ Predict
+ };
+
+ PinyinInputMethodPrivate(PinyinInputMethod *q_ptr) :
+ q_ptr(q_ptr),
+ inputMode(DeclarativeInputEngine::Pinyin),
+ pinyinDecoderService(PinyinDecoderService::getInstance()),
+ state(Idle),
+ surface(),
+ totalChoicesNum(0),
+ candidatesList(),
+ fixedLen(0),
+ composingStr(),
+ activeCmpsLen(0),
+ finishSelection(true),
+ posDelSpl(-1),
+ isPosInSpl(false)
+ {
+ }
+
+ void resetToIdleState()
+ {
+ Q_Q(PinyinInputMethod);
+ if (state == Idle)
+ return;
+
+ state = Idle;
+ surface.clear();
+ fixedLen = 0;
+ finishSelection = true;
+ composingStr.clear();
+ DeclarativeInputContext *inputContext = q->inputContext();
+ if (inputContext)
+ inputContext->setPreeditText("");
+ activeCmpsLen = 0;
+ posDelSpl = -1;
+ isPosInSpl = false;
+
+ resetCandidates();
+ }
+
+ bool addSpellingChar(QChar ch, bool reset)
+ {
+ if (reset) {
+ surface.clear();
+ pinyinDecoderService->resetSearch();
+ }
+ if (ch == Qt::Key_Apostrophe) {
+ if (surface.isEmpty())
+ return false;
+ if (surface.endsWith(ch))
+ return true;
+ }
+ surface.append(ch);
+ return true;
+ }
+
+ bool removeSpellingChar()
+ {
+ if (surface.isEmpty())
+ return false;
+ QVector<int> splStart = pinyinDecoderService->spellingStartPositions();
+ isPosInSpl = (surface.length() <= splStart[fixedLen + 1]);
+ posDelSpl = isPosInSpl ? fixedLen - 1 : surface.length() - 1;
+ return true;
+ }
+
+ void chooseAndUpdate(int candId)
+ {
+ Q_Q(PinyinInputMethod);
+
+ if (state == Predict)
+ choosePredictChoice(candId);
+ else
+ chooseDecodingCandidate(candId);
+
+ if (composingStr.length() > 0) {
+ if ((candId >= 0 || finishSelection) && composingStr.length() == fixedLen) {
+ QString resultStr = getComposingStrActivePart();
+ tryPredict();
+ q->inputContext()->commit(resultStr);
+ } else if (state == Idle) {
+ state = Input;
+ }
+ } else {
+ tryPredict();
+ }
+ }
+
+ bool chooseAndFinish()
+ {
+ if (state == Predict || !totalChoicesNum)
+ return false;
+
+ chooseAndUpdate(0);
+ if (state != Predict && totalChoicesNum > 0)
+ chooseAndUpdate(0);
+
+ return true;
+ }
+
+ int candidatesCount()
+ {
+ return totalChoicesNum;
+ }
+
+ QString candidateAt(int index)
+ {
+ if (index < 0 || index >= totalChoicesNum)
+ return QString();
+ if (index >= candidatesList.size()) {
+ int fetchMore = qMin(index + 20, totalChoicesNum - candidatesList.size());
+ candidatesList.append(pinyinDecoderService->fetchCandidates(candidatesList.size(), fetchMore, fixedLen));
+ if (index == 0 && totalChoicesNum == 1) {
+ int surfaceDecodedLen = pinyinDecoderService->pinyinStringLength(true);
+ if (surfaceDecodedLen < surface.length())
+ candidatesList[0] = candidatesList[0] + surface.mid(surfaceDecodedLen).toLower();
+ }
+ }
+ return index < candidatesList.size() ? candidatesList[index] : QString();
+ }
+
+ void chooseDecodingCandidate(int candId)
+ {
+ Q_Q(PinyinInputMethod);
+ Q_ASSERT(state != Predict);
+
+ int result;
+ if (candId < 0) {
+ if (surface.length() > 0) {
+ if (posDelSpl < 0) {
+ result = pinyinDecoderService->search(surface);
+ } else {
+ result = pinyinDecoderService->deleteSearch(posDelSpl, isPosInSpl, false);
+ posDelSpl = -1;
+ }
+ }
+ } else {
+ if (totalChoicesNum > 1) {
+ result = pinyinDecoderService->chooceCandidate(candId);
+ } else {
+ QString resultStr;
+ if (totalChoicesNum == 1) {
+ QString undecodedStr = candId < candidatesList.length() ? candidatesList.at(candId) : QString();
+ resultStr = pinyinDecoderService->candidateAt(0).mid(0, fixedLen) + undecodedStr;
+ }
+ resetToIdleState();
+ if (!resultStr.isEmpty())
+ q->inputContext()->commit(resultStr);
+ return;
+ }
+ }
+
+ resetCandidates();
+ totalChoicesNum = result;
+
+ surface = pinyinDecoderService->pinyinString(false);
+ QVector<int> splStart = pinyinDecoderService->spellingStartPositions();
+ QString fullSent = pinyinDecoderService->candidateAt(0);
+ fixedLen = pinyinDecoderService->fixedLength();
+ composingStr = fullSent.mid(0, fixedLen) + surface.mid(splStart[fixedLen + 1]);
+ activeCmpsLen = composingStr.length();
+
+ // Prepare the display string.
+ QString composingStrDisplay;
+ int surfaceDecodedLen = pinyinDecoderService->pinyinStringLength(true);
+ if (!surfaceDecodedLen) {
+ composingStrDisplay = composingStr.toLower();
+ if (!totalChoicesNum)
+ totalChoicesNum = 1;
+ } else {
+ activeCmpsLen = activeCmpsLen - (surface.length() - surfaceDecodedLen);
+ composingStrDisplay = fullSent.mid(0, fixedLen);
+ for (int pos = fixedLen + 1; pos < splStart.size() - 1; pos++) {
+ composingStrDisplay += surface.mid(splStart[pos], splStart[pos + 1] - splStart[pos]).toUpper();
+ if (splStart[pos + 1] < surfaceDecodedLen)
+ composingStrDisplay += " ";
+ }
+ if (surfaceDecodedLen < surface.length())
+ composingStrDisplay += surface.mid(surfaceDecodedLen).toLower();
+ }
+ q->inputContext()->setPreeditText(composingStrDisplay);
+
+ finishSelection = splStart.size() == (fixedLen + 2);
+ if (!finishSelection)
+ candidateAt(0);
+
+ emit q->selectionListChanged(DeclarativeSelectionListModel::WordCandidateList);
+ emit q->selectionListActiveItemChanged(DeclarativeSelectionListModel::WordCandidateList, totalChoicesNum > 0 ? 0 : -1);
+ }
+
+ void choosePredictChoice(int choiceId)
+ {
+ Q_Q(PinyinInputMethod);
+ Q_ASSERT(state == Predict);
+
+ if (choiceId < 0 || choiceId >= totalChoicesNum)
+ return;
+
+ QString tmp = candidatesList.at(choiceId);
+
+ resetCandidates();
+
+ candidatesList.append(tmp);
+ totalChoicesNum = 1;
+
+ surface.clear();
+ fixedLen = tmp.length();
+ composingStr = tmp;
+ activeCmpsLen = fixedLen;
+
+ finishSelection = true;
+
+ emit q->selectionListChanged(DeclarativeSelectionListModel::WordCandidateList);
+ emit q->selectionListActiveItemChanged(DeclarativeSelectionListModel::WordCandidateList, 0);
+ emit q->selectionListActiveItemChanged(DeclarativeSelectionListModel::WordCandidateList, -1);
+ }
+
+ QString getComposingStrActivePart()
+ {
+ return composingStr.mid(0, activeCmpsLen);
+ }
+
+ void resetCandidates()
+ {
+ Q_Q(PinyinInputMethod);
+ candidatesList.clear();
+ if (totalChoicesNum) {
+ totalChoicesNum = 0;
+ emit q->selectionListChanged(DeclarativeSelectionListModel::WordCandidateList);
+ emit q->selectionListActiveItemChanged(DeclarativeSelectionListModel::WordCandidateList, -1);
+ }
+ }
+
+ bool canDoPrediction()
+ {
+ Q_Q(PinyinInputMethod);
+ DeclarativeInputContext *inputContext = q->inputContext();
+ return inputMode == DeclarativeInputEngine::Pinyin &&
+ composingStr.length() == fixedLen &&
+ inputContext &&
+ !inputContext->inputMethodHints().testFlag(Qt::ImhNoPredictiveText);
+ }
+
+ void tryPredict()
+ {
+ // Try to get the prediction list.
+ if (canDoPrediction()) {
+ Q_Q(PinyinInputMethod);
+ if (state != Predict)
+ resetToIdleState();
+ DeclarativeInputContext *inputContext = q->inputContext();
+ int cursorPosition = inputContext->cursorPosition();
+ int historyStart = qMax(0, cursorPosition - 3);
+ QString history = inputContext->surroundingText().mid(historyStart, cursorPosition - historyStart);
+ candidatesList = pinyinDecoderService->predictionList(history);
+ totalChoicesNum = candidatesList.size();
+ emit q->selectionListChanged(DeclarativeSelectionListModel::WordCandidateList);
+ finishSelection = false;
+ state = Predict;
+ } else {
+ resetCandidates();
+ }
+
+ if (!candidatesCount())
+ resetToIdleState();
+ }
+
+ PinyinInputMethod *q_ptr;
+ DeclarativeInputEngine::InputMode inputMode;
+ QPointer<PinyinDecoderService> pinyinDecoderService;
+ State state;
+ QString surface;
+ int totalChoicesNum;
+ QList<QString> candidatesList;
+ int fixedLen;
+ QString composingStr;
+ int activeCmpsLen;
+ bool finishSelection;
+ int posDelSpl;
+ bool isPosInSpl;
+};
+
+PinyinInputMethod::PinyinInputMethod(QObject *parent) :
+ AbstractInputMethod(*new PinyinInputMethodPrivate(this), parent)
+{
+}
+
+PinyinInputMethod::~PinyinInputMethod()
+{
+}
+
+QList<DeclarativeInputEngine::InputMode> PinyinInputMethod::inputModes(const QString &locale)
+{
+ Q_UNUSED(locale)
+ Q_D(PinyinInputMethod);
+ QList<DeclarativeInputEngine::InputMode> result;
+ if (d->pinyinDecoderService)
+ result << DeclarativeInputEngine::Pinyin;
+ result << DeclarativeInputEngine::Latin;
+ return result;
+}
+
+bool PinyinInputMethod::setInputMode(const QString &locale, DeclarativeInputEngine::InputMode inputMode)
+{
+ Q_UNUSED(locale)
+ Q_D(PinyinInputMethod);
+ reset();
+ if (inputMode == DeclarativeInputEngine::Pinyin && !d->pinyinDecoderService)
+ return false;
+ d->inputMode = inputMode;
+ return true;
+}
+
+bool PinyinInputMethod::setTextCase(DeclarativeInputEngine::TextCase textCase)
+{
+ Q_UNUSED(textCase)
+ return true;
+}
+
+bool PinyinInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers)
+{
+ Q_UNUSED(modifiers)
+ Q_D(PinyinInputMethod);
+ if (d->inputMode == DeclarativeInputEngine::Pinyin) {
+ if ((key >= Qt::Key_A && key <= Qt::Key_Z) || (key == Qt::Key_Apostrophe)) {
+ if (d->state == PinyinInputMethodPrivate::Predict)
+ d->resetToIdleState();
+ if (d->addSpellingChar(text.at(0), d->state == PinyinInputMethodPrivate::Idle)) {
+ d->chooseAndUpdate(-1);
+ return true;
+ }
+ } else if (key == Qt::Key_Space) {
+ if (d->state != PinyinInputMethodPrivate::Predict && d->candidatesCount() > 0) {
+ d->chooseAndUpdate(0);
+ return true;
+ }
+ } else if (key == Qt::Key_Return) {
+ if (d->state != PinyinInputMethodPrivate::Predict && d->candidatesCount() > 0) {
+ QString surface = d->surface;
+ d->resetToIdleState();
+ inputContext()->commit(surface);
+ return true;
+ }
+ } else if (key == Qt::Key_Backspace) {
+ if (d->removeSpellingChar()) {
+ d->chooseAndUpdate(-1);
+ return true;
+ }
+ } else {
+ d->chooseAndFinish();
+ }
+ }
+ return false;
+}
+
+QList<DeclarativeSelectionListModel::Type> PinyinInputMethod::selectionLists()
+{
+ return QList<DeclarativeSelectionListModel::Type>() << DeclarativeSelectionListModel::WordCandidateList;
+}
+
+int PinyinInputMethod::selectionListItemCount(DeclarativeSelectionListModel::Type type)
+{
+ Q_UNUSED(type)
+ Q_D(PinyinInputMethod);
+ return d->candidatesCount();
+}
+
+QVariant PinyinInputMethod::selectionListData(DeclarativeSelectionListModel::Type type, int index, int role)
+{
+ QVariant result;
+ Q_UNUSED(type)
+ Q_D(PinyinInputMethod);
+ switch (role) {
+ case DeclarativeSelectionListModel::DisplayRole:
+ result = QVariant(d->candidateAt(index));
+ break;
+ case DeclarativeSelectionListModel::WordCompletionLengthRole:
+ result.setValue(0);
+ break;
+ default:
+ result = AbstractInputMethod::selectionListData(type, index, role);
+ break;
+ }
+ return result;
+}
+
+void PinyinInputMethod::selectionListItemSelected(DeclarativeSelectionListModel::Type type, int index)
+{
+ Q_UNUSED(type)
+ Q_D(PinyinInputMethod);
+ d->chooseAndUpdate(index);
+}
+
+void PinyinInputMethod::reset()
+{
+ Q_D(PinyinInputMethod);
+ d->resetToIdleState();
+}
+
+void PinyinInputMethod::update()
+{
+ Q_D(PinyinInputMethod);
+ d->chooseAndFinish();
+ d->tryPredict();
+}
diff --git a/src/virtualkeyboard/pinyininputmethod.h b/src/virtualkeyboard/pinyininputmethod.h
new file mode 100644
index 00000000..4c7386d7
--- /dev/null
+++ b/src/virtualkeyboard/pinyininputmethod.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the Qt Quick Enterprise Controls add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef PINYININPUTMETHOD_H
+#define PINYININPUTMETHOD_H
+
+#include "abstractinputmethod.h"
+
+class PinyinInputMethodPrivate;
+
+class PinyinInputMethod : public AbstractInputMethod
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(PinyinInputMethod)
+
+public:
+ explicit PinyinInputMethod(QObject *parent = 0);
+ ~PinyinInputMethod();
+
+ QList<DeclarativeInputEngine::InputMode> inputModes(const QString &locale);
+ bool setInputMode(const QString &locale, DeclarativeInputEngine::InputMode inputMode);
+ bool setTextCase(DeclarativeInputEngine::TextCase textCase);
+
+ bool keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers);
+
+ QList<DeclarativeSelectionListModel::Type> selectionLists();
+ int selectionListItemCount(DeclarativeSelectionListModel::Type type);
+ QVariant selectionListData(DeclarativeSelectionListModel::Type type, int index, int role);
+ void selectionListItemSelected(DeclarativeSelectionListModel::Type type, int index);
+
+ void reset();
+ void update();
+};
+
+#endif // PINYININPUTMETHOD_H
diff --git a/src/virtualkeyboard/plaininputmethod.cpp b/src/virtualkeyboard/plaininputmethod.cpp
index 3c433198..1d137f88 100644
--- a/src/virtualkeyboard/plaininputmethod.cpp
+++ b/src/virtualkeyboard/plaininputmethod.cpp
@@ -32,7 +32,12 @@ PlainInputMethod::~PlainInputMethod()
QList<DeclarativeInputEngine::InputMode> PlainInputMethod::inputModes(const QString &locale)
{
Q_UNUSED(locale)
- return QList<DeclarativeInputEngine::InputMode>() << DeclarativeInputEngine::Latin << DeclarativeInputEngine::Numeric;
+ // Supports all input modes
+ return QList<DeclarativeInputEngine::InputMode>()
+ << DeclarativeInputEngine::Latin
+ << DeclarativeInputEngine::Numeric
+ << DeclarativeInputEngine::Dialable
+ << DeclarativeInputEngine::Pinyin;
}
bool PlainInputMethod::setInputMode(const QString &locale, DeclarativeInputEngine::InputMode inputMode)
diff --git a/src/virtualkeyboard/plugin.cpp b/src/virtualkeyboard/plugin.cpp
index cde1e209..2d51437e 100644
--- a/src/virtualkeyboard/plugin.cpp
+++ b/src/virtualkeyboard/plugin.cpp
@@ -28,6 +28,9 @@
#ifdef HAVE_HUNSPELL
#include "hunspellinputmethod.h"
#endif
+#ifdef HAVE_PINYIN
+#include "pinyininputmethod.h"
+#endif
#include "declarativeinputmethod.h"
#include "declarativeselectionlistmodel.h"
#include "enterkeyaction.h"
@@ -71,6 +74,9 @@ QPlatformInputContext *PlatformInputContextPlugin::create(const QString &system,
#ifdef HAVE_HUNSPELL
qmlRegisterType<HunspellInputMethod>("QtQuick.Enterprise.VirtualKeyboard", 1, 0, "HunspellInputMethod");
#endif
+#ifdef HAVE_PINYIN
+ qmlRegisterType<PinyinInputMethod>("QtQuick.Enterprise.VirtualKeyboard", 1, 0, "PinyinInputMethod");
+#endif
qmlRegisterType<EnterKeyActionAttachedType>();
qmlRegisterType<EnterKeyAction>("QtQuick.Enterprise.VirtualKeyboard", 1, 0, "EnterKeyAction");
diff --git a/src/virtualkeyboard/virtualkeyboard.pro b/src/virtualkeyboard/virtualkeyboard.pro
index 9054bf1a..f4ec1f86 100644
--- a/src/virtualkeyboard/virtualkeyboard.pro
+++ b/src/virtualkeyboard/virtualkeyboard.pro
@@ -81,10 +81,24 @@ OTHER += qtvirtualkeyboard.json
DEFINES += QT_VIRTUALKEYBOARD_IMPORT_PATH=\\\"$$QMLPATH\\\"
qml.files = content/*.qml \
content/qmldir \
- content/components \
- content/layouts
+ content/components
qml.path = $$QMLPATH
INSTALLS += qml
+pinyin: qml_layouts.files = \
+ content/layouts/en_GB \
+ content/layouts/zh_CN
+else: qml_layouts.files = \
+ content/layouts/ar_AR \
+ content/layouts/de_DE \
+ content/layouts/en_GB \
+ content/layouts/es_ES \
+ content/layouts/fi_FI \
+ content/layouts/fr_FR \
+ content/layouts/it_IT \
+ content/layouts/pt_PT \
+ content/layouts/ru_RU
+qml_layouts.path = $$QMLPATH/layouts
+INSTALLS += qml_layouts
!disable-hunspell {
exists(3rdparty/hunspell/src/hunspell/hunspell.h) {
@@ -116,3 +130,20 @@ INSTALLS += qml
message(Hunspell not found! Spell correction will not be available.)
}
}
+
+pinyin {
+ SOURCES += \
+ pinyininputmethod.cpp \
+ pinyindecoderservice.cpp
+ HEADERS += \
+ pinyininputmethod.h \
+ pinyindecoderservice.h
+ DEFINES += HAVE_PINYIN
+ INCLUDEPATH += 3rdparty/pinyin/include
+ DEPENDPATH += 3rdparty/pinyin/include
+ LIBS += -L$$OUT_PWD/3rdparty/pinyin/ -lpinyin
+ DEFINES += QT_VIRTUALKEYBOARD_PINYIN_DICTIONARY=\\\"$$DATAPATH/pinyin/dict_pinyin.dat\\\"
+ pinyin_data.files = $$PWD/3rdparty/pinyin/data/dict_pinyin.dat
+ pinyin_data.path = $$DATAPATH/pinyin
+ INSTALLS += pinyin_data
+}