summaryrefslogtreecommitdiff
authorTing Li <ting.li@amlogic.com>2015-04-24 10:16:46 (GMT)
committer Ting Li <ting.li@amlogic.com>2015-04-24 10:30:17 (GMT)
commit0627d4b1ff66ffdc9ca18f0ca28da8ae41cb7b2e (patch)
tree67a7a44d27ffddba1e7195cf795b642b5dcc822d
parentf44c8021f1420e11cab0128423c08df36919d446 (diff)
downloadRemoteIME-0627d4b1ff66ffdc9ca18f0ca28da8ae41cb7b2e.zip
RemoteIME-0627d4b1ff66ffdc9ca18f0ca28da8ae41cb7b2e.tar.gz
RemoteIME-0627d4b1ff66ffdc9ca18f0ca28da8ae41cb7b2e.tar.bz2
update code to new packageName & adjust code format
Change-Id: I0bb2f7947d99e2c012207b7fc6a6f2211887ccc2
Diffstat
-rw-r--r--Android.mk2
-rwxr-xr-xAndroidManifest.xml62
-rw-r--r--jni/Android.mk2
-rwxr-xr-xjni/android/com_amlogic_inputmethod_remote_PinyinDecoderService.cpp441
-rw-r--r--jni/android/com_droidlogic_inputmethod_remote_PinyinDecoderService.cpp449
-rwxr-xr-xjni/command/pinyinime_dictbuilder.cpp48
-rwxr-xr-xjni/include/atomdictbase.h400
-rwxr-xr-xjni/include/dictbuilder.h200
-rwxr-xr-xjni/include/dictdef.h252
-rwxr-xr-xjni/include/dictlist.h124
-rwxr-xr-xjni/include/dicttrie.h348
-rwxr-xr-xjni/include/lpicache.h66
-rwxr-xr-xjni/include/matrixsearch.h850
-rwxr-xr-xjni/include/mystdlib.h10
-rwxr-xr-xjni/include/ngram.h94
-rwxr-xr-xjni/include/pinyinime.h358
-rwxr-xr-xjni/include/searchutility.h228
-rwxr-xr-xjni/include/spellingtable.h162
-rwxr-xr-xjni/include/spellingtrie.h382
-rwxr-xr-xjni/include/splparser.h120
-rwxr-xr-xjni/include/sync.h104
-rwxr-xr-xjni/include/userdict.h588
-rwxr-xr-xjni/include/utf16char.h32
-rwxr-xr-xjni/include/utf16reader.h42
-rwxr-xr-xjni/share/dictbuilder.cpp1778
-rwxr-xr-xjni/share/dictlist.cpp711
-rwxr-xr-xjni/share/dicttrie.cpp1611
-rwxr-xr-xjni/share/lpicache.cpp100
-rwxr-xr-xjni/share/matrixsearch.cpp3400
-rwxr-xr-xjni/share/mystdlib.cpp22
-rwxr-xr-xjni/share/ngram.cpp524
-rwxr-xr-xjni/share/pinyinime.cpp244
-rwxr-xr-xjni/share/searchutility.cpp358
-rwxr-xr-xjni/share/spellingtable.cpp478
-rwxr-xr-xjni/share/spellingtrie.cpp1415
-rwxr-xr-xjni/share/splparser.cpp554
-rwxr-xr-xjni/share/sync.cpp164
-rwxr-xr-xjni/share/userdict.cpp3824
-rwxr-xr-xjni/share/utf16char.cpp283
-rwxr-xr-xjni/share/utf16reader.cpp184
-rwxr-xr-xlib/Android.mk4
-rwxr-xr-xlib/com/droidlogic/inputmethod/remote/IPinyinDecoderService.aidl (renamed from lib/com/amlogic/inputmethod/remote/IPinyinDecoderService.aidl)2
-rwxr-xr-xres/drawable-nodpi/arrow_bg.xml8
-rwxr-xr-xres/layout/candidates_container.xml48
-rwxr-xr-xres/layout/floating_container.xml15
-rwxr-xr-xres/layout/skb_container.xml30
-rwxr-xr-xres/values-en/bools.xml4
-rwxr-xr-xres/values-land/dimens.xml6
-rwxr-xr-xres/values-port/dimens.xml6
-rwxr-xr-xres/values-zh-rCN/bools.xml4
-rwxr-xr-xres/values-zh-rCN/strings.xml100
-rwxr-xr-xres/values-zh-rTW/bools.xml4
-rwxr-xr-xres/values-zh-rTW/strings.xml96
-rwxr-xr-xres/values/colors.xml22
-rwxr-xr-xres/values/config.xml6
-rwxr-xr-xres/values/dimens.xml2
-rwxr-xr-xres/values/strings.xml100
-rwxr-xr-xres/xml/method.xml19
-rwxr-xr-xres/xml/settings.xml50
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/BalloonHint.java472
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/CandidateView.java760
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/CandidatesContainer.java474
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/ComposingView.java280
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/EnglishInputProcessor.java110
-rw-r--r--src/com/amlogic/inputmethod/remote/Environment.java221
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/InputModeSwitcher.java836
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/KeyMapDream.java106
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/PinyinDecoderService.java326
-rw-r--r--src/com/amlogic/inputmethod/remote/RemoteIME.java2311
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/Settings.java101
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SettingsActivity.java117
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SkbContainer.java801
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SkbPool.java92
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SkbTemplate.java233
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SoftKey.java238
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SoftKeyToggle.java283
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SoftKeyboard.java541
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SoftKeyboardView.java495
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/SoundManager.java64
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/Vibrator.java132
-rwxr-xr-xsrc/com/amlogic/inputmethod/remote/XmlKeyboardLoader.java835
-rw-r--r--src/com/droidlogic/inputmethod/remote/BalloonHint.java460
-rw-r--r--src/com/droidlogic/inputmethod/remote/CandidateView.java709
-rw-r--r--[-rwxr-xr-x]src/com/droidlogic/inputmethod/remote/CandidateViewListener.java (renamed from src/com/amlogic/inputmethod/remote/CandidateViewListener.java)4
-rw-r--r--src/com/droidlogic/inputmethod/remote/CandidatesContainer.java449
-rw-r--r--src/com/droidlogic/inputmethod/remote/ComposingView.java259
-rw-r--r--src/com/droidlogic/inputmethod/remote/EnglishInputProcessor.java101
-rw-r--r--src/com/droidlogic/inputmethod/remote/Environment.java221
-rw-r--r--src/com/droidlogic/inputmethod/remote/InputModeSwitcher.java814
-rw-r--r--src/com/droidlogic/inputmethod/remote/KeyMapDream.java107
-rw-r--r--src/com/droidlogic/inputmethod/remote/PinyinDecoderService.java294
-rw-r--r--src/com/droidlogic/inputmethod/remote/RemoteIME.java2158
-rw-r--r--src/com/droidlogic/inputmethod/remote/Settings.java101
-rw-r--r--src/com/droidlogic/inputmethod/remote/SettingsActivity.java111
-rw-r--r--src/com/droidlogic/inputmethod/remote/SkbContainer.java704
-rw-r--r--src/com/droidlogic/inputmethod/remote/SkbPool.java92
-rw-r--r--src/com/droidlogic/inputmethod/remote/SkbTemplate.java229
-rw-r--r--src/com/droidlogic/inputmethod/remote/SoftKey.java237
-rw-r--r--src/com/droidlogic/inputmethod/remote/SoftKeyToggle.java280
-rw-r--r--src/com/droidlogic/inputmethod/remote/SoftKeyboard.java532
-rw-r--r--src/com/droidlogic/inputmethod/remote/SoftKeyboardView.java464
-rw-r--r--src/com/droidlogic/inputmethod/remote/SoundManager.java64
-rw-r--r--src/com/droidlogic/inputmethod/remote/Vibrator.java127
-rw-r--r--src/com/droidlogic/inputmethod/remote/XmlKeyboardLoader.java810
104 files changed, 19487 insertions, 21208 deletions
diff --git a/Android.mk b/Android.mk
index aa93285..862de2c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -11,7 +11,7 @@ LOCAL_PACKAGE_NAME := RemoteIME
LOCAL_JAVA_LIBRARIES := droidlogic
LOCAL_REQUIRED_MODULES := libjni_remoteime
-LOCAL_STATIC_JAVA_LIBRARIES := com.amlogic.inputmethod.remote.lib
+LOCAL_STATIC_JAVA_LIBRARIES := com.droidlogic.inputmethod.remote.lib
LOCAL_CERTIFICATE := shared
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 942443b..58cfa09 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,42 +13,26 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.amlogic.inputmethod.remote"
- android:sharedUserId="android.uid.shared">
-
- <original-package android:name="com.amlogic.inputmethod.remote" />
-
- <uses-permission android:name="android.permission.VIBRATE"/>
-
- <application android:icon="@drawable/app_icon"
- android:allowBackup="false"
- android:persistent="true"
- android:killAfterRestore="false"
- android:label="@string/ime_name">
- <service android:name=".PinyinDecoderService"
- android:exported="true">
- <intent-filter>
- <action android:name="com.android.inputmethod.pinyin.Decoder_Service" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </service>
-
- <service android:name=".RemoteIME"
- android:label="@string/ime_name"
- android:permission="android.permission.BIND_INPUT_METHOD">
- <intent-filter>
- <action android:name="android.view.InputMethod" />
- </intent-filter>
- <meta-data android:name="android.view.im" android:resource="@xml/method" />
- </service>
-
- <activity android:name=".SettingsActivity"
- android:label="@string/ime_settings_activity_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- </intent-filter>
- </activity>
-
- </application>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.droidlogic.inputmethod.remote" android:sharedUserId="android.uid.shared">
+ <original-package android:name="com.amlogic.inputmethod.remote" />
+ <uses-permission android:name="android.permission.VIBRATE" />
+ <application android:icon="@drawable/app_icon" android:allowBackup="false" android:persistent="true" android:killAfterRestore="false" android:label="@string/ime_name">
+ <service android:name=".PinyinDecoderService" android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.inputmethod.pinyin.Decoder_Service" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+ <service android:name=".RemoteIME" android:label="@string/ime_name" android:permission="android.permission.BIND_INPUT_METHOD">
+ <intent-filter>
+ <action android:name="android.view.InputMethod" />
+ </intent-filter>
+ <meta-data android:name="android.view.im" android:resource="@xml/method" />
+ </service>
+ <activity android:name=".SettingsActivity" android:label="@string/ime_settings_activity_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ </application>
</manifest>
diff --git a/jni/Android.mk b/jni/Android.mk
index 440253a..16d03f2 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -5,7 +5,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- android/com_amlogic_inputmethod_remote_PinyinDecoderService.cpp \
+ android/com_droidlogic_inputmethod_remote_PinyinDecoderService.cpp \
share/dictbuilder.cpp \
share/dictlist.cpp \
share/dicttrie.cpp \
diff --git a/jni/android/com_amlogic_inputmethod_remote_PinyinDecoderService.cpp b/jni/android/com_amlogic_inputmethod_remote_PinyinDecoderService.cpp
deleted file mode 100755
index f033f86..0000000
--- a/jni/android/com_amlogic_inputmethod_remote_PinyinDecoderService.cpp
+++ b/dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include <cutils/log.h>
-#include <jni.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "../include/pinyinime.h"
-#include "../include/sync.h"
-#include "../include/userdict.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-using namespace ime_pinyin;
-
-#define RET_BUF_LEN 256
-
-static char16 retbuf[RET_BUF_LEN];
-static char16 (*predict_buf)[kMaxPredictSize + 1] = NULL;
-static size_t predict_len;
-
-static Sync sync_worker;
-
-static struct file_descriptor_offsets_t
-{
- jclass mClass;
- jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
-JNIEXPORT jboolean JNICALL nativeImOpenDecoder(JNIEnv* env, jclass jclazz,
- jbyteArray fn_sys_dict,
- jbyteArray fn_usr_dict) {
- jbyte *fsd = (*env).GetByteArrayElements(fn_sys_dict, 0);
- jbyte *fud = (*env).GetByteArrayElements(fn_usr_dict, 0);
-
- jboolean jret = JNI_FALSE;
-
- if (im_open_decoder((const char*)fsd, (const char*)fud))
- jret = JNI_TRUE;
-
- (*env).ReleaseByteArrayElements(fn_sys_dict, fsd, 0);
- (*env).ReleaseByteArrayElements(fn_usr_dict, fud, 0);
-
- return jret;
-}
-
-JNIEXPORT jboolean JNICALL nativeImOpenDecoderFd(JNIEnv* env, jclass jclazz,
- jobject fd_sys_dict,
- jlong startoffset,
- jlong length,
- jbyteArray fn_usr_dict) {
- jint fd = env->GetIntField(fd_sys_dict, gFileDescriptorOffsets.mDescriptor);
- jbyte *fud = (*env).GetByteArrayElements(fn_usr_dict, 0);
-
- jboolean jret = JNI_FALSE;
-
- int newfd = dup(fd);
- if (im_open_decoder_fd(newfd, startoffset, length, (const char*)fud))
- jret = JNI_TRUE;
-
- close(newfd);
-
- (*env).ReleaseByteArrayElements(fn_usr_dict, fud, 0);
-
- return jret;
-}
-
-JNIEXPORT void JNICALL nativeImSetMaxLens(JNIEnv* env, jclass jclazz,
- jint max_sps_len,
- jint max_hzs_len) {
- im_set_max_lens(static_cast<size_t>(max_sps_len),
- static_cast<size_t>(max_hzs_len));
- return;
-}
-
-JNIEXPORT jboolean JNICALL nativeImCloseDecoder(JNIEnv* env, jclass jclazz) {
- im_close_decoder();
- return JNI_TRUE;
-}
-
-JNIEXPORT jint JNICALL nativeImSearch(JNIEnv* env, jclass jclazz,
- jbyteArray pybuf, jint pylen) {
- jbyte *array_body = (*env).GetByteArrayElements(pybuf, 0);
-
- jint jret = 0;
- if (NULL != array_body) {
- jret = im_search((const char*)array_body, pylen);
- }
-
- (*env).ReleaseByteArrayElements(pybuf, array_body, 0);
-
- return jret;
-}
-
-JNIEXPORT jint JNICALL nativeImDelSearch(JNIEnv* env, jclass jclazz, jint pos,
- jboolean is_pos_in_splid,
- jboolean clear_fixed_this_step) {
- return im_delsearch(pos, is_pos_in_splid, clear_fixed_this_step);
-}
-
-JNIEXPORT void JNICALL nativeImResetSearch(JNIEnv* env, jclass jclazz) {
- im_reset_search();
- return;
-}
-
-JNIEXPORT jint JNICALL nativeImAddLetter(JNIEnv *env, jclass clazz, jbyte ch) {
- return im_add_letter(ch);
-}
-
-JNIEXPORT jstring JNICALL nativeImGetPyStr(JNIEnv* env, jclass jclazz,
- jboolean decoded) {
- size_t py_len;
- const char *py = im_get_sps_str(&py_len); // py_len gets decoded length
- assert(NULL != py);
- if (!decoded)
- py_len = strlen(py);
-
- const unsigned short *spl_start;
- size_t len;
- len = im_get_spl_start_pos(spl_start);
-
- size_t i;
- for (i = 0; i < py_len; i++)
- retbuf[i] = py[i];
- retbuf[i] = (char16)'\0';
-
- jstring retstr = (*env).NewString((unsigned short*)retbuf, i);
- return retstr;
-}
-
-JNIEXPORT jint JNICALL nativeImGetPyStrLen(JNIEnv* env, jclass jclazz,
- jboolean decoded) {
- size_t py_len;
- const char *py = im_get_sps_str(&py_len); // py_len gets decoded length
- assert(NULL != py);
- if (!decoded)
- py_len = strlen(py);
- return py_len;
-}
-
-JNIEXPORT jintArray JNICALL nativeImGetSplStart(JNIEnv* env, jclass jclazz) {
- 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);
-
- jintArray arr = (*env).NewIntArray(len + 2);
- jint *arr_body = (*env).GetIntArrayElements(arr, 0);
- assert(NULL != arr_body);
- arr_body[0] = len; // element 0 is used to store the length of buffer.
- for (size_t i = 0; i <= len; i++)
- arr_body[i + 1] = spl_start[i];
-
- (*env).ReleaseIntArrayElements(arr, arr_body, 0);
-
- return arr;
-}
-
-JNIEXPORT jstring JNICALL nativeImGetChoice(JNIEnv *env, jclass clazz,
- jint candidateId) {
- jstring retstr;
- if(im_get_candidate(candidateId, retbuf, RET_BUF_LEN)) {
- retstr = (*env).NewString(retbuf, utf16_strlen(retbuf));
- return retstr;
- } else {
- retstr = (*env).NewString((unsigned short*)retbuf, 0);
- return retstr;
- }
-}
-
-JNIEXPORT jint JNICALL nativeImChoose(JNIEnv *env, jclass clazz,
- jint choice_id) {
- return im_choose(choice_id);
-}
-
-JNIEXPORT jint JNICALL nativeImCancelLastChoice(JNIEnv *env, jclass clazz) {
- return im_cancel_last_choice();
-}
-
-JNIEXPORT jint JNICALL nativeImGetFixedLen(JNIEnv *env, jclass clazz) {
- return im_get_fixed_len();
-}
-
-JNIEXPORT jboolean JNICALL nativeImCancelInput(JNIEnv *env, jclass clazz) {
- if (im_cancel_input())
- return JNI_TRUE;
-
- return JNI_FALSE;
-}
-
-JNIEXPORT jboolean JNICALL nativeImFlushCache(JNIEnv *env, jclass clazz) {
- im_flush_cache();
- return JNI_TRUE;
-}
-
-JNIEXPORT jint JNICALL nativeImGetPredictsNum(JNIEnv *env, jclass clazz,
- jstring fixed_str) {
- char16 *fixed_ptr = (char16*)(*env).GetStringChars(fixed_str, false);
- size_t fixed_len = (size_t)(*env).GetStringLength(fixed_str);
-
- char16 fixed_buf[kMaxPredictSize + 1];
-
- if (fixed_len > kMaxPredictSize) {
- fixed_ptr += fixed_len - kMaxPredictSize;
- fixed_len = kMaxPredictSize;
- }
- utf16_strncpy(fixed_buf, fixed_ptr, fixed_len);
- fixed_buf[fixed_len] = (char16)'\0';
-
- predict_len = im_get_predicts(fixed_buf, predict_buf);
-
- (*env).ReleaseStringChars(fixed_str, fixed_ptr);
-
- return predict_len;
-}
-
-JNIEXPORT jstring JNICALL nativeImGetPredictItem(JNIEnv *env, jclass clazz,
- jint predict_no) {
- jstring retstr;
-
- if (predict_no < 0 || (size_t)predict_no >= predict_len) {
- retstr = (*env).NewString((unsigned short*)predict_buf[0], 0);
- } else {
- retstr = (*env).NewString((unsigned short*)predict_buf[predict_no],
- utf16_strlen(predict_buf[predict_no]));
- }
- return retstr;
-}
-
-JNIEXPORT jboolean JNICALL nativeSyncBegin(JNIEnv *env, jclass clazz,
- jbyteArray dict_file) {
- jbyte *file_name = (*env).GetByteArrayElements(dict_file, 0);
-
- jboolean jret = JNI_FALSE;
- if (true == sync_worker.begin((const char *)file_name))
- jret = JNI_TRUE;
-
- (*env).ReleaseByteArrayElements(dict_file, file_name, 0);
-
- return jret;
-}
-
-JNIEXPORT jboolean JNICALL nativeSyncFinish(JNIEnv *env, jclass clazz) {
- sync_worker.finish();
- return JNI_TRUE;
-}
-
-JNIEXPORT jint JNICALL nativeSyncGetCapacity(JNIEnv *env, jclass clazz) {
- return sync_worker.get_capacity();
-}
-
-JNIEXPORT jint JNICALL nativeSyncPutLemmas(JNIEnv *env, jclass clazz,
- jstring tomerge) {
-
- char16 *ptr = (char16*)(*env).GetStringChars(tomerge, NULL);
- int len = (size_t)(*env).GetStringLength(tomerge);
-
- int added = sync_worker.put_lemmas(ptr, len);
-
- (*env).ReleaseStringChars(tomerge, ptr);
-
- return added;
-}
-
-JNIEXPORT jstring JNICALL nativeSyncGetLemmas(JNIEnv *env, jclass clazz) {
-
- int len = sync_worker.get_lemmas(retbuf, RET_BUF_LEN);
- if (len == 0)
- return NULL;
- jstring retstr;
- retstr = (*env).NewString((unsigned short*)retbuf, len);
- return retstr;
-}
-
-JNIEXPORT jint JNICALL nativeSyncGetLastCount(JNIEnv *env, jclass clazz) {
- return sync_worker.get_last_got_count();
-}
-
-JNIEXPORT jint JNICALL nativeSyncGetTotalCount(JNIEnv *env, jclass clazz) {
- return sync_worker.get_total_count();
-}
-
-JNIEXPORT jboolean JNICALL nativeSyncClearLastGot(JNIEnv *env, jclass clazz) {
- sync_worker.clear_last_got();
- return JNI_TRUE;
-}
-
-/**
- * Table of methods associated with a single class.
- */
-static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- /* ------Functions for Pinyin-to-hanzi decoding begin--------->> */
- { "nativeImOpenDecoder", "([B[B)Z",
- (void*) nativeImOpenDecoder },
- { "nativeImOpenDecoderFd", "(Ljava/io/FileDescriptor;JJ[B)Z",
- (void*) nativeImOpenDecoderFd },
- { "nativeImSetMaxLens", "(II)V",
- (void*) nativeImSetMaxLens },
- { "nativeImCloseDecoder", "()Z",
- (void*) nativeImCloseDecoder },
- { "nativeImSearch", "([BI)I",
- (void*) nativeImSearch },
- { "nativeImDelSearch", "(IZZ)I",
- (void*) nativeImDelSearch },
- { "nativeImResetSearch", "()V",
- (void*) nativeImResetSearch },
- { "nativeImAddLetter", "(B)I",
- (void*) nativeImAddLetter },
- { "nativeImGetPyStr", "(Z)Ljava/lang/String;",
- (void*) nativeImGetPyStr },
- { "nativeImGetPyStrLen", "(Z)I",
- (void*) nativeImGetPyStrLen },
- { "nativeImGetSplStart", "()[I",
- (void*) nativeImGetSplStart },
- { "nativeImGetChoice", "(I)Ljava/lang/String;",
- (void*) nativeImGetChoice },
- { "nativeImChoose", "(I)I",
- (void*) nativeImChoose },
- { "nativeImCancelLastChoice", "()I",
- (void*) nativeImCancelLastChoice },
- { "nativeImGetFixedLen", "()I",
- (void*) nativeImGetFixedLen },
- { "nativeImGetPredictsNum", "(Ljava/lang/String;)I",
- (void*) nativeImGetPredictsNum },
- { "nativeImGetPredictItem", "(I)Ljava/lang/String;",
- (void*) nativeImGetPredictItem },
- { "nativeImCancelInput", "()Z",
- (void*) nativeImCancelInput },
- { "nativeImFlushCache", "()Z",
- (void*) nativeImFlushCache },
- /* <<----Functions for Pinyin-to-hanzi decoding end------------- */
-
- /* ------Functions for sync begin----------------------------->> */
- { "nativeSyncBegin", "([B)Z",
- (void*) nativeSyncBegin },
- { "nativeSyncFinish", "()Z",
- (void*) nativeSyncFinish },
- { "nativeSyncPutLemmas", "(Ljava/lang/String;)I",
- (void*) nativeSyncPutLemmas },
- { "nativeSyncGetLemmas", "()Ljava/lang/String;",
- (void*) nativeSyncGetLemmas },
- { "nativeSyncGetLastCount", "()I",
- (void*) nativeSyncGetLastCount },
- { "nativeSyncGetTotalCount", "()I",
- (void*) nativeSyncGetTotalCount },
- { "nativeSyncClearLastGot", "()Z",
- (void*) nativeSyncClearLastGot },
- { "nativeSyncGetCapacity", "()I",
- (void*) nativeSyncGetCapacity },
- /* <<----Functions for sync end--------------------------------- */
-};
-
-
-/*
- * Register several native methods for one class.
- */
-static int registerNativeMethods(JNIEnv* env, const char* className,
- JNINativeMethod* gMethods, int numMethods)
-{
- jclass clazz;
-
- clazz = (*env).FindClass(className);
- if (clazz == NULL) {
- return JNI_FALSE;
- }
- if ((*env).RegisterNatives(clazz, gMethods, numMethods) < 0) {
- return JNI_FALSE;
- }
-
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find Java class java.io.FileDescriptor");
- gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
- gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
- return JNI_TRUE;
-}
-
-/*
- * Register native methods for all classes we know about.
- */
-static int registerNatives(JNIEnv* env)
-{
- if (!registerNativeMethods(env,
- "com/amlogic/inputmethod/remote/PinyinDecoderService",
- gMethods, sizeof(gMethods) / sizeof(gMethods[0])))
- return JNI_FALSE;
-
- return JNI_TRUE;
-}
-
-/*
- * Set some test stuff up.
- *
- * Returns the JNI version on success, -1 on failure.
- */
-JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
-{
- JNIEnv* env = NULL;
- jint result = -1;
-
- if ((*vm).GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- goto bail;
- }
- assert(env != NULL);
-
- if (!registerNatives(env)) {
- goto bail;
- }
-
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
-
-bail:
- return result;
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/jni/android/com_droidlogic_inputmethod_remote_PinyinDecoderService.cpp b/jni/android/com_droidlogic_inputmethod_remote_PinyinDecoderService.cpp
new file mode 100644
index 0000000..c8b9415
--- a/dev/null
+++ b/jni/android/com_droidlogic_inputmethod_remote_PinyinDecoderService.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <cutils/log.h>
+#include <jni.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "../include/pinyinime.h"
+#include "../include/sync.h"
+#include "../include/userdict.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ using namespace ime_pinyin;
+
+#define RET_BUF_LEN 256
+
+ static char16 retbuf[RET_BUF_LEN];
+ static char16 ( *predict_buf ) [kMaxPredictSize + 1] = NULL;
+ static size_t predict_len;
+
+ static Sync sync_worker;
+
+ static struct file_descriptor_offsets_t {
+ jclass mClass;
+ jfieldID mDescriptor;
+ } gFileDescriptorOffsets;
+
+ JNIEXPORT jboolean JNICALL nativeImOpenDecoder ( JNIEnv *env, jclass jclazz,
+ jbyteArray fn_sys_dict,
+ jbyteArray fn_usr_dict ) {
+ jbyte *fsd = ( *env ).GetByteArrayElements ( fn_sys_dict, 0 );
+ jbyte *fud = ( *env ).GetByteArrayElements ( fn_usr_dict, 0 );
+ jboolean jret = JNI_FALSE;
+ if ( im_open_decoder ( ( const char * ) fsd, ( const char * ) fud ) )
+ { jret = JNI_TRUE; }
+ ( *env ).ReleaseByteArrayElements ( fn_sys_dict, fsd, 0 );
+ ( *env ).ReleaseByteArrayElements ( fn_usr_dict, fud, 0 );
+ return jret;
+ }
+
+ JNIEXPORT jboolean JNICALL nativeImOpenDecoderFd ( JNIEnv *env, jclass jclazz,
+ jobject fd_sys_dict,
+ jlong startoffset,
+ jlong length,
+ jbyteArray fn_usr_dict ) {
+ jint fd = env->GetIntField ( fd_sys_dict, gFileDescriptorOffsets.mDescriptor );
+ jbyte *fud = ( *env ).GetByteArrayElements ( fn_usr_dict, 0 );
+ jboolean jret = JNI_FALSE;
+ int newfd = dup ( fd );
+ if ( im_open_decoder_fd ( newfd, startoffset, length, ( const char * ) fud ) )
+ { jret = JNI_TRUE; }
+ close ( newfd );
+ ( *env ).ReleaseByteArrayElements ( fn_usr_dict, fud, 0 );
+ return jret;
+ }
+
+ JNIEXPORT void JNICALL nativeImSetMaxLens ( JNIEnv *env, jclass jclazz,
+ jint max_sps_len,
+ jint max_hzs_len ) {
+ im_set_max_lens ( static_cast<size_t> ( max_sps_len ),
+ static_cast<size_t> ( max_hzs_len ) );
+ return;
+ }
+
+ JNIEXPORT jboolean JNICALL nativeImCloseDecoder ( JNIEnv *env, jclass jclazz ) {
+ im_close_decoder();
+ return JNI_TRUE;
+ }
+
+ JNIEXPORT jint JNICALL nativeImSearch ( JNIEnv *env, jclass jclazz,
+ jbyteArray pybuf, jint pylen ) {
+ jbyte *array_body = ( *env ).GetByteArrayElements ( pybuf, 0 );
+ jint jret = 0;
+ if ( NULL != array_body ) {
+ jret = im_search ( ( const char * ) array_body, pylen );
+ }
+ ( *env ).ReleaseByteArrayElements ( pybuf, array_body, 0 );
+ return jret;
+ }
+
+ JNIEXPORT jint JNICALL nativeImDelSearch ( JNIEnv *env, jclass jclazz, jint pos,
+ jboolean is_pos_in_splid,
+ jboolean clear_fixed_this_step ) {
+ return im_delsearch ( pos, is_pos_in_splid, clear_fixed_this_step );
+ }
+
+ JNIEXPORT void JNICALL nativeImResetSearch ( JNIEnv *env, jclass jclazz ) {
+ im_reset_search();
+ return;
+ }
+
+ JNIEXPORT jint JNICALL nativeImAddLetter ( JNIEnv *env, jclass clazz, jbyte ch ) {
+ return im_add_letter ( ch );
+ }
+
+ JNIEXPORT jstring JNICALL nativeImGetPyStr ( JNIEnv *env, jclass jclazz,
+ jboolean decoded ) {
+ size_t py_len;
+ const char *py = im_get_sps_str ( &py_len ); // py_len gets decoded length
+ assert ( NULL != py );
+ if ( !decoded )
+ { py_len = strlen ( py ); }
+ const unsigned short *spl_start;
+ size_t len;
+ len = im_get_spl_start_pos ( spl_start );
+ size_t i;
+ for ( i = 0; i < py_len; i++ )
+ { retbuf[i] = py[i]; }
+ retbuf[i] = ( char16 ) '\0';
+ jstring retstr = ( *env ).NewString ( ( unsigned short * ) retbuf, i );
+ return retstr;
+ }
+
+ JNIEXPORT jint JNICALL nativeImGetPyStrLen ( JNIEnv *env, jclass jclazz,
+ jboolean decoded ) {
+ size_t py_len;
+ const char *py = im_get_sps_str ( &py_len ); // py_len gets decoded length
+ assert ( NULL != py );
+ if ( !decoded )
+ { py_len = strlen ( py ); }
+ return py_len;
+ }
+
+ JNIEXPORT jintArray JNICALL nativeImGetSplStart ( JNIEnv *env, jclass jclazz ) {
+ 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 );
+ jintArray arr = ( *env ).NewIntArray ( len + 2 );
+ jint *arr_body = ( *env ).GetIntArrayElements ( arr, 0 );
+ assert ( NULL != arr_body );
+ arr_body[0] = len; // element 0 is used to store the length of buffer.
+ for ( size_t i = 0; i <= len; i++ )
+ { arr_body[i + 1] = spl_start[i]; }
+ ( *env ).ReleaseIntArrayElements ( arr, arr_body, 0 );
+ return arr;
+ }
+
+ JNIEXPORT jstring JNICALL nativeImGetChoice ( JNIEnv *env, jclass clazz,
+ jint candidateId ) {
+ jstring retstr;
+ if ( im_get_candidate ( candidateId, retbuf, RET_BUF_LEN ) ) {
+ retstr = ( *env ).NewString ( retbuf, utf16_strlen ( retbuf ) );
+ return retstr;
+ } else {
+ retstr = ( *env ).NewString ( ( unsigned short * ) retbuf, 0 );
+ return retstr;
+ }
+ }
+
+ JNIEXPORT jint JNICALL nativeImChoose ( JNIEnv *env, jclass clazz,
+ jint choice_id ) {
+ return im_choose ( choice_id );
+ }
+
+ JNIEXPORT jint JNICALL nativeImCancelLastChoice ( JNIEnv *env, jclass clazz ) {
+ return im_cancel_last_choice();
+ }
+
+ JNIEXPORT jint JNICALL nativeImGetFixedLen ( JNIEnv *env, jclass clazz ) {
+ return im_get_fixed_len();
+ }
+
+ JNIEXPORT jboolean JNICALL nativeImCancelInput ( JNIEnv *env, jclass clazz ) {
+ if ( im_cancel_input() )
+ { return JNI_TRUE; }
+ return JNI_FALSE;
+ }
+
+ JNIEXPORT jboolean JNICALL nativeImFlushCache ( JNIEnv *env, jclass clazz ) {
+ im_flush_cache();
+ return JNI_TRUE;
+ }
+
+ JNIEXPORT jint JNICALL nativeImGetPredictsNum ( JNIEnv *env, jclass clazz,
+ jstring fixed_str ) {
+ char16 *fixed_ptr = ( char16 * ) ( *env ).GetStringChars ( fixed_str, false );
+ size_t fixed_len = ( size_t ) ( *env ).GetStringLength ( fixed_str );
+ char16 fixed_buf[kMaxPredictSize + 1];
+ if ( fixed_len > kMaxPredictSize ) {
+ fixed_ptr += fixed_len - kMaxPredictSize;
+ fixed_len = kMaxPredictSize;
+ }
+ utf16_strncpy ( fixed_buf, fixed_ptr, fixed_len );
+ fixed_buf[fixed_len] = ( char16 ) '\0';
+ predict_len = im_get_predicts ( fixed_buf, predict_buf );
+ ( *env ).ReleaseStringChars ( fixed_str, fixed_ptr );
+ return predict_len;
+ }
+
+ JNIEXPORT jstring JNICALL nativeImGetPredictItem ( JNIEnv *env, jclass clazz,
+ jint predict_no ) {
+ jstring retstr;
+ if ( predict_no < 0 || ( size_t ) predict_no >= predict_len ) {
+ retstr = ( *env ).NewString ( ( unsigned short * ) predict_buf[0], 0 );
+ } else {
+ retstr = ( *env ).NewString ( ( unsigned short * ) predict_buf[predict_no],
+ utf16_strlen ( predict_buf[predict_no] ) );
+ }
+ return retstr;
+ }
+
+ JNIEXPORT jboolean JNICALL nativeSyncBegin ( JNIEnv *env, jclass clazz,
+ jbyteArray dict_file ) {
+ jbyte *file_name = ( *env ).GetByteArrayElements ( dict_file, 0 );
+ jboolean jret = JNI_FALSE;
+ if ( true == sync_worker.begin ( ( const char * ) file_name ) )
+ { jret = JNI_TRUE; }
+ ( *env ).ReleaseByteArrayElements ( dict_file, file_name, 0 );
+ return jret;
+ }
+
+ JNIEXPORT jboolean JNICALL nativeSyncFinish ( JNIEnv *env, jclass clazz ) {
+ sync_worker.finish();
+ return JNI_TRUE;
+ }
+
+ JNIEXPORT jint JNICALL nativeSyncGetCapacity ( JNIEnv *env, jclass clazz ) {
+ return sync_worker.get_capacity();
+ }
+
+ JNIEXPORT jint JNICALL nativeSyncPutLemmas ( JNIEnv *env, jclass clazz,
+ jstring tomerge ) {
+ char16 *ptr = ( char16 * ) ( *env ).GetStringChars ( tomerge, NULL );
+ int len = ( size_t ) ( *env ).GetStringLength ( tomerge );
+ int added = sync_worker.put_lemmas ( ptr, len );
+ ( *env ).ReleaseStringChars ( tomerge, ptr );
+ return added;
+ }
+
+ JNIEXPORT jstring JNICALL nativeSyncGetLemmas ( JNIEnv *env, jclass clazz ) {
+ int len = sync_worker.get_lemmas ( retbuf, RET_BUF_LEN );
+ if ( len == 0 )
+ { return NULL; }
+ jstring retstr;
+ retstr = ( *env ).NewString ( ( unsigned short * ) retbuf, len );
+ return retstr;
+ }
+
+ JNIEXPORT jint JNICALL nativeSyncGetLastCount ( JNIEnv *env, jclass clazz ) {
+ return sync_worker.get_last_got_count();
+ }
+
+ JNIEXPORT jint JNICALL nativeSyncGetTotalCount ( JNIEnv *env, jclass clazz ) {
+ return sync_worker.get_total_count();
+ }
+
+ JNIEXPORT jboolean JNICALL nativeSyncClearLastGot ( JNIEnv *env, jclass clazz ) {
+ sync_worker.clear_last_got();
+ return JNI_TRUE;
+ }
+
+ /**
+ * Table of methods associated with a single class.
+ */
+ static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ /* ------Functions for Pinyin-to-hanzi decoding begin--------->> */
+ {
+ "nativeImOpenDecoder", "([B[B)Z",
+ ( void * ) nativeImOpenDecoder
+ },
+ {
+ "nativeImOpenDecoderFd", "(Ljava/io/FileDescriptor;JJ[B)Z",
+ ( void * ) nativeImOpenDecoderFd
+ },
+ {
+ "nativeImSetMaxLens", "(II)V",
+ ( void * ) nativeImSetMaxLens
+ },
+ {
+ "nativeImCloseDecoder", "()Z",
+ ( void * ) nativeImCloseDecoder
+ },
+ {
+ "nativeImSearch", "([BI)I",
+ ( void * ) nativeImSearch
+ },
+ {
+ "nativeImDelSearch", "(IZZ)I",
+ ( void * ) nativeImDelSearch
+ },
+ {
+ "nativeImResetSearch", "()V",
+ ( void * ) nativeImResetSearch
+ },
+ {
+ "nativeImAddLetter", "(B)I",
+ ( void * ) nativeImAddLetter
+ },
+ {
+ "nativeImGetPyStr", "(Z)Ljava/lang/String;",
+ ( void * ) nativeImGetPyStr
+ },
+ {
+ "nativeImGetPyStrLen", "(Z)I",
+ ( void * ) nativeImGetPyStrLen
+ },
+ {
+ "nativeImGetSplStart", "()[I",
+ ( void * ) nativeImGetSplStart
+ },
+ {
+ "nativeImGetChoice", "(I)Ljava/lang/String;",
+ ( void * ) nativeImGetChoice
+ },
+ {
+ "nativeImChoose", "(I)I",
+ ( void * ) nativeImChoose
+ },
+ {
+ "nativeImCancelLastChoice", "()I",
+ ( void * ) nativeImCancelLastChoice
+ },
+ {
+ "nativeImGetFixedLen", "()I",
+ ( void * ) nativeImGetFixedLen
+ },
+ {
+ "nativeImGetPredictsNum", "(Ljava/lang/String;)I",
+ ( void * ) nativeImGetPredictsNum
+ },
+ {
+ "nativeImGetPredictItem", "(I)Ljava/lang/String;",
+ ( void * ) nativeImGetPredictItem
+ },
+ {
+ "nativeImCancelInput", "()Z",
+ ( void * ) nativeImCancelInput
+ },
+ {
+ "nativeImFlushCache", "()Z",
+ ( void * ) nativeImFlushCache
+ },
+ /* <<----Functions for Pinyin-to-hanzi decoding end------------- */
+
+ /* ------Functions for sync begin----------------------------->> */
+ {
+ "nativeSyncBegin", "([B)Z",
+ ( void * ) nativeSyncBegin
+ },
+ {
+ "nativeSyncFinish", "()Z",
+ ( void * ) nativeSyncFinish
+ },
+ {
+ "nativeSyncPutLemmas", "(Ljava/lang/String;)I",
+ ( void * ) nativeSyncPutLemmas
+ },
+ {
+ "nativeSyncGetLemmas", "()Ljava/lang/String;",
+ ( void * ) nativeSyncGetLemmas
+ },
+ {
+ "nativeSyncGetLastCount", "()I",
+ ( void * ) nativeSyncGetLastCount
+ },
+ {
+ "nativeSyncGetTotalCount", "()I",
+ ( void * ) nativeSyncGetTotalCount
+ },
+ {
+ "nativeSyncClearLastGot", "()Z",
+ ( void * ) nativeSyncClearLastGot
+ },
+ {
+ "nativeSyncGetCapacity", "()I",
+ ( void * ) nativeSyncGetCapacity
+ },
+ /* <<----Functions for sync end--------------------------------- */
+ };
+
+
+ /*
+ * Register several native methods for one class.
+ */
+ static int registerNativeMethods ( JNIEnv *env, const char *className,
+ JNINativeMethod *gMethods, int numMethods ) {
+ jclass clazz;
+ clazz = ( *env ).FindClass ( className );
+ if ( clazz == NULL ) {
+ return JNI_FALSE;
+ }
+ if ( ( *env ).RegisterNatives ( clazz, gMethods, numMethods ) < 0 ) {
+ return JNI_FALSE;
+ }
+ clazz = env->FindClass ( "java/io/FileDescriptor" );
+ LOG_FATAL_IF ( clazz == NULL, "Unable to find Java class java.io.FileDescriptor" );
+ gFileDescriptorOffsets.mClass = ( jclass ) env->NewGlobalRef ( clazz );
+ gFileDescriptorOffsets.mDescriptor = env->GetFieldID ( clazz, "descriptor", "I" );
+ LOG_FATAL_IF ( gFileDescriptorOffsets.mDescriptor == NULL,
+ "Unable to find descriptor field in java.io.FileDescriptor" );
+ return JNI_TRUE;
+ }
+
+ /*
+ * Register native methods for all classes we know about.
+ */
+ static int registerNatives ( JNIEnv *env ) {
+ if ( !registerNativeMethods ( env,
+ "com/droidlogic/inputmethod/remote/PinyinDecoderService",
+ gMethods, sizeof ( gMethods ) / sizeof ( gMethods[0] ) ) )
+ { return JNI_FALSE; }
+ return JNI_TRUE;
+ }
+
+ /*
+ * Set some test stuff up.
+ *
+ * Returns the JNI version on success, -1 on failure.
+ */
+ JNIEXPORT jint JNICALL JNI_OnLoad ( JavaVM *vm, void *reserved ) {
+ JNIEnv *env = NULL;
+ jint result = -1;
+ if ( ( *vm ).GetEnv ( ( void ** ) &env, JNI_VERSION_1_4 ) != JNI_OK ) {
+ goto bail;
+ }
+ assert ( env != NULL );
+ if ( !registerNatives ( env ) ) {
+ goto bail;
+ }
+ /* success -- return valid version number */
+ result = JNI_VERSION_1_4;
+ bail:
+ return result;
+ }
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/jni/command/pinyinime_dictbuilder.cpp b/jni/command/pinyinime_dictbuilder.cpp
index b7f9606..40fd7d3 100755
--- a/jni/command/pinyinime_dictbuilder.cpp
+++ b/jni/command/pinyinime_dictbuilder.cpp
@@ -27,30 +27,26 @@ using namespace ime_pinyin;
* Build binary dictionary model. Make sure that ___BUILD_MODEL___ is defined
* in dictdef.h.
*/
-int main(int argc, char* argv[]) {
- DictTrie* dict_trie = new DictTrie();
- bool success;
- if (argc >= 3)
- success = dict_trie->build_dict(argv[1], argv[2]);
- else
- success = dict_trie->build_dict("../data/rawdict_utf16_65105_freq.txt",
- "../data/valid_utf16.txt");
-
- if (success) {
- printf("Build dictionary successfully.\n");
- } else {
- printf("Build dictionary unsuccessfully.\n");
- return -1;
- }
-
- success = dict_trie->save_dict("../../res/raw/dict_pinyin.dat");
-
- if (success) {
- printf("Save dictionary successfully.\n");
- } else {
- printf("Save dictionary unsuccessfully.\n");
- return -1;
- }
-
- return 0;
+int main ( int argc, char *argv[] ) {
+ DictTrie *dict_trie = new DictTrie();
+ bool success;
+ if ( argc >= 3 )
+ { success = dict_trie->build_dict ( argv[1], argv[2] ); }
+ else
+ success = dict_trie->build_dict ( "../data/rawdict_utf16_65105_freq.txt",
+ "../data/valid_utf16.txt" );
+ if ( success ) {
+ printf ( "Build dictionary successfully.\n" );
+ } else {
+ printf ( "Build dictionary unsuccessfully.\n" );
+ return -1;
+ }
+ success = dict_trie->save_dict ( "../../res/raw/dict_pinyin.dat" );
+ if ( success ) {
+ printf ( "Save dictionary successfully.\n" );
+ } else {
+ printf ( "Save dictionary unsuccessfully.\n" );
+ return -1;
+ }
+ return 0;
}
diff --git a/jni/include/atomdictbase.h b/jni/include/atomdictbase.h
index 0a70a51..27a39be 100755
--- a/jni/include/atomdictbase.h
+++ b/jni/include/atomdictbase.h
@@ -46,224 +46,224 @@
#include "./searchutility.h"
namespace ime_pinyin {
-class AtomDictBase {
- public:
- virtual ~AtomDictBase() {}
+ class AtomDictBase {
+ public:
+ virtual ~AtomDictBase() {}
- /**
- * Load an atom dictionary from a file.
- *
- * @param file_name The file name to load dictionary.
- * @param start_id The starting id used for this atom dictionary.
- * @param end_id The end id (included) which can be used for this atom
- * dictionary. User dictionary will always use the last id space, so it can
- * ignore this paramter. All other atom dictionaries should check this
- * parameter.
- * @return True if succeed.
- */
- virtual bool load_dict(const char *file_name, LemmaIdType start_id,
- LemmaIdType end_id) = 0;
+ /**
+ * Load an atom dictionary from a file.
+ *
+ * @param file_name The file name to load dictionary.
+ * @param start_id The starting id used for this atom dictionary.
+ * @param end_id The end id (included) which can be used for this atom
+ * dictionary. User dictionary will always use the last id space, so it can
+ * ignore this paramter. All other atom dictionaries should check this
+ * parameter.
+ * @return True if succeed.
+ */
+ virtual bool load_dict ( const char *file_name, LemmaIdType start_id,
+ LemmaIdType end_id ) = 0;
- /**
- * Close this atom dictionary.
- *
- * @return True if succeed.
- */
- virtual bool close_dict() = 0;
+ /**
+ * Close this atom dictionary.
+ *
+ * @return True if succeed.
+ */
+ virtual bool close_dict() = 0;
- /**
- * Get the total number of lemmas in this atom dictionary.
- *
- * @return The total number of lemmas.
- */
- virtual size_t number_of_lemmas() = 0;
+ /**
+ * Get the total number of lemmas in this atom dictionary.
+ *
+ * @return The total number of lemmas.
+ */
+ virtual size_t number_of_lemmas() = 0;
- /**
- * This function is called by the decoder when user deletes a character from
- * the input string, or begins a new input string.
- *
- * Different atom dictionaries may implement this function in different way.
- * an atom dictionary can use one of these two parameters (or both) to reset
- * its corresponding MileStoneHandle objects according its detailed
- * implementation.
- *
- * For example, if an atom dictionary uses step information to manage its
- * MileStoneHandle objects, parameter from_step can be used to identify which
- * objects should be reset; otherwise, if another atom dictionary does not
- * use the detailed step information, it only uses ascendant handles
- * (according to step. For the same step, earlier call, smaller handle), it
- * can easily reset those MileStoneHandle which are larger than from_handle.
- *
- * The decoder always reset the decoding state by step. So when it begins
- * resetting, it will call reset_milestones() of its atom dictionaries with
- * the step information, and the MileStoneHandle objects returned by the
- * earliest calling of extend_dict() for that step.
- *
- * If an atom dictionary does not implement incremental search, this function
- * can be totally ignored.
- *
- * @param from_step From which step(included) the MileStoneHandle
- * objects should be reset.
- * @param from_handle The ealiest MileStoneHandle object for step from_step
- */
- virtual void reset_milestones(uint16 from_step,
- MileStoneHandle from_handle) = 0;
+ /**
+ * This function is called by the decoder when user deletes a character from
+ * the input string, or begins a new input string.
+ *
+ * Different atom dictionaries may implement this function in different way.
+ * an atom dictionary can use one of these two parameters (or both) to reset
+ * its corresponding MileStoneHandle objects according its detailed
+ * implementation.
+ *
+ * For example, if an atom dictionary uses step information to manage its
+ * MileStoneHandle objects, parameter from_step can be used to identify which
+ * objects should be reset; otherwise, if another atom dictionary does not
+ * use the detailed step information, it only uses ascendant handles
+ * (according to step. For the same step, earlier call, smaller handle), it
+ * can easily reset those MileStoneHandle which are larger than from_handle.
+ *
+ * The decoder always reset the decoding state by step. So when it begins
+ * resetting, it will call reset_milestones() of its atom dictionaries with
+ * the step information, and the MileStoneHandle objects returned by the
+ * earliest calling of extend_dict() for that step.
+ *
+ * If an atom dictionary does not implement incremental search, this function
+ * can be totally ignored.
+ *
+ * @param from_step From which step(included) the MileStoneHandle
+ * objects should be reset.
+ * @param from_handle The ealiest MileStoneHandle object for step from_step
+ */
+ virtual void reset_milestones ( uint16 from_step,
+ MileStoneHandle from_handle ) = 0;
- /**
- * Used to extend in this dictionary. The handle returned should keep valid
- * until reset_milestones() is called.
- *
- * @param from_handle Its previous returned extended handle without the new
- * spelling id, it can be used to speed up the extending.
- * @param dep The paramter used for extending.
- * @param lpi_items Used to fill in the lemmas matched.
- * @param lpi_max The length of the buffer
- * @param lpi_num Used to return the newly added items.
- * @return The new mile stone for this extending. 0 if fail.
- */
- virtual MileStoneHandle extend_dict(MileStoneHandle from_handle,
- const DictExtPara *dep,
- LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num) = 0;
+ /**
+ * Used to extend in this dictionary. The handle returned should keep valid
+ * until reset_milestones() is called.
+ *
+ * @param from_handle Its previous returned extended handle without the new
+ * spelling id, it can be used to speed up the extending.
+ * @param dep The paramter used for extending.
+ * @param lpi_items Used to fill in the lemmas matched.
+ * @param lpi_max The length of the buffer
+ * @param lpi_num Used to return the newly added items.
+ * @return The new mile stone for this extending. 0 if fail.
+ */
+ virtual MileStoneHandle extend_dict ( MileStoneHandle from_handle,
+ const DictExtPara *dep,
+ LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num ) = 0;
- /**
- * Get lemma items with scores according to a spelling id stream.
- * This atom dictionary does not need to sort the returned items.
- *
- * @param splid_str The spelling id stream buffer.
- * @param splid_str_len The length of the spelling id stream buffer.
- * @param lpi_items Used to return matched lemma items with scores.
- * @param lpi_max The maximum size of the buffer to return result.
- * @return The number of matched items which have been filled in to lpi_items.
- */
- virtual size_t get_lpis(const uint16 *splid_str, uint16 splid_str_len,
- LmaPsbItem *lpi_items, size_t lpi_max) = 0;
+ /**
+ * Get lemma items with scores according to a spelling id stream.
+ * This atom dictionary does not need to sort the returned items.
+ *
+ * @param splid_str The spelling id stream buffer.
+ * @param splid_str_len The length of the spelling id stream buffer.
+ * @param lpi_items Used to return matched lemma items with scores.
+ * @param lpi_max The maximum size of the buffer to return result.
+ * @return The number of matched items which have been filled in to lpi_items.
+ */
+ virtual size_t get_lpis ( const uint16 *splid_str, uint16 splid_str_len,
+ LmaPsbItem *lpi_items, size_t lpi_max ) = 0;
- /**
- * Get a lemma string (The Chinese string) by the given lemma id.
- *
- * @param id_lemma The lemma id to get the string.
- * @param str_buf The buffer to return the Chinese string.
- * @param str_max The maximum size of the buffer.
- * @return The length of the string, 0 if fail.
- */
- virtual uint16 get_lemma_str(LemmaIdType id_lemma, char16 *str_buf,
- uint16 str_max) = 0;
+ /**
+ * Get a lemma string (The Chinese string) by the given lemma id.
+ *
+ * @param id_lemma The lemma id to get the string.
+ * @param str_buf The buffer to return the Chinese string.
+ * @param str_max The maximum size of the buffer.
+ * @return The length of the string, 0 if fail.
+ */
+ virtual uint16 get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf,
+ uint16 str_max ) = 0;
- /**
- * Get the full spelling ids for the given lemma id.
- * If the given buffer is too short, return 0.
- *
- * @param splids Used to return the spelling ids.
- * @param splids_max The maximum buffer length of splids.
- * @param arg_valid Used to indicate if the incoming parameters have been
- * initialized are valid. If it is true, the splids and splids_max are valid
- * and there may be half ids in splids to be updated to full ids. In this
- * case, splids_max is the number of valid ids in splids.
- * @return The number of ids in the buffer.
- */
- virtual uint16 get_lemma_splids(LemmaIdType id_lemma, uint16 *splids,
- uint16 splids_max, bool arg_valid) = 0;
+ /**
+ * Get the full spelling ids for the given lemma id.
+ * If the given buffer is too short, return 0.
+ *
+ * @param splids Used to return the spelling ids.
+ * @param splids_max The maximum buffer length of splids.
+ * @param arg_valid Used to indicate if the incoming parameters have been
+ * initialized are valid. If it is true, the splids and splids_max are valid
+ * and there may be half ids in splids to be updated to full ids. In this
+ * case, splids_max is the number of valid ids in splids.
+ * @return The number of ids in the buffer.
+ */
+ virtual uint16 get_lemma_splids ( LemmaIdType id_lemma, uint16 *splids,
+ uint16 splids_max, bool arg_valid ) = 0;
- /**
- * Function used for prediction.
- * No need to sort the newly added items.
- *
- * @param last_hzs The last n Chinese chracters(called Hanzi), its length
- * should be less than or equal to kMaxPredictSize.
- * @param hzs_len specifies the length(<= kMaxPredictSize) of the history.
- * @param npre_items Used used to return the result.
- * @param npre_max The length of the buffer to return result
- * @param b4_used Number of prediction result (from npre_items[-b4_used])
- * from other atom dictionaries. A atom ditionary can just ignore it.
- * @return The number of prediction result from this atom dictionary.
- */
- virtual size_t predict(const char16 last_hzs[], uint16 hzs_len,
- NPredictItem *npre_items, size_t npre_max,
- size_t b4_used) = 0;
+ /**
+ * Function used for prediction.
+ * No need to sort the newly added items.
+ *
+ * @param last_hzs The last n Chinese chracters(called Hanzi), its length
+ * should be less than or equal to kMaxPredictSize.
+ * @param hzs_len specifies the length(<= kMaxPredictSize) of the history.
+ * @param npre_items Used used to return the result.
+ * @param npre_max The length of the buffer to return result
+ * @param b4_used Number of prediction result (from npre_items[-b4_used])
+ * from other atom dictionaries. A atom ditionary can just ignore it.
+ * @return The number of prediction result from this atom dictionary.
+ */
+ virtual size_t predict ( const char16 last_hzs[], uint16 hzs_len,
+ NPredictItem *npre_items, size_t npre_max,
+ size_t b4_used ) = 0;
- /**
- * Add a lemma to the dictionary. If the dictionary allows to add new
- * items and this item does not exist, add it.
- *
- * @param lemma_str The Chinese string of the lemma.
- * @param splids The spelling ids of the lemma.
- * @param lemma_len The length of the Chinese lemma.
- * @param count The frequency count for this lemma.
- */
- virtual LemmaIdType put_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count) = 0;
+ /**
+ * Add a lemma to the dictionary. If the dictionary allows to add new
+ * items and this item does not exist, add it.
+ *
+ * @param lemma_str The Chinese string of the lemma.
+ * @param splids The spelling ids of the lemma.
+ * @param lemma_len The length of the Chinese lemma.
+ * @param count The frequency count for this lemma.
+ */
+ virtual LemmaIdType put_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count ) = 0;
- /**
- * Update a lemma's occuring count.
- *
- * @param lemma_id The lemma id to update.
- * @param delta_count The frequnecy count to ajust.
- * @param selected Indicate whether this lemma is selected by user and
- * submitted to target edit box.
- * @return The id if succeed, 0 if fail.
- */
- virtual LemmaIdType update_lemma(LemmaIdType lemma_id, int16 delta_count,
- bool selected) = 0;
+ /**
+ * Update a lemma's occuring count.
+ *
+ * @param lemma_id The lemma id to update.
+ * @param delta_count The frequnecy count to ajust.
+ * @param selected Indicate whether this lemma is selected by user and
+ * submitted to target edit box.
+ * @return The id if succeed, 0 if fail.
+ */
+ virtual LemmaIdType update_lemma ( LemmaIdType lemma_id, int16 delta_count,
+ bool selected ) = 0;
- /**
- * Get the lemma id for the given lemma.
- *
- * @param lemma_str The Chinese string of the lemma.
- * @param splids The spelling ids of the lemma.
- * @param lemma_len The length of the lemma.
- * @return The matched lemma id, or 0 if fail.
- */
- virtual LemmaIdType get_lemma_id(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len) = 0;
+ /**
+ * Get the lemma id for the given lemma.
+ *
+ * @param lemma_str The Chinese string of the lemma.
+ * @param splids The spelling ids of the lemma.
+ * @param lemma_len The length of the lemma.
+ * @return The matched lemma id, or 0 if fail.
+ */
+ virtual LemmaIdType get_lemma_id ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len ) = 0;
- /**
- * Get the lemma score.
- *
- * @param lemma_id The lemma id to get score.
- * @return The score of the lemma, or 0 if fail.
- */
- virtual LmaScoreType get_lemma_score(LemmaIdType lemma_id) = 0;
+ /**
+ * Get the lemma score.
+ *
+ * @param lemma_id The lemma id to get score.
+ * @return The score of the lemma, or 0 if fail.
+ */
+ virtual LmaScoreType get_lemma_score ( LemmaIdType lemma_id ) = 0;
- /**
- * Get the lemma score.
- *
- * @param lemma_str The Chinese string of the lemma.
- * @param splids The spelling ids of the lemma.
- * @param lemma_len The length of the lemma.
- * @return The score of the lamm, or 0 if fail.
- */
- virtual LmaScoreType get_lemma_score(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len) = 0;
+ /**
+ * Get the lemma score.
+ *
+ * @param lemma_str The Chinese string of the lemma.
+ * @param splids The spelling ids of the lemma.
+ * @param lemma_len The length of the lemma.
+ * @return The score of the lamm, or 0 if fail.
+ */
+ virtual LmaScoreType get_lemma_score ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len ) = 0;
- /**
- * If the dictionary allowed, remove a lemma from it.
- *
- * @param lemma_id The id of the lemma to remove.
- * @return True if succeed.
- */
- virtual bool remove_lemma(LemmaIdType lemma_id) = 0;
+ /**
+ * If the dictionary allowed, remove a lemma from it.
+ *
+ * @param lemma_id The id of the lemma to remove.
+ * @return True if succeed.
+ */
+ virtual bool remove_lemma ( LemmaIdType lemma_id ) = 0;
- /**
- * Get the total occuring count of this atom dictionary.
- *
- * @return The total occuring count of this atom dictionary.
- */
- virtual size_t get_total_lemma_count() = 0;
+ /**
+ * Get the total occuring count of this atom dictionary.
+ *
+ * @return The total occuring count of this atom dictionary.
+ */
+ virtual size_t get_total_lemma_count() = 0;
- /**
- * Set the total occuring count of other atom dictionaries.
- *
- * @param count The total occuring count of other atom dictionaies.
- */
- virtual void set_total_lemma_count_of_others(size_t count) = 0;
+ /**
+ * Set the total occuring count of other atom dictionaries.
+ *
+ * @param count The total occuring count of other atom dictionaies.
+ */
+ virtual void set_total_lemma_count_of_others ( size_t count ) = 0;
- /**
- * Notify this atom dictionary to flush the cached data to persistent storage
- * if necessary.
- */
- virtual void flush_cache() = 0;
-};
+ /**
+ * Notify this atom dictionary to flush the cached data to persistent storage
+ * if necessary.
+ */
+ virtual void flush_cache() = 0;
+ };
}
#endif // PINYINIME_INCLUDE_ATOMDICTBASE_H__
diff --git a/jni/include/dictbuilder.h b/jni/include/dictbuilder.h
index da0d6cd..aa7d4e4 100755
--- a/jni/include/dictbuilder.h
+++ b/jni/include/dictbuilder.h
@@ -31,140 +31,140 @@ namespace ime_pinyin {
#define ___DO_STATISTICS___
-class DictTrie;
+ class DictTrie;
-class DictBuilder {
- private:
- // The raw lemma array buffer.
- LemmaEntry *lemma_arr_;
- size_t lemma_num_;
+ class DictBuilder {
+ private:
+ // The raw lemma array buffer.
+ LemmaEntry *lemma_arr_;
+ size_t lemma_num_;
- // Used to store all possible single char items.
- // Two items may have the same Hanzi while their spelling ids are different.
- SingleCharItem *scis_;
- size_t scis_num_;
+ // Used to store all possible single char items.
+ // Two items may have the same Hanzi while their spelling ids are different.
+ SingleCharItem *scis_;
+ size_t scis_num_;
- // In the tree, root's level is -1.
- // Lemma nodes for root, and level 0
- LmaNodeLE0 *lma_nodes_le0_;
+ // In the tree, root's level is -1.
+ // Lemma nodes for root, and level 0
+ LmaNodeLE0 *lma_nodes_le0_;
- // Lemma nodes for layers whose levels are deeper than 0
- LmaNodeGE1 *lma_nodes_ge1_;
+ // Lemma nodes for layers whose levels are deeper than 0
+ LmaNodeGE1 *lma_nodes_ge1_;
- // Number of used lemma nodes
- size_t lma_nds_used_num_le0_;
- size_t lma_nds_used_num_ge1_;
+ // Number of used lemma nodes
+ size_t lma_nds_used_num_le0_;
+ size_t lma_nds_used_num_ge1_;
- // Used to store homophonies' ids.
- LemmaIdType *homo_idx_buf_;
- // Number of homophonies each of which only contains one Chinese character.
- size_t homo_idx_num_eq1_;
- // Number of homophonies each of which contains more than one character.
- size_t homo_idx_num_gt1_;
+ // Used to store homophonies' ids.
+ LemmaIdType *homo_idx_buf_;
+ // Number of homophonies each of which only contains one Chinese character.
+ size_t homo_idx_num_eq1_;
+ // Number of homophonies each of which contains more than one character.
+ size_t homo_idx_num_gt1_;
- // The items with highest scores.
- LemmaEntry *top_lmas_;
- size_t top_lmas_num_;
+ // The items with highest scores.
+ LemmaEntry *top_lmas_;
+ size_t top_lmas_num_;
- SpellingTable *spl_table_;
- SpellingParser *spl_parser_;
+ SpellingTable *spl_table_;
+ SpellingParser *spl_parser_;
#ifdef ___DO_STATISTICS___
- size_t max_sonbuf_len_[kMaxLemmaSize];
- size_t max_homobuf_len_[kMaxLemmaSize];
+ size_t max_sonbuf_len_[kMaxLemmaSize];
+ size_t max_homobuf_len_[kMaxLemmaSize];
- size_t total_son_num_[kMaxLemmaSize];
- size_t total_node_hasson_[kMaxLemmaSize];
- size_t total_sonbuf_num_[kMaxLemmaSize];
- size_t total_sonbuf_allnoson_[kMaxLemmaSize];
- size_t total_node_in_sonbuf_allnoson_[kMaxLemmaSize];
- size_t total_homo_num_[kMaxLemmaSize];
+ size_t total_son_num_[kMaxLemmaSize];
+ size_t total_node_hasson_[kMaxLemmaSize];
+ size_t total_sonbuf_num_[kMaxLemmaSize];
+ size_t total_sonbuf_allnoson_[kMaxLemmaSize];
+ size_t total_node_in_sonbuf_allnoson_[kMaxLemmaSize];
+ size_t total_homo_num_[kMaxLemmaSize];
- size_t sonbufs_num1_; // Number of son buffer with only 1 son
- size_t sonbufs_numgt1_; // Number of son buffer with more 1 son;
+ size_t sonbufs_num1_; // Number of son buffer with only 1 son
+ size_t sonbufs_numgt1_; // Number of son buffer with more 1 son;
- size_t total_lma_node_num_;
+ size_t total_lma_node_num_;
- void stat_init();
- void stat_print();
+ void stat_init();
+ void stat_print();
#endif
- public:
+ public:
- DictBuilder();
- ~DictBuilder();
+ DictBuilder();
+ ~DictBuilder();
- // Build dictionary trie from the file fn_raw. File fn_validhzs provides
- // valid chars. If fn_validhzs is NULL, only chars in GB2312 will be
- // included.
- bool build_dict(const char* fn_raw, const char* fn_validhzs,
- DictTrie *dict_trie);
+ // Build dictionary trie from the file fn_raw. File fn_validhzs provides
+ // valid chars. If fn_validhzs is NULL, only chars in GB2312 will be
+ // included.
+ bool build_dict ( const char *fn_raw, const char *fn_validhzs,
+ DictTrie *dict_trie );
- private:
- // Fill in the buffer with id. The caller guarantees that the paramters are
- // vaild.
- void id_to_charbuf(unsigned char *buf, LemmaIdType id);
+ private:
+ // Fill in the buffer with id. The caller guarantees that the paramters are
+ // vaild.
+ void id_to_charbuf ( unsigned char *buf, LemmaIdType id );
- // Update the offset of sons for a node.
- void set_son_offset(LmaNodeGE1 *node, size_t offset);
+ // Update the offset of sons for a node.
+ void set_son_offset ( LmaNodeGE1 *node, size_t offset );
- // Update the offset of homophonies' ids for a node.
- void set_homo_id_buf_offset(LmaNodeGE1 *node, size_t offset);
+ // Update the offset of homophonies' ids for a node.
+ void set_homo_id_buf_offset ( LmaNodeGE1 *node, size_t offset );
- // Format a speling string.
- void format_spelling_str(char *spl_str);
+ // Format a speling string.
+ void format_spelling_str ( char *spl_str );
- // Sort the lemma_arr by the hanzi string, and give each of unique items
- // a id. Why we need to sort the lemma list according to their Hanzi string
- // is to find items started by a given prefix string to do prediction.
- // Actually, the single char items are be in other order, for example,
- // in spelling id order, etc.
- // Return value is next un-allocated idx available.
- LemmaIdType sort_lemmas_by_hz();
+ // Sort the lemma_arr by the hanzi string, and give each of unique items
+ // a id. Why we need to sort the lemma list according to their Hanzi string
+ // is to find items started by a given prefix string to do prediction.
+ // Actually, the single char items are be in other order, for example,
+ // in spelling id order, etc.
+ // Return value is next un-allocated idx available.
+ LemmaIdType sort_lemmas_by_hz();
- // Build the SingleCharItem list, and fill the hanzi_scis_ids in the
- // lemma buffer lemma_arr_.
- // This function should be called after the lemma array is ready.
- // Return the number of unique SingleCharItem elements.
- size_t build_scis();
+ // Build the SingleCharItem list, and fill the hanzi_scis_ids in the
+ // lemma buffer lemma_arr_.
+ // This function should be called after the lemma array is ready.
+ // Return the number of unique SingleCharItem elements.
+ size_t build_scis();
- // Construct a subtree using a subset of the spelling array (from
- // item_star to item_end)
- // parent is the parent node to update the necessary information
- // parent can be a member of LmaNodeLE0 or LmaNodeGE1
- bool construct_subset(void* parent, LemmaEntry* lemma_arr,
- size_t item_start, size_t item_end, size_t level);
+ // Construct a subtree using a subset of the spelling array (from
+ // item_star to item_end)
+ // parent is the parent node to update the necessary information
+ // parent can be a member of LmaNodeLE0 or LmaNodeGE1
+ bool construct_subset ( void *parent, LemmaEntry *lemma_arr,
+ size_t item_start, size_t item_end, size_t level );
- // Read valid Chinese Hanzis from the given file.
- // num is used to return number of chars.
- // The return buffer is sorted and caller needs to free the returned buffer.
- char16* read_valid_hanzis(const char *fn_validhzs, size_t *num);
+ // Read valid Chinese Hanzis from the given file.
+ // num is used to return number of chars.
+ // The return buffer is sorted and caller needs to free the returned buffer.
+ char16 *read_valid_hanzis ( const char *fn_validhzs, size_t *num );
- // Read a raw dictionary. max_item is the maximum number of items. If there
- // are more items in the ditionary, only the first max_item will be read.
- // Returned value is the number of items successfully read from the file.
- size_t read_raw_dict(const char* fn_raw, const char *fn_validhzs,
- size_t max_item);
+ // Read a raw dictionary. max_item is the maximum number of items. If there
+ // are more items in the ditionary, only the first max_item will be read.
+ // Returned value is the number of items successfully read from the file.
+ size_t read_raw_dict ( const char *fn_raw, const char *fn_validhzs,
+ size_t max_item );
- // Try to find if a character is in hzs buffer.
- bool hz_in_hanzis_list(const char16 *hzs, size_t hzs_len, char16 hz);
+ // Try to find if a character is in hzs buffer.
+ bool hz_in_hanzis_list ( const char16 *hzs, size_t hzs_len, char16 hz );
- // Try to find if all characters in str are in hzs buffer.
- bool str_in_hanzis_list(const char16 *hzs, size_t hzs_len,
- const char16 *str, size_t str_len);
+ // Try to find if all characters in str are in hzs buffer.
+ bool str_in_hanzis_list ( const char16 *hzs, size_t hzs_len,
+ const char16 *str, size_t str_len );
- // Get these lemmas with toppest scores.
- void get_top_lemmas();
+ // Get these lemmas with toppest scores.
+ void get_top_lemmas();
- // Allocate resource to build dictionary.
- // lma_num is the number of items to be loaded
- bool alloc_resource(size_t lma_num);
+ // Allocate resource to build dictionary.
+ // lma_num is the number of items to be loaded
+ bool alloc_resource ( size_t lma_num );
- // Free resource.
- void free_resource();
-};
+ // Free resource.
+ void free_resource();
+ };
#endif // ___BUILD_MODEL___
}
diff --git a/jni/include/dictdef.h b/jni/include/dictdef.h
index 3e79d98..25b1e39 100755
--- a/jni/include/dictdef.h
+++ b/jni/include/dictdef.h
@@ -22,134 +22,134 @@
namespace ime_pinyin {
-// Enable the following line when building the binary dictionary model.
-// #define ___BUILD_MODEL___
-
-typedef unsigned char uint8;
-typedef unsigned short uint16;
-typedef unsigned int uint32;
-
-typedef signed char int8;
-typedef short int16;
-typedef int int32;
-typedef long long int64;
-typedef unsigned long long uint64;
-
-const bool kPrintDebug0 = false;
-const bool kPrintDebug1 = false;
-const bool kPrintDebug2 = false;
-
-// The max length of a lemma.
-const size_t kMaxLemmaSize = 8;
-
-// The max length of a Pinyin (spelling).
-const size_t kMaxPinyinSize = 6;
-
-// The number of half spelling ids. For Chinese Pinyin, there 30 half ids.
-// See SpellingTrie.h for details.
-const size_t kHalfSpellingIdNum = 29;
-
-// The maximum number of full spellings. For Chinese Pinyin, there are only
-// about 410 spellings.
-// If change this value is bigger(needs more bits), please also update
-// other structures like SpellingNode, to make sure than a spelling id can be
-// stored.
-// -1 is because that 0 is never used.
-const size_t kMaxSpellingNum = 512 - kHalfSpellingIdNum - 1;
-const size_t kMaxSearchSteps = 40;
-
-// One character predicts its following characters.
-const size_t kMaxPredictSize = (kMaxLemmaSize - 1);
-
-// LemmaIdType must always be size_t.
-typedef size_t LemmaIdType;
-const size_t kLemmaIdSize = 3; // Actually, a Id occupies 3 bytes in storage.
-const size_t kLemmaIdComposing = 0xffffff;
-
-typedef uint16 LmaScoreType;
-typedef uint16 KeyScoreType;
-
-// Number of items with highest score are kept for prediction purpose.
-const size_t kTopScoreLemmaNum = 10;
-
-const size_t kMaxPredictNumByGt3 = 1;
-const size_t kMaxPredictNumBy3 = 2;
-const size_t kMaxPredictNumBy2 = 2;
-
-// The last lemma id (included) for the system dictionary. The system
-// dictionary's ids always start from 1.
-const LemmaIdType kSysDictIdEnd = 500000;
-
-// The first lemma id for the user dictionary.
-const LemmaIdType kUserDictIdStart = 500001;
-
-// The last lemma id (included) for the user dictionary.
-const LemmaIdType kUserDictIdEnd = 600000;
-
-typedef struct {
- uint16 half_splid:5;
- uint16 full_splid:11;
-} SpellingId, *PSpellingId;
-
-
-/**
- * We use different node types for different layers
- * Statistical data of the building result for a testing dictionary:
- * root, level 0, level 1, level 2, level 3
- * max son num of one node: 406 280 41 2 -
- * max homo num of one node: 0 90 23 2 2
- * total node num of a layer: 1 406 31766 13516 993
- * total homo num of a layer: 9 5674 44609 12667 995
- *
- * The node number for root and level 0 won't be larger than 500
- * According to the information above, two kinds of nodes can be used; one for
- * root and level 0, the other for these layers deeper than 0.
- *
- * LE = less and equal,
- * A node occupies 16 bytes. so, totallly less than 16 * 500 = 8K
- */
-struct LmaNodeLE0 {
- size_t son_1st_off;
- size_t homo_idx_buf_off;
- uint16 spl_idx;
- uint16 num_of_son;
- uint16 num_of_homo;
-};
-
-/**
- * GE = great and equal
- * A node occupies 8 bytes.
- */
-struct LmaNodeGE1 {
- uint16 son_1st_off_l; // Low bits of the son_1st_off
- uint16 homo_idx_buf_off_l; // Low bits of the homo_idx_buf_off_1
- uint16 spl_idx;
- unsigned char num_of_son; // number of son nodes
- unsigned char num_of_homo; // number of homo words
- unsigned char son_1st_off_h; // high bits of the son_1st_off
- unsigned char homo_idx_buf_off_h; // high bits of the homo_idx_buf_off
-};
+ // Enable the following line when building the binary dictionary model.
+ // #define ___BUILD_MODEL___
+
+ typedef unsigned char uint8;
+ typedef unsigned short uint16;
+ typedef unsigned int uint32;
+
+ typedef signed char int8;
+ typedef short int16;
+ typedef int int32;
+ typedef long long int64;
+ typedef unsigned long long uint64;
+
+ const bool kPrintDebug0 = false;
+ const bool kPrintDebug1 = false;
+ const bool kPrintDebug2 = false;
+
+ // The max length of a lemma.
+ const size_t kMaxLemmaSize = 8;
+
+ // The max length of a Pinyin (spelling).
+ const size_t kMaxPinyinSize = 6;
+
+ // The number of half spelling ids. For Chinese Pinyin, there 30 half ids.
+ // See SpellingTrie.h for details.
+ const size_t kHalfSpellingIdNum = 29;
+
+ // The maximum number of full spellings. For Chinese Pinyin, there are only
+ // about 410 spellings.
+ // If change this value is bigger(needs more bits), please also update
+ // other structures like SpellingNode, to make sure than a spelling id can be
+ // stored.
+ // -1 is because that 0 is never used.
+ const size_t kMaxSpellingNum = 512 - kHalfSpellingIdNum - 1;
+ const size_t kMaxSearchSteps = 40;
+
+ // One character predicts its following characters.
+ const size_t kMaxPredictSize = ( kMaxLemmaSize - 1 );
+
+ // LemmaIdType must always be size_t.
+ typedef size_t LemmaIdType;
+ const size_t kLemmaIdSize = 3; // Actually, a Id occupies 3 bytes in storage.
+ const size_t kLemmaIdComposing = 0xffffff;
+
+ typedef uint16 LmaScoreType;
+ typedef uint16 KeyScoreType;
+
+ // Number of items with highest score are kept for prediction purpose.
+ const size_t kTopScoreLemmaNum = 10;
+
+ const size_t kMaxPredictNumByGt3 = 1;
+ const size_t kMaxPredictNumBy3 = 2;
+ const size_t kMaxPredictNumBy2 = 2;
+
+ // The last lemma id (included) for the system dictionary. The system
+ // dictionary's ids always start from 1.
+ const LemmaIdType kSysDictIdEnd = 500000;
+
+ // The first lemma id for the user dictionary.
+ const LemmaIdType kUserDictIdStart = 500001;
+
+ // The last lemma id (included) for the user dictionary.
+ const LemmaIdType kUserDictIdEnd = 600000;
+
+ typedef struct {
+ uint16 half_splid: 5;
+ uint16 full_splid: 11;
+ } SpellingId, *PSpellingId;
+
+
+ /**
+ * We use different node types for different layers
+ * Statistical data of the building result for a testing dictionary:
+ * root, level 0, level 1, level 2, level 3
+ * max son num of one node: 406 280 41 2 -
+ * max homo num of one node: 0 90 23 2 2
+ * total node num of a layer: 1 406 31766 13516 993
+ * total homo num of a layer: 9 5674 44609 12667 995
+ *
+ * The node number for root and level 0 won't be larger than 500
+ * According to the information above, two kinds of nodes can be used; one for
+ * root and level 0, the other for these layers deeper than 0.
+ *
+ * LE = less and equal,
+ * A node occupies 16 bytes. so, totallly less than 16 * 500 = 8K
+ */
+ struct LmaNodeLE0 {
+ size_t son_1st_off;
+ size_t homo_idx_buf_off;
+ uint16 spl_idx;
+ uint16 num_of_son;
+ uint16 num_of_homo;
+ };
+
+ /**
+ * GE = great and equal
+ * A node occupies 8 bytes.
+ */
+ struct LmaNodeGE1 {
+ uint16 son_1st_off_l; // Low bits of the son_1st_off
+ uint16 homo_idx_buf_off_l; // Low bits of the homo_idx_buf_off_1
+ uint16 spl_idx;
+ unsigned char num_of_son; // number of son nodes
+ unsigned char num_of_homo; // number of homo words
+ unsigned char son_1st_off_h; // high bits of the son_1st_off
+ unsigned char homo_idx_buf_off_h; // high bits of the homo_idx_buf_off
+ };
#ifdef ___BUILD_MODEL___
-struct SingleCharItem {
- float freq;
- char16 hz;
- SpellingId splid;
-};
-
-struct LemmaEntry {
- LemmaIdType idx_by_py;
- LemmaIdType idx_by_hz;
- char16 hanzi_str[kMaxLemmaSize + 1];
-
- // The SingleCharItem id for each Hanzi.
- uint16 hanzi_scis_ids[kMaxLemmaSize];
-
- uint16 spl_idx_arr[kMaxLemmaSize + 1];
- char pinyin_str[kMaxLemmaSize][kMaxPinyinSize + 1];
- unsigned char hz_str_len;
- float freq;
-};
+ struct SingleCharItem {
+ float freq;
+ char16 hz;
+ SpellingId splid;
+ };
+
+ struct LemmaEntry {
+ LemmaIdType idx_by_py;
+ LemmaIdType idx_by_hz;
+ char16 hanzi_str[kMaxLemmaSize + 1];
+
+ // The SingleCharItem id for each Hanzi.
+ uint16 hanzi_scis_ids[kMaxLemmaSize];
+
+ uint16 spl_idx_arr[kMaxLemmaSize + 1];
+ char pinyin_str[kMaxLemmaSize][kMaxPinyinSize + 1];
+ unsigned char hz_str_len;
+ float freq;
+ };
#endif // ___BUILD_MODEL___
} // namespace ime_pinyin
diff --git a/jni/include/dictlist.h b/jni/include/dictlist.h
index 5fcc12f..a2d78ac 100755
--- a/jni/include/dictlist.h
+++ b/jni/include/dictlist.h
@@ -26,95 +26,95 @@
namespace ime_pinyin {
-class DictList {
- private:
- bool initialized_;
+ class DictList {
+ private:
+ bool initialized_;
- const SpellingTrie *spl_trie_;
+ const SpellingTrie *spl_trie_;
- // Number of SingCharItem. The first is blank, because id 0 is invalid.
- size_t scis_num_;
- char16 *scis_hz_;
- SpellingId *scis_splid_;
+ // Number of SingCharItem. The first is blank, because id 0 is invalid.
+ size_t scis_num_;
+ char16 *scis_hz_;
+ SpellingId *scis_splid_;
- // The large memory block to store the word list.
- char16 *buf_;
+ // The large memory block to store the word list.
+ char16 *buf_;
- // Starting position of those words whose lengths are i+1, counted in
- // char16
- size_t start_pos_[kMaxLemmaSize + 1];
+ // Starting position of those words whose lengths are i+1, counted in
+ // char16
+ size_t start_pos_[kMaxLemmaSize + 1];
- size_t start_id_[kMaxLemmaSize + 1];
+ size_t start_id_[kMaxLemmaSize + 1];
- int (*cmp_func_[kMaxLemmaSize])(const void *, const void *);
+ int ( *cmp_func_[kMaxLemmaSize] ) ( const void *, const void * );
- bool alloc_resource(size_t buf_size, size_t scim_num);
+ bool alloc_resource ( size_t buf_size, size_t scim_num );
- void free_resource();
+ void free_resource();
#ifdef ___BUILD_MODEL___
- // Calculate the requsted memory, including the start_pos[] buffer.
- size_t calculate_size(const LemmaEntry *lemma_arr, size_t lemma_num);
+ // Calculate the requsted memory, including the start_pos[] buffer.
+ size_t calculate_size ( const LemmaEntry *lemma_arr, size_t lemma_num );
- void fill_scis(const SingleCharItem *scis, size_t scis_num);
+ void fill_scis ( const SingleCharItem *scis, size_t scis_num );
- // Copy the related content to the inner buffer
- // It should be called after calculate_size()
- void fill_list(const LemmaEntry *lemma_arr, size_t lemma_num);
+ // Copy the related content to the inner buffer
+ // It should be called after calculate_size()
+ void fill_list ( const LemmaEntry *lemma_arr, size_t lemma_num );
- // Find the starting position for the buffer of those 2-character Chinese word
- // whose first character is the given Chinese character.
- char16* find_pos2_startedbyhz(char16 hz_char);
+ // Find the starting position for the buffer of those 2-character Chinese word
+ // whose first character is the given Chinese character.
+ char16 *find_pos2_startedbyhz ( char16 hz_char );
#endif
- // Find the starting position for the buffer of those words whose lengths are
- // word_len. The given parameter cmp_func decides how many characters from
- // beginning will be used to compare.
- char16* find_pos_startedbyhzs(const char16 last_hzs[],
- size_t word_Len,
- int (*cmp_func)(const void *, const void *));
+ // Find the starting position for the buffer of those words whose lengths are
+ // word_len. The given parameter cmp_func decides how many characters from
+ // beginning will be used to compare.
+ char16 *find_pos_startedbyhzs ( const char16 last_hzs[],
+ size_t word_Len,
+ int ( *cmp_func ) ( const void *, const void * ) );
- public:
+ public:
- DictList();
- ~DictList();
+ DictList();
+ ~DictList();
- bool save_list(FILE *fp);
- bool load_list(FILE *fp);
+ bool save_list ( FILE *fp );
+ bool load_list ( FILE *fp );
#ifdef ___BUILD_MODEL___
- // Init the list from the LemmaEntry array.
- // lemma_arr should have been sorted by the hanzi_str, and have been given
- // ids from 1
- bool init_list(const SingleCharItem *scis, size_t scis_num,
- const LemmaEntry *lemma_arr, size_t lemma_num);
+ // Init the list from the LemmaEntry array.
+ // lemma_arr should have been sorted by the hanzi_str, and have been given
+ // ids from 1
+ bool init_list ( const SingleCharItem *scis, size_t scis_num,
+ const LemmaEntry *lemma_arr, size_t lemma_num );
#endif
- // Get the hanzi string for the given id
- uint16 get_lemma_str(LemmaIdType id_hz, char16 *str_buf, uint16 str_max);
+ // Get the hanzi string for the given id
+ uint16 get_lemma_str ( LemmaIdType id_hz, char16 *str_buf, uint16 str_max );
- void convert_to_hanzis(char16 *str, uint16 str_len);
+ void convert_to_hanzis ( char16 *str, uint16 str_len );
- void convert_to_scis_ids(char16 *str, uint16 str_len);
+ void convert_to_scis_ids ( char16 *str, uint16 str_len );
- // last_hzs stores the last n Chinese characters history, its length should be
- // less or equal than kMaxPredictSize.
- // hzs_len specifies the length(<= kMaxPredictSize).
- // predict_buf is used to store the result.
- // buf_len specifies the buffer length.
- // b4_used specifies how many items before predict_buf have been used.
- // Returned value is the number of newly added items.
- size_t predict(const char16 last_hzs[], uint16 hzs_len,
- NPredictItem *npre_items, size_t npre_max,
- size_t b4_used);
+ // last_hzs stores the last n Chinese characters history, its length should be
+ // less or equal than kMaxPredictSize.
+ // hzs_len specifies the length(<= kMaxPredictSize).
+ // predict_buf is used to store the result.
+ // buf_len specifies the buffer length.
+ // b4_used specifies how many items before predict_buf have been used.
+ // Returned value is the number of newly added items.
+ size_t predict ( const char16 last_hzs[], uint16 hzs_len,
+ NPredictItem *npre_items, size_t npre_max,
+ size_t b4_used );
- // If half_splid is a valid half spelling id, return those full spelling
- // ids which share this half id.
- uint16 get_splids_for_hanzi(char16 hanzi, uint16 half_splid,
- uint16 *splids, uint16 max_splids);
+ // If half_splid is a valid half spelling id, return those full spelling
+ // ids which share this half id.
+ uint16 get_splids_for_hanzi ( char16 hanzi, uint16 half_splid,
+ uint16 *splids, uint16 max_splids );
- LemmaIdType get_lemma_id(const char16 *str, uint16 str_len);
-};
+ LemmaIdType get_lemma_id ( const char16 *str, uint16 str_len );
+ };
}
#endif // PINYINIME_INCLUDE_DICTLIST_H__
diff --git a/jni/include/dicttrie.h b/jni/include/dicttrie.h
index 268624f..2886d22 100755
--- a/jni/include/dicttrie.h
+++ b/jni/include/dicttrie.h
@@ -25,209 +25,209 @@
namespace ime_pinyin {
-class DictTrie : AtomDictBase {
- private:
- typedef struct ParsingMark {
- size_t node_offset:24;
- size_t node_num:8; // Number of nodes with this spelling id given
- // by spl_id. If spl_id is a Shengmu, for nodes
- // in the first layer of DictTrie, it equals to
- // SpellingTrie::shm2full_num(); but for those
- // nodes which are not in the first layer,
- // node_num < SpellingTrie::shm2full_num().
- // For a full spelling id, node_num = 1;
- };
-
- // Used to indicate an extended mile stone.
- // An extended mile stone is used to mark a partial match in the dictionary
- // trie to speed up further potential extending.
- // For example, when the user inputs "w", a mile stone is created to mark the
- // partial match status, so that when user inputs another char 'm', it will be
- // faster to extend search space based on this mile stone.
- //
- // For partial match status of "wm", there can be more than one sub mile
- // stone, for example, "wm" can be matched to "wanm", "wom", ..., etc, so
- // there may be more one parsing mark used to mark these partial matchings.
- // A mile stone records the starting position in the mark list and number of
- // marks.
- struct MileStone {
- uint16 mark_start;
- uint16 mark_num;
- };
-
- DictList* dict_list_;
-
- const SpellingTrie *spl_trie_;
-
- LmaNodeLE0* root_; // Nodes for root and the first layer.
- LmaNodeGE1* nodes_ge1_; // Nodes for other layers.
-
- // An quick index from spelling id to the LmaNodeLE0 node buffer, or
- // to the root_ buffer.
- // Index length:
- // SpellingTrie::get_instance().get_spelling_num() + 1. The last one is used
- // to get the end.
- // All Shengmu ids are not indexed because they will be converted into
- // corresponding full ids.
- // So, given an id splid, the son is:
- // root_[splid_le0_index_[splid - kFullSplIdStart]]
- uint16 *splid_le0_index_;
-
- size_t lma_node_num_le0_;
- size_t lma_node_num_ge1_;
-
- // The first part is for homophnies, and the last top_lma_num_ items are
- // lemmas with highest scores.
- unsigned char *lma_idx_buf_;
- size_t lma_idx_buf_len_; // The total size of lma_idx_buf_ in byte.
- size_t total_lma_num_; // Total number of lemmas in this dictionary.
- size_t top_lmas_num_; // Number of lemma with highest scores.
-
- // Parsing mark list used to mark the detailed extended statuses.
- ParsingMark *parsing_marks_;
- // The position for next available mark.
- uint16 parsing_marks_pos_;
-
- // Mile stone list used to mark the extended status.
- MileStone *mile_stones_;
- // The position for the next available mile stone. We use positions (except 0)
- // as handles.
- MileStoneHandle mile_stones_pos_;
-
- // Get the offset of sons for a node.
- inline size_t get_son_offset(const LmaNodeGE1 *node);
-
- // Get the offset of homonious ids for a node.
- inline size_t get_homo_idx_buf_offset(const LmaNodeGE1 *node);
-
- // Get the lemma id by the offset.
- inline LemmaIdType get_lemma_id(size_t id_offset);
-
- void free_resource(bool free_dict_list);
-
- bool load_dict(FILE *fp);
-
- // Given a LmaNodeLE0 node, extract the lemmas specified by it, and fill
- // them into the lpi_items buffer.
- // This function is called by the search engine.
- size_t fill_lpi_buffer(LmaPsbItem lpi_items[], size_t max_size,
- LmaNodeLE0 *node);
-
- // Given a LmaNodeGE1 node, extract the lemmas specified by it, and fill
- // them into the lpi_items buffer.
- // This function is called by inner functions extend_dict0(), extend_dict1()
- // and extend_dict2().
- size_t fill_lpi_buffer(LmaPsbItem lpi_items[], size_t max_size,
- size_t homo_buf_off, LmaNodeGE1 *node,
- uint16 lma_len);
-
- // Extend in the trie from level 0.
- MileStoneHandle extend_dict0(MileStoneHandle from_handle,
- const DictExtPara *dep, LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num);
-
- // Extend in the trie from level 1.
- MileStoneHandle extend_dict1(MileStoneHandle from_handle,
- const DictExtPara *dep, LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num);
-
- // Extend in the trie from level 2.
- MileStoneHandle extend_dict2(MileStoneHandle from_handle,
- const DictExtPara *dep, LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num);
-
- // Try to extend the given spelling id buffer, and if the given id_lemma can
- // be successfully gotten, return true;
- // The given spelling ids are all valid full ids.
- bool try_extend(const uint16 *splids, uint16 splid_num, LemmaIdType id_lemma);
+ class DictTrie : AtomDictBase {
+ private:
+ typedef struct ParsingMark {
+ size_t node_offset: 24;
+ size_t node_num: 8; // Number of nodes with this spelling id given
+ // by spl_id. If spl_id is a Shengmu, for nodes
+ // in the first layer of DictTrie, it equals to
+ // SpellingTrie::shm2full_num(); but for those
+ // nodes which are not in the first layer,
+ // node_num < SpellingTrie::shm2full_num().
+ // For a full spelling id, node_num = 1;
+ };
+
+ // Used to indicate an extended mile stone.
+ // An extended mile stone is used to mark a partial match in the dictionary
+ // trie to speed up further potential extending.
+ // For example, when the user inputs "w", a mile stone is created to mark the
+ // partial match status, so that when user inputs another char 'm', it will be
+ // faster to extend search space based on this mile stone.
+ //
+ // For partial match status of "wm", there can be more than one sub mile
+ // stone, for example, "wm" can be matched to "wanm", "wom", ..., etc, so
+ // there may be more one parsing mark used to mark these partial matchings.
+ // A mile stone records the starting position in the mark list and number of
+ // marks.
+ struct MileStone {
+ uint16 mark_start;
+ uint16 mark_num;
+ };
+
+ DictList *dict_list_;
+
+ const SpellingTrie *spl_trie_;
+
+ LmaNodeLE0 *root_; // Nodes for root and the first layer.
+ LmaNodeGE1 *nodes_ge1_; // Nodes for other layers.
+
+ // An quick index from spelling id to the LmaNodeLE0 node buffer, or
+ // to the root_ buffer.
+ // Index length:
+ // SpellingTrie::get_instance().get_spelling_num() + 1. The last one is used
+ // to get the end.
+ // All Shengmu ids are not indexed because they will be converted into
+ // corresponding full ids.
+ // So, given an id splid, the son is:
+ // root_[splid_le0_index_[splid - kFullSplIdStart]]
+ uint16 *splid_le0_index_;
+
+ size_t lma_node_num_le0_;
+ size_t lma_node_num_ge1_;
+
+ // The first part is for homophnies, and the last top_lma_num_ items are
+ // lemmas with highest scores.
+ unsigned char *lma_idx_buf_;
+ size_t lma_idx_buf_len_; // The total size of lma_idx_buf_ in byte.
+ size_t total_lma_num_; // Total number of lemmas in this dictionary.
+ size_t top_lmas_num_; // Number of lemma with highest scores.
+
+ // Parsing mark list used to mark the detailed extended statuses.
+ ParsingMark *parsing_marks_;
+ // The position for next available mark.
+ uint16 parsing_marks_pos_;
+
+ // Mile stone list used to mark the extended status.
+ MileStone *mile_stones_;
+ // The position for the next available mile stone. We use positions (except 0)
+ // as handles.
+ MileStoneHandle mile_stones_pos_;
+
+ // Get the offset of sons for a node.
+ inline size_t get_son_offset ( const LmaNodeGE1 *node );
+
+ // Get the offset of homonious ids for a node.
+ inline size_t get_homo_idx_buf_offset ( const LmaNodeGE1 *node );
+
+ // Get the lemma id by the offset.
+ inline LemmaIdType get_lemma_id ( size_t id_offset );
+
+ void free_resource ( bool free_dict_list );
+
+ bool load_dict ( FILE *fp );
+
+ // Given a LmaNodeLE0 node, extract the lemmas specified by it, and fill
+ // them into the lpi_items buffer.
+ // This function is called by the search engine.
+ size_t fill_lpi_buffer ( LmaPsbItem lpi_items[], size_t max_size,
+ LmaNodeLE0 *node );
+
+ // Given a LmaNodeGE1 node, extract the lemmas specified by it, and fill
+ // them into the lpi_items buffer.
+ // This function is called by inner functions extend_dict0(), extend_dict1()
+ // and extend_dict2().
+ size_t fill_lpi_buffer ( LmaPsbItem lpi_items[], size_t max_size,
+ size_t homo_buf_off, LmaNodeGE1 *node,
+ uint16 lma_len );
+
+ // Extend in the trie from level 0.
+ MileStoneHandle extend_dict0 ( MileStoneHandle from_handle,
+ const DictExtPara *dep, LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num );
+
+ // Extend in the trie from level 1.
+ MileStoneHandle extend_dict1 ( MileStoneHandle from_handle,
+ const DictExtPara *dep, LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num );
+
+ // Extend in the trie from level 2.
+ MileStoneHandle extend_dict2 ( MileStoneHandle from_handle,
+ const DictExtPara *dep, LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num );
+
+ // Try to extend the given spelling id buffer, and if the given id_lemma can
+ // be successfully gotten, return true;
+ // The given spelling ids are all valid full ids.
+ bool try_extend ( const uint16 *splids, uint16 splid_num, LemmaIdType id_lemma );
#ifdef ___BUILD_MODEL___
- bool save_dict(FILE *fp);
+ bool save_dict ( FILE *fp );
#endif // ___BUILD_MODEL___
- static const int kMaxMileStone = 100;
- static const int kMaxParsingMark = 600;
- static const MileStoneHandle kFirstValidMileStoneHandle = 1;
+ static const int kMaxMileStone = 100;
+ static const int kMaxParsingMark = 600;
+ static const MileStoneHandle kFirstValidMileStoneHandle = 1;
- friend class DictParser;
- friend class DictBuilder;
+ friend class DictParser;
+ friend class DictBuilder;
- public:
+ public:
- DictTrie();
- ~DictTrie();
+ DictTrie();
+ ~DictTrie();
#ifdef ___BUILD_MODEL___
- // Construct the tree from the file fn_raw.
- // fn_validhzs provide the valid hanzi list. If fn_validhzs is
- // NULL, only chars in GB2312 will be included.
- bool build_dict(const char *fn_raw, const char *fn_validhzs);
-
- // Save the binary dictionary
- // Actually, the SpellingTrie/DictList instance will be also saved.
- bool save_dict(const char *filename);
+ // Construct the tree from the file fn_raw.
+ // fn_validhzs provide the valid hanzi list. If fn_validhzs is
+ // NULL, only chars in GB2312 will be included.
+ bool build_dict ( const char *fn_raw, const char *fn_validhzs );
+
+ // Save the binary dictionary
+ // Actually, the SpellingTrie/DictList instance will be also saved.
+ bool save_dict ( const char *filename );
#endif // ___BUILD_MODEL___
- void convert_to_hanzis(char16 *str, uint16 str_len);
+ void convert_to_hanzis ( char16 *str, uint16 str_len );
- void convert_to_scis_ids(char16 *str, uint16 str_len);
+ void convert_to_scis_ids ( char16 *str, uint16 str_len );
- // Load a binary dictionary
- // The SpellingTrie instance/DictList will be also loaded
- bool load_dict(const char *filename, LemmaIdType start_id,
- LemmaIdType end_id);
- bool load_dict_fd(int sys_fd, long start_offset, long length,
- LemmaIdType start_id, LemmaIdType end_id);
- bool close_dict() {return true;}
- size_t number_of_lemmas() {return 0;}
+ // Load a binary dictionary
+ // The SpellingTrie instance/DictList will be also loaded
+ bool load_dict ( const char *filename, LemmaIdType start_id,
+ LemmaIdType end_id );
+ bool load_dict_fd ( int sys_fd, long start_offset, long length,
+ LemmaIdType start_id, LemmaIdType end_id );
+ bool close_dict() {return true;}
+ size_t number_of_lemmas() {return 0;}
- void reset_milestones(uint16 from_step, MileStoneHandle from_handle);
+ void reset_milestones ( uint16 from_step, MileStoneHandle from_handle );
- MileStoneHandle extend_dict(MileStoneHandle from_handle,
- const DictExtPara *dep,
- LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num);
+ MileStoneHandle extend_dict ( MileStoneHandle from_handle,
+ const DictExtPara *dep,
+ LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num );
- size_t get_lpis(const uint16 *splid_str, uint16 splid_str_len,
- LmaPsbItem *lpi_items, size_t lpi_max);
+ size_t get_lpis ( const uint16 *splid_str, uint16 splid_str_len,
+ LmaPsbItem *lpi_items, size_t lpi_max );
- uint16 get_lemma_str(LemmaIdType id_lemma, char16 *str_buf, uint16 str_max);
+ uint16 get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf, uint16 str_max );
- uint16 get_lemma_splids(LemmaIdType id_lemma, uint16 *splids,
- uint16 splids_max, bool arg_valid);
+ uint16 get_lemma_splids ( LemmaIdType id_lemma, uint16 *splids,
+ uint16 splids_max, bool arg_valid );
- size_t predict(const char16 *last_hzs, uint16 hzs_len,
- NPredictItem *npre_items, size_t npre_max,
- size_t b4_used);
+ size_t predict ( const char16 *last_hzs, uint16 hzs_len,
+ NPredictItem *npre_items, size_t npre_max,
+ size_t b4_used );
- LemmaIdType put_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count) {return 0;}
+ LemmaIdType put_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count ) {return 0;}
- LemmaIdType update_lemma(LemmaIdType lemma_id, int16 delta_count,
- bool selected) {return 0;}
+ LemmaIdType update_lemma ( LemmaIdType lemma_id, int16 delta_count,
+ bool selected ) {return 0;}
- LemmaIdType get_lemma_id(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len) {return 0;}
+ LemmaIdType get_lemma_id ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len ) {return 0;}
- LmaScoreType get_lemma_score(LemmaIdType lemma_id) {return 0;}
+ LmaScoreType get_lemma_score ( LemmaIdType lemma_id ) {return 0;}
- LmaScoreType get_lemma_score(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len) {return 0;}
+ LmaScoreType get_lemma_score ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len ) {return 0;}
- bool remove_lemma(LemmaIdType lemma_id) {return false;}
+ bool remove_lemma ( LemmaIdType lemma_id ) {return false;}
- size_t get_total_lemma_count() {return 0;}
- void set_total_lemma_count_of_others(size_t count);
+ size_t get_total_lemma_count() {return 0;}
+ void set_total_lemma_count_of_others ( size_t count );
- void flush_cache() {}
+ void flush_cache() {}
- LemmaIdType get_lemma_id(const char16 lemma_str[], uint16 lemma_len);
+ LemmaIdType get_lemma_id ( const char16 lemma_str[], uint16 lemma_len );
- // Fill the lemmas with highest scores to the prediction buffer.
- // his_len is the history length to fill in the prediction buffer.
- size_t predict_top_lmas(size_t his_len, NPredictItem *npre_items,
- size_t npre_max, size_t b4_used);
-};
+ // Fill the lemmas with highest scores to the prediction buffer.
+ // his_len is the history length to fill in the prediction buffer.
+ size_t predict_top_lmas ( size_t his_len, NPredictItem *npre_items,
+ size_t npre_max, size_t b4_used );
+ };
}
#endif // PINYINIME_INCLUDE_DICTTRIE_H__
diff --git a/jni/include/lpicache.h b/jni/include/lpicache.h
index 6073597..6c90bf1 100755
--- a/jni/include/lpicache.h
+++ b/jni/include/lpicache.h
@@ -23,39 +23,39 @@
namespace ime_pinyin {
-// Used to cache LmaPsbItem list for half spelling ids.
-class LpiCache {
- private:
- static LpiCache *instance_;
- static const int kMaxLpiCachePerId = 15;
-
- LmaPsbItem *lpi_cache_;
- uint16 *lpi_cache_len_;
-
- public:
- LpiCache();
- ~LpiCache();
-
- static LpiCache& get_instance();
-
- // Test if the LPI list of the given splid has been cached.
- // If splid is a full spelling id, it returns false, because we only cache
- // list for half ids.
- bool is_cached(uint16 splid);
-
- // Put LPI list to cahce. If the length of the list, lpi_num, is longer than
- // the cache buffer. the list will be truncated, and function returns the
- // maximum length of the cache buffer.
- // Note: splid must be a half id, and lpi_items must be not NULL. The
- // caller of this function should guarantee this.
- size_t put_cache(uint16 splid, LmaPsbItem lpi_items[], size_t lpi_num);
-
- // Get the cached list for the given half id.
- // Return the length of the cached buffer.
- // Note: splid must be a half id, and lpi_items must be not NULL. The
- // caller of this function should guarantee this.
- size_t get_cache(uint16 splid, LmaPsbItem lpi_items[], size_t lpi_max);
-};
+ // Used to cache LmaPsbItem list for half spelling ids.
+ class LpiCache {
+ private:
+ static LpiCache *instance_;
+ static const int kMaxLpiCachePerId = 15;
+
+ LmaPsbItem *lpi_cache_;
+ uint16 *lpi_cache_len_;
+
+ public:
+ LpiCache();
+ ~LpiCache();
+
+ static LpiCache &get_instance();
+
+ // Test if the LPI list of the given splid has been cached.
+ // If splid is a full spelling id, it returns false, because we only cache
+ // list for half ids.
+ bool is_cached ( uint16 splid );
+
+ // Put LPI list to cahce. If the length of the list, lpi_num, is longer than
+ // the cache buffer. the list will be truncated, and function returns the
+ // maximum length of the cache buffer.
+ // Note: splid must be a half id, and lpi_items must be not NULL. The
+ // caller of this function should guarantee this.
+ size_t put_cache ( uint16 splid, LmaPsbItem lpi_items[], size_t lpi_num );
+
+ // Get the cached list for the given half id.
+ // Return the length of the cached buffer.
+ // Note: splid must be a half id, and lpi_items must be not NULL. The
+ // caller of this function should guarantee this.
+ size_t get_cache ( uint16 splid, LmaPsbItem lpi_items[], size_t lpi_max );
+ };
} // namespace
diff --git a/jni/include/matrixsearch.h b/jni/include/matrixsearch.h
index f581d30..4e882f8 100755
--- a/jni/include/matrixsearch.h
+++ b/jni/include/matrixsearch.h
@@ -26,431 +26,431 @@
namespace ime_pinyin {
-static const size_t kMaxRowNum = kMaxSearchSteps;
-
-typedef struct {
- // MileStoneHandle objects for the system and user dictionaries.
- MileStoneHandle dict_handles[2];
- // From which DMI node. -1 means it's from root.
- PoolPosType dmi_fr;
- // The spelling id for the Pinyin string from the previous DMI to this node.
- // If it is a half id like Shengmu, the node pointed by dict_node is the first
- // node with this Shengmu,
- uint16 spl_id;
- // What's the level of the dict node. Level of root is 0, but root is never
- // recorded by dict_node.
- unsigned char dict_level:7;
- // If this node is for composing phrase, this bit is 1.
- unsigned char c_phrase:1;
- // Whether the spl_id is parsed with a split character at the end.
- unsigned char splid_end_split:1;
- // What's the length of the spelling string for this match, for the whole
- // word.
- unsigned char splstr_len:7;
- // Used to indicate whether all spelling ids from the root are full spelling
- // ids. This information is useful for keymapping mode(not finished). Because
- // in this mode, there is no clear boundaries, we prefer those results which
- // have full spelling ids.
- unsigned char all_full_id:1;
-} DictMatchInfo, *PDictMatchInfo;
-
-typedef struct MatrixNode {
- LemmaIdType id;
- float score;
- MatrixNode *from;
- // From which DMI node. Used to trace the spelling segmentation.
- PoolPosType dmi_fr;
- uint16 step;
-} MatrixNode, *PMatrixNode;
-
-typedef struct {
- // The MatrixNode position in the matrix pool
- PoolPosType mtrx_nd_pos;
- // The DictMatchInfo position in the DictMatchInfo pool.
- PoolPosType dmi_pos;
- uint16 mtrx_nd_num;
- uint16 dmi_num:15;
- // Used to indicate whether there are dmi nodes in this step with full
- // spelling id. This information is used to decide whether a substring of a
- // valid Pinyin should be extended.
- //
- // Example1: shoudao
- // When the last char 'o' is added, the parser will find "dao" is a valid
- // Pinyin, and because all dmi nodes at location 'd' (including those for
- // "shoud", and those for "d") have Shengmu id only, so it is not necessary
- // to extend "ao", otherwise the result may be "shoud ao", that is not
- // reasonable.
- //
- // Example2: hengao
- // When the last 'o' is added, the parser finds "gao" is a valid Pinyin.
- // Because some dmi nodes at 'g' has Shengmu ids (hen'g and g), but some dmi
- // nodes at 'g' has full ids ('heng'), so it is necessary to extend "ao", thus
- // "heng ao" can also be the result.
- //
- // Similarly, "ganga" is expanded to "gang a".
- //
- // For Pinyin string "xian", because "xian" is a valid Pinyin, because all dmi
- // nodes at 'x' only have Shengmu ids, the parser will not try "x ian" (and it
- // is not valid either). If the parser uses break in the loop, the result
- // always be "xian"; but if the parser uses continue in the loop, "xi an" will
- // also be tried. This behaviour can be set via the function
- // set_xi_an_switch().
- uint16 dmi_has_full_id:1;
- // Points to a MatrixNode of the current step to indicate which choice the
- // user selects.
- MatrixNode *mtrx_nd_fixed;
-} MatrixRow, *PMatrixRow;
-
-// When user inputs and selects candidates, the fixed lemma ids are stored in
-// lma_id_ of class MatrixSearch, and fixed_lmas_ is used to indicate how many
-// lemmas from the beginning are fixed. If user deletes Pinyin characters one
-// by one from the end, these fixed lemmas can be unlocked one by one when
-// necessary. Whenever user deletes a Chinese character and its spelling string
-// in these fixed lemmas, all fixed lemmas will be merged together into a unit
-// named ComposingPhrase with a lemma id kLemmaIdComposing, and this composing
-// phrase will be the first lemma in the sentence. Because it contains some
-// modified lemmas (by deleting a character), these merged lemmas are called
-// sub lemmas (sublma), and each of them are represented individually, so that
-// when user deletes Pinyin characters from the end, these sub lemmas can also
-// be unlocked one by one.
-typedef struct {
- uint16 spl_ids[kMaxRowNum];
- uint16 spl_start[kMaxRowNum];
- char16 chn_str[kMaxRowNum]; // Chinese string.
- uint16 sublma_start[kMaxRowNum]; // Counted in Chinese characters.
- size_t sublma_num;
- uint16 length; // Counted in Chinese characters.
-} ComposingPhrase, *TComposingPhrase;
-
-class MatrixSearch {
- private:
- // If it is true, prediction list by string whose length is greater than 1
- // will be limited to a reasonable number.
- static const bool kPredictLimitGt1 = false;
-
- // If it is true, the engine will prefer long history based prediction,
- // for example, when user inputs "BeiJing", we prefer "DaXue", etc., which are
- // based on the two-character history.
- static const bool kPreferLongHistoryPredict = true;
-
- // If it is true, prediction will only be based on user dictionary. this flag
- // is for debug purpose.
- static const bool kOnlyUserDictPredict = false;
-
- // The maximum buffer to store LmaPsbItems.
- static const size_t kMaxLmaPsbItems = 1450;
-
- // How many rows for each step.
- static const size_t kMaxNodeARow = 5;
-
- // The maximum length of the sentence candidates counted in chinese
- // characters
- static const size_t kMaxSentenceLength = 16;
-
- // The size of the matrix node pool.
- static const size_t kMtrxNdPoolSize = 200;
-
- // The size of the DMI node pool.
- static const size_t kDmiPoolSize = 800;
-
- // Used to indicate whether this object has been initialized.
- bool inited_;
-
- // Spelling trie.
- const SpellingTrie *spl_trie_;
-
- // Used to indicate this switcher status: when "xian" is parseed, should
- // "xi an" also be extended. Default is false.
- // These cases include: xia, xian, xiang, zhuan, jiang..., etc. The string
- // should be valid for a FULL spelling, or a combination of two spellings,
- // first of which is a FULL id too. So even it is true, "da" will never be
- // split into "d a", because "d" is not a full spelling id.
- bool xi_an_enabled_;
-
- // System dictionary.
- DictTrie* dict_trie_;
-
- // User dictionary.
- AtomDictBase* user_dict_;
-
- // Spelling parser.
- SpellingParser* spl_parser_;
-
- // The maximum allowed length of spelling string (such as a Pinyin string).
- size_t max_sps_len_;
-
- // The maximum allowed length of a result Chinese string.
- size_t max_hzs_len_;
-
- // Pinyin string. Max length: kMaxRowNum - 1
- char pys_[kMaxRowNum];
-
- // The length of the string that has been decoded successfully.
- size_t pys_decoded_len_;
-
- // Shared buffer for multiple purposes.
- size_t *share_buf_;
-
- MatrixNode *mtrx_nd_pool_;
- PoolPosType mtrx_nd_pool_used_; // How many nodes used in the pool
- DictMatchInfo *dmi_pool_;
- PoolPosType dmi_pool_used_; // How many items used in the pool
-
- MatrixRow *matrix_; // The first row is for starting
-
- DictExtPara *dep_; // Parameter used to extend DMI nodes.
-
- NPredictItem *npre_items_; // Used to do prediction
- size_t npre_items_len_;
-
- // The starting positions and lemma ids for the full sentence candidate.
- size_t lma_id_num_;
- uint16 lma_start_[kMaxRowNum]; // Counted in spelling ids.
- LemmaIdType lma_id_[kMaxRowNum];
- size_t fixed_lmas_;
-
- // If fixed_lmas_ is bigger than i, Element i is used to indicate whether
- // the i'th lemma id in lma_id_ is the first candidate for that step.
- // If all candidates are the first one for that step, the whole string can be
- // decoded by the engine automatically, so no need to add it to user
- // dictionary. (We are considering to add it to user dictionary in the
- // future).
- uint8 fixed_lmas_no1_[kMaxRowNum];
-
- // Composing phrase
- ComposingPhrase c_phrase_;
-
- // If dmi_c_phrase_ is true, the decoder will try to match the
- // composing phrase (And definitely it will match successfully). If it
- // is false, the decoder will try to match lemmas items in dictionaries.
- bool dmi_c_phrase_;
-
- // The starting positions and spelling ids for the first full sentence
- // candidate.
- size_t spl_id_num_; // Number of splling ids
- uint16 spl_start_[kMaxRowNum]; // Starting positions
- uint16 spl_id_[kMaxRowNum]; // Spelling ids
- // Used to remember the last fixed position, counted in Hanzi.
- size_t fixed_hzs_;
-
- // Lemma Items with possibility score, two purposes:
- // 1. In Viterbi decoding, this buffer is used to get all possible candidates
- // for current step;
- // 2. When the search is done, this buffer is used to get candiates from the
- // first un-fixed step and show them to the user.
- LmaPsbItem lpi_items_[kMaxLmaPsbItems];
- size_t lpi_total_;
-
- // Assign the pointers with NULL. The caller makes sure that all pointers are
- // not valid before calling it. This function only will be called in the
- // construction function and free_resource().
- void reset_pointers_to_null();
-
- bool alloc_resource();
-
- void free_resource();
-
- // Reset the search space totally.
- bool reset_search0();
-
- // Reset the search space from ch_pos step. For example, if the original
- // input Pinyin is "an", reset_search(1) will reset the search space to the
- // result of "a". If the given position is out of range, return false.
- // if clear_fixed_this_step is true, and the ch_pos step is a fixed step,
- // clear its fixed status. if clear_dmi_his_step is true, clear the DMI nodes.
- // If clear_mtrx_this_sTep is true, clear the mtrx nodes of this step.
- // The DMI nodes will be kept.
- //
- // Note: this function should not destroy content of pys_.
- bool reset_search(size_t ch_pos, bool clear_fixed_this_step,
- bool clear_dmi_this_step, bool clear_mtrx_this_step);
-
- // Delete a part of the content in pys_.
- void del_in_pys(size_t start, size_t len);
-
- // Delete a spelling id and its corresponding Chinese character, and merge
- // the fixed lemmas into the composing phrase.
- // del_spl_pos indicates which spelling id needs to be delete.
- // This function will update the lemma and spelling segmentation information.
- // The caller guarantees that fixed_lmas_ > 0 and del_spl_pos is within
- // the fixed lemmas.
- void merge_fixed_lmas(size_t del_spl_pos);
-
- // Get spelling start posistions and ids. The result will be stored in
- // spl_id_num_, spl_start_[], spl_id_[].
- // fixed_hzs_ will be also assigned.
- void get_spl_start_id();
-
- // Get all lemma ids with match the given spelling id stream(shorter than the
- // maximum length of a word).
- // If pfullsent is not NULL, means the full sentence candidate may be the
- // same with the coming lemma string, if so, remove that lemma.
- // The result is sorted in descendant order by the frequency score.
- size_t get_lpis(const uint16* splid_str, size_t splid_str_len,
- LmaPsbItem* lma_buf, size_t max_lma_buf,
- const char16 *pfullsent, bool sort_by_psb);
-
- uint16 get_lemma_str(LemmaIdType id_lemma, char16 *str_buf, uint16 str_max);
-
- uint16 get_lemma_splids(LemmaIdType id_lemma, uint16 *splids,
- uint16 splids_max, bool arg_valid);
-
-
- // Extend a DMI node with a spelling id. ext_len is the length of the rows
- // to extend, actually, it is the size of the spelling string of splid.
- // return value can be 1 or 0.
- // 1 means a new DMI is filled in (dmi_pool_used_ is the next blank DMI in
- // the pool).
- // 0 means either the dmi node can not be extended with splid, or the splid
- // is a Shengmu id, which is only used to get lpi_items, or the result node
- // in DictTrie has no son, it is not nccessary to keep the new DMI.
- //
- // This function modifies the content of lpi_items_ and lpi_total_.
- // lpi_items_ is used to get the LmaPsbItem list, lpi_total_ returns the size.
- // The function's returned value has no relation with the value of lpi_num.
- //
- // If dmi == NULL, this function will extend the root node of DictTrie
- //
- // This function will not change dmi_nd_pool_used_. Please change it after
- // calling this function if necessary.
- //
- // The caller should guarantees that NULL != dep.
- size_t extend_dmi(DictExtPara *dep, DictMatchInfo *dmi_s);
-
- // Extend dmi for the composing phrase.
- size_t extend_dmi_c(DictExtPara *dep, DictMatchInfo *dmi_s);
-
- // Extend a MatrixNode with the give LmaPsbItem list.
- // res_row is the destination row number.
- // This function does not change mtrx_nd_pool_used_. Please change it after
- // calling this function if necessary.
- // return 0 always.
- size_t extend_mtrx_nd(MatrixNode *mtrx_nd, LmaPsbItem lpi_items[],
- size_t lpi_num, PoolPosType dmi_fr, size_t res_row);
-
-
- // Try to find a dmi node at step_to position, and the found dmi node should
- // match the given spelling id strings.
- PoolPosType match_dmi(size_t step_to, uint16 spl_ids[], uint16 spl_id_num);
-
- bool add_char(char ch);
- bool prepare_add_char(char ch);
-
- // Called after prepare_add_char, so the input char has been saved.
- bool add_char_qwerty();
-
- // Prepare candidates from the last fixed hanzi position.
- void prepare_candidates();
-
- // Is the character in step pos a splitter character?
- // The caller guarantees that the position is valid.
- bool is_split_at(uint16 pos);
-
- void fill_dmi(DictMatchInfo *dmi, MileStoneHandle *handles,
- PoolPosType dmi_fr,
- uint16 spl_id, uint16 node_num, unsigned char dict_level,
- bool splid_end_split, unsigned char splstr_len,
- unsigned char all_full_id);
-
- size_t inner_predict(const char16 fixed_scis_ids[], uint16 scis_num,
- char16 predict_buf[][kMaxPredictSize + 1],
- size_t buf_len);
-
- // Add the first candidate to the user dictionary.
- bool try_add_cand0_to_userdict();
-
- // Add a user lemma to the user dictionary. This lemma is a subset of
- // candidate 0. lma_from is from which lemma in lma_ids_, lma_num is the
- // number of lemmas to be combined together as a new lemma. The caller
- // gurantees that the combined new lemma's length is less or equal to
- // kMaxLemmaSize.
- bool add_lma_to_userdict(uint16 lma_from, uint16 lma_num, float score);
-
- // Update dictionary frequencies.
- void update_dict_freq();
-
- void debug_print_dmi(PoolPosType dmi_pos, uint16 nest_level);
-
- public:
- MatrixSearch();
- ~MatrixSearch();
-
- bool init(const char *fn_sys_dict, const char *fn_usr_dict);
-
- bool init_fd(int sys_fd, long start_offset, long length,
- const char *fn_usr_dict);
-
- void set_max_lens(size_t max_sps_len, size_t max_hzs_len);
-
- void close();
-
- void flush_cache();
-
- void set_xi_an_switch(bool xi_an_enabled);
-
- bool get_xi_an_switch();
-
- // Reset the search space. Equivalent to reset_search(0).
- // If inited, always return true;
- bool reset_search();
-
- // Search a Pinyin string.
- // Return value is the position successfully parsed.
- size_t search(const char *py, size_t py_len);
-
- // Used to delete something in the Pinyin string kept by the engine, and do
- // a re-search.
- // Return value is the new length of Pinyin string kept by the engine which
- // is parsed successfully.
- // If is_pos_in_splid is false, pos is used to indicate that pos-th Pinyin
- // character needs to be deleted. If is_pos_in_splid is true, all Pinyin
- // characters for pos-th spelling id needs to be deleted.
- // If the deleted character(s) is just after a fixed lemma or sub lemma in
- // composing phrase, clear_fixed_this_step indicates whether we needs to
- // unlock the last fixed lemma or sub lemma.
- // If is_pos_in_splid is false, and pos-th character is in the range for the
- // fixed lemmas or composing string, this function will do nothing and just
- // return the result of the previous search.
- size_t delsearch(size_t pos, bool is_pos_in_splid,
- bool clear_fixed_this_step);
-
- // Get the number of candiates, called after search().
- size_t get_candidate_num();
-
- // Get the Pinyin string stored by the engine.
- // *decoded_len returns the length of the successfully decoded string.
- const char* get_pystr(size_t *decoded_len);
-
- // Get the spelling boundaries for the first sentence candidate.
- // Number of spellings will be returned. The number of valid elements in
- // spl_start is one more than the return value because the last one is used
- // to indicate the beginning of the next un-input speling.
- // For a Pinyin "women", the returned value is 2, spl_start is [0, 2, 5] .
- size_t get_spl_start(const uint16 *&spl_start);
-
- // Get one candiate string. If full sentence candidate is available, it will
- // be the first one.
- char16* get_candidate(size_t cand_id, char16 *cand_str, size_t max_len);
-
- // Get the first candiate, which is a "full sentence".
- // retstr_len is not NULL, it will be used to return the string length.
- // If only_unfixed is true, only unfixed part will be fetched.
- char16* get_candidate0(char16* cand_str, size_t max_len,
- uint16 *retstr_len, bool only_unfixed);
-
- // Choose a candidate. The decoder will do a search after the fixed position.
- size_t choose(size_t cand_id);
-
- // Cancel the last choosing operation, and return the new number of choices.
- size_t cancel_last_choice();
-
- // Get the length of fixed Hanzis.
- size_t get_fixedlen();
-
- size_t get_predicts(const char16 fixed_buf[],
- char16 predict_buf[][kMaxPredictSize + 1],
- size_t buf_len);
-};
+ static const size_t kMaxRowNum = kMaxSearchSteps;
+
+ typedef struct {
+ // MileStoneHandle objects for the system and user dictionaries.
+ MileStoneHandle dict_handles[2];
+ // From which DMI node. -1 means it's from root.
+ PoolPosType dmi_fr;
+ // The spelling id for the Pinyin string from the previous DMI to this node.
+ // If it is a half id like Shengmu, the node pointed by dict_node is the first
+ // node with this Shengmu,
+ uint16 spl_id;
+ // What's the level of the dict node. Level of root is 0, but root is never
+ // recorded by dict_node.
+ unsigned char dict_level: 7;
+ // If this node is for composing phrase, this bit is 1.
+ unsigned char c_phrase: 1;
+ // Whether the spl_id is parsed with a split character at the end.
+ unsigned char splid_end_split: 1;
+ // What's the length of the spelling string for this match, for the whole
+ // word.
+ unsigned char splstr_len: 7;
+ // Used to indicate whether all spelling ids from the root are full spelling
+ // ids. This information is useful for keymapping mode(not finished). Because
+ // in this mode, there is no clear boundaries, we prefer those results which
+ // have full spelling ids.
+ unsigned char all_full_id: 1;
+ } DictMatchInfo, *PDictMatchInfo;
+
+ typedef struct MatrixNode {
+ LemmaIdType id;
+ float score;
+ MatrixNode *from;
+ // From which DMI node. Used to trace the spelling segmentation.
+ PoolPosType dmi_fr;
+ uint16 step;
+ } MatrixNode, *PMatrixNode;
+
+ typedef struct {
+ // The MatrixNode position in the matrix pool
+ PoolPosType mtrx_nd_pos;
+ // The DictMatchInfo position in the DictMatchInfo pool.
+ PoolPosType dmi_pos;
+ uint16 mtrx_nd_num;
+ uint16 dmi_num: 15;
+ // Used to indicate whether there are dmi nodes in this step with full
+ // spelling id. This information is used to decide whether a substring of a
+ // valid Pinyin should be extended.
+ //
+ // Example1: shoudao
+ // When the last char 'o' is added, the parser will find "dao" is a valid
+ // Pinyin, and because all dmi nodes at location 'd' (including those for
+ // "shoud", and those for "d") have Shengmu id only, so it is not necessary
+ // to extend "ao", otherwise the result may be "shoud ao", that is not
+ // reasonable.
+ //
+ // Example2: hengao
+ // When the last 'o' is added, the parser finds "gao" is a valid Pinyin.
+ // Because some dmi nodes at 'g' has Shengmu ids (hen'g and g), but some dmi
+ // nodes at 'g' has full ids ('heng'), so it is necessary to extend "ao", thus
+ // "heng ao" can also be the result.
+ //
+ // Similarly, "ganga" is expanded to "gang a".
+ //
+ // For Pinyin string "xian", because "xian" is a valid Pinyin, because all dmi
+ // nodes at 'x' only have Shengmu ids, the parser will not try "x ian" (and it
+ // is not valid either). If the parser uses break in the loop, the result
+ // always be "xian"; but if the parser uses continue in the loop, "xi an" will
+ // also be tried. This behaviour can be set via the function
+ // set_xi_an_switch().
+ uint16 dmi_has_full_id: 1;
+ // Points to a MatrixNode of the current step to indicate which choice the
+ // user selects.
+ MatrixNode *mtrx_nd_fixed;
+ } MatrixRow, *PMatrixRow;
+
+ // When user inputs and selects candidates, the fixed lemma ids are stored in
+ // lma_id_ of class MatrixSearch, and fixed_lmas_ is used to indicate how many
+ // lemmas from the beginning are fixed. If user deletes Pinyin characters one
+ // by one from the end, these fixed lemmas can be unlocked one by one when
+ // necessary. Whenever user deletes a Chinese character and its spelling string
+ // in these fixed lemmas, all fixed lemmas will be merged together into a unit
+ // named ComposingPhrase with a lemma id kLemmaIdComposing, and this composing
+ // phrase will be the first lemma in the sentence. Because it contains some
+ // modified lemmas (by deleting a character), these merged lemmas are called
+ // sub lemmas (sublma), and each of them are represented individually, so that
+ // when user deletes Pinyin characters from the end, these sub lemmas can also
+ // be unlocked one by one.
+ typedef struct {
+ uint16 spl_ids[kMaxRowNum];
+ uint16 spl_start[kMaxRowNum];
+ char16 chn_str[kMaxRowNum]; // Chinese string.
+ uint16 sublma_start[kMaxRowNum]; // Counted in Chinese characters.
+ size_t sublma_num;
+ uint16 length; // Counted in Chinese characters.
+ } ComposingPhrase, *TComposingPhrase;
+
+ class MatrixSearch {
+ private:
+ // If it is true, prediction list by string whose length is greater than 1
+ // will be limited to a reasonable number.
+ static const bool kPredictLimitGt1 = false;
+
+ // If it is true, the engine will prefer long history based prediction,
+ // for example, when user inputs "BeiJing", we prefer "DaXue", etc., which are
+ // based on the two-character history.
+ static const bool kPreferLongHistoryPredict = true;
+
+ // If it is true, prediction will only be based on user dictionary. this flag
+ // is for debug purpose.
+ static const bool kOnlyUserDictPredict = false;
+
+ // The maximum buffer to store LmaPsbItems.
+ static const size_t kMaxLmaPsbItems = 1450;
+
+ // How many rows for each step.
+ static const size_t kMaxNodeARow = 5;
+
+ // The maximum length of the sentence candidates counted in chinese
+ // characters
+ static const size_t kMaxSentenceLength = 16;
+
+ // The size of the matrix node pool.
+ static const size_t kMtrxNdPoolSize = 200;
+
+ // The size of the DMI node pool.
+ static const size_t kDmiPoolSize = 800;
+
+ // Used to indicate whether this object has been initialized.
+ bool inited_;
+
+ // Spelling trie.
+ const SpellingTrie *spl_trie_;
+
+ // Used to indicate this switcher status: when "xian" is parseed, should
+ // "xi an" also be extended. Default is false.
+ // These cases include: xia, xian, xiang, zhuan, jiang..., etc. The string
+ // should be valid for a FULL spelling, or a combination of two spellings,
+ // first of which is a FULL id too. So even it is true, "da" will never be
+ // split into "d a", because "d" is not a full spelling id.
+ bool xi_an_enabled_;
+
+ // System dictionary.
+ DictTrie *dict_trie_;
+
+ // User dictionary.
+ AtomDictBase *user_dict_;
+
+ // Spelling parser.
+ SpellingParser *spl_parser_;
+
+ // The maximum allowed length of spelling string (such as a Pinyin string).
+ size_t max_sps_len_;
+
+ // The maximum allowed length of a result Chinese string.
+ size_t max_hzs_len_;
+
+ // Pinyin string. Max length: kMaxRowNum - 1
+ char pys_[kMaxRowNum];
+
+ // The length of the string that has been decoded successfully.
+ size_t pys_decoded_len_;
+
+ // Shared buffer for multiple purposes.
+ size_t *share_buf_;
+
+ MatrixNode *mtrx_nd_pool_;
+ PoolPosType mtrx_nd_pool_used_; // How many nodes used in the pool
+ DictMatchInfo *dmi_pool_;
+ PoolPosType dmi_pool_used_; // How many items used in the pool
+
+ MatrixRow *matrix_; // The first row is for starting
+
+ DictExtPara *dep_; // Parameter used to extend DMI nodes.
+
+ NPredictItem *npre_items_; // Used to do prediction
+ size_t npre_items_len_;
+
+ // The starting positions and lemma ids for the full sentence candidate.
+ size_t lma_id_num_;
+ uint16 lma_start_[kMaxRowNum]; // Counted in spelling ids.
+ LemmaIdType lma_id_[kMaxRowNum];
+ size_t fixed_lmas_;
+
+ // If fixed_lmas_ is bigger than i, Element i is used to indicate whether
+ // the i'th lemma id in lma_id_ is the first candidate for that step.
+ // If all candidates are the first one for that step, the whole string can be
+ // decoded by the engine automatically, so no need to add it to user
+ // dictionary. (We are considering to add it to user dictionary in the
+ // future).
+ uint8 fixed_lmas_no1_[kMaxRowNum];
+
+ // Composing phrase
+ ComposingPhrase c_phrase_;
+
+ // If dmi_c_phrase_ is true, the decoder will try to match the
+ // composing phrase (And definitely it will match successfully). If it
+ // is false, the decoder will try to match lemmas items in dictionaries.
+ bool dmi_c_phrase_;
+
+ // The starting positions and spelling ids for the first full sentence
+ // candidate.
+ size_t spl_id_num_; // Number of splling ids
+ uint16 spl_start_[kMaxRowNum]; // Starting positions
+ uint16 spl_id_[kMaxRowNum]; // Spelling ids
+ // Used to remember the last fixed position, counted in Hanzi.
+ size_t fixed_hzs_;
+
+ // Lemma Items with possibility score, two purposes:
+ // 1. In Viterbi decoding, this buffer is used to get all possible candidates
+ // for current step;
+ // 2. When the search is done, this buffer is used to get candiates from the
+ // first un-fixed step and show them to the user.
+ LmaPsbItem lpi_items_[kMaxLmaPsbItems];
+ size_t lpi_total_;
+
+ // Assign the pointers with NULL. The caller makes sure that all pointers are
+ // not valid before calling it. This function only will be called in the
+ // construction function and free_resource().
+ void reset_pointers_to_null();
+
+ bool alloc_resource();
+
+ void free_resource();
+
+ // Reset the search space totally.
+ bool reset_search0();
+
+ // Reset the search space from ch_pos step. For example, if the original
+ // input Pinyin is "an", reset_search(1) will reset the search space to the
+ // result of "a". If the given position is out of range, return false.
+ // if clear_fixed_this_step is true, and the ch_pos step is a fixed step,
+ // clear its fixed status. if clear_dmi_his_step is true, clear the DMI nodes.
+ // If clear_mtrx_this_sTep is true, clear the mtrx nodes of this step.
+ // The DMI nodes will be kept.
+ //
+ // Note: this function should not destroy content of pys_.
+ bool reset_search ( size_t ch_pos, bool clear_fixed_this_step,
+ bool clear_dmi_this_step, bool clear_mtrx_this_step );
+
+ // Delete a part of the content in pys_.
+ void del_in_pys ( size_t start, size_t len );
+
+ // Delete a spelling id and its corresponding Chinese character, and merge
+ // the fixed lemmas into the composing phrase.
+ // del_spl_pos indicates which spelling id needs to be delete.
+ // This function will update the lemma and spelling segmentation information.
+ // The caller guarantees that fixed_lmas_ > 0 and del_spl_pos is within
+ // the fixed lemmas.
+ void merge_fixed_lmas ( size_t del_spl_pos );
+
+ // Get spelling start posistions and ids. The result will be stored in
+ // spl_id_num_, spl_start_[], spl_id_[].
+ // fixed_hzs_ will be also assigned.
+ void get_spl_start_id();
+
+ // Get all lemma ids with match the given spelling id stream(shorter than the
+ // maximum length of a word).
+ // If pfullsent is not NULL, means the full sentence candidate may be the
+ // same with the coming lemma string, if so, remove that lemma.
+ // The result is sorted in descendant order by the frequency score.
+ size_t get_lpis ( const uint16 *splid_str, size_t splid_str_len,
+ LmaPsbItem *lma_buf, size_t max_lma_buf,
+ const char16 *pfullsent, bool sort_by_psb );
+
+ uint16 get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf, uint16 str_max );
+
+ uint16 get_lemma_splids ( LemmaIdType id_lemma, uint16 *splids,
+ uint16 splids_max, bool arg_valid );
+
+
+ // Extend a DMI node with a spelling id. ext_len is the length of the rows
+ // to extend, actually, it is the size of the spelling string of splid.
+ // return value can be 1 or 0.
+ // 1 means a new DMI is filled in (dmi_pool_used_ is the next blank DMI in
+ // the pool).
+ // 0 means either the dmi node can not be extended with splid, or the splid
+ // is a Shengmu id, which is only used to get lpi_items, or the result node
+ // in DictTrie has no son, it is not nccessary to keep the new DMI.
+ //
+ // This function modifies the content of lpi_items_ and lpi_total_.
+ // lpi_items_ is used to get the LmaPsbItem list, lpi_total_ returns the size.
+ // The function's returned value has no relation with the value of lpi_num.
+ //
+ // If dmi == NULL, this function will extend the root node of DictTrie
+ //
+ // This function will not change dmi_nd_pool_used_. Please change it after
+ // calling this function if necessary.
+ //
+ // The caller should guarantees that NULL != dep.
+ size_t extend_dmi ( DictExtPara *dep, DictMatchInfo *dmi_s );
+
+ // Extend dmi for the composing phrase.
+ size_t extend_dmi_c ( DictExtPara *dep, DictMatchInfo *dmi_s );
+
+ // Extend a MatrixNode with the give LmaPsbItem list.
+ // res_row is the destination row number.
+ // This function does not change mtrx_nd_pool_used_. Please change it after
+ // calling this function if necessary.
+ // return 0 always.
+ size_t extend_mtrx_nd ( MatrixNode *mtrx_nd, LmaPsbItem lpi_items[],
+ size_t lpi_num, PoolPosType dmi_fr, size_t res_row );
+
+
+ // Try to find a dmi node at step_to position, and the found dmi node should
+ // match the given spelling id strings.
+ PoolPosType match_dmi ( size_t step_to, uint16 spl_ids[], uint16 spl_id_num );
+
+ bool add_char ( char ch );
+ bool prepare_add_char ( char ch );
+
+ // Called after prepare_add_char, so the input char has been saved.
+ bool add_char_qwerty();
+
+ // Prepare candidates from the last fixed hanzi position.
+ void prepare_candidates();
+
+ // Is the character in step pos a splitter character?
+ // The caller guarantees that the position is valid.
+ bool is_split_at ( uint16 pos );
+
+ void fill_dmi ( DictMatchInfo *dmi, MileStoneHandle *handles,
+ PoolPosType dmi_fr,
+ uint16 spl_id, uint16 node_num, unsigned char dict_level,
+ bool splid_end_split, unsigned char splstr_len,
+ unsigned char all_full_id );
+
+ size_t inner_predict ( const char16 fixed_scis_ids[], uint16 scis_num,
+ char16 predict_buf[][kMaxPredictSize + 1],
+ size_t buf_len );
+
+ // Add the first candidate to the user dictionary.
+ bool try_add_cand0_to_userdict();
+
+ // Add a user lemma to the user dictionary. This lemma is a subset of
+ // candidate 0. lma_from is from which lemma in lma_ids_, lma_num is the
+ // number of lemmas to be combined together as a new lemma. The caller
+ // gurantees that the combined new lemma's length is less or equal to
+ // kMaxLemmaSize.
+ bool add_lma_to_userdict ( uint16 lma_from, uint16 lma_num, float score );
+
+ // Update dictionary frequencies.
+ void update_dict_freq();
+
+ void debug_print_dmi ( PoolPosType dmi_pos, uint16 nest_level );
+
+ public:
+ MatrixSearch();
+ ~MatrixSearch();
+
+ bool init ( const char *fn_sys_dict, const char *fn_usr_dict );
+
+ bool init_fd ( int sys_fd, long start_offset, long length,
+ const char *fn_usr_dict );
+
+ void set_max_lens ( size_t max_sps_len, size_t max_hzs_len );
+
+ void close();
+
+ void flush_cache();
+
+ void set_xi_an_switch ( bool xi_an_enabled );
+
+ bool get_xi_an_switch();
+
+ // Reset the search space. Equivalent to reset_search(0).
+ // If inited, always return true;
+ bool reset_search();
+
+ // Search a Pinyin string.
+ // Return value is the position successfully parsed.
+ size_t search ( const char *py, size_t py_len );
+
+ // Used to delete something in the Pinyin string kept by the engine, and do
+ // a re-search.
+ // Return value is the new length of Pinyin string kept by the engine which
+ // is parsed successfully.
+ // If is_pos_in_splid is false, pos is used to indicate that pos-th Pinyin
+ // character needs to be deleted. If is_pos_in_splid is true, all Pinyin
+ // characters for pos-th spelling id needs to be deleted.
+ // If the deleted character(s) is just after a fixed lemma or sub lemma in
+ // composing phrase, clear_fixed_this_step indicates whether we needs to
+ // unlock the last fixed lemma or sub lemma.
+ // If is_pos_in_splid is false, and pos-th character is in the range for the
+ // fixed lemmas or composing string, this function will do nothing and just
+ // return the result of the previous search.
+ size_t delsearch ( size_t pos, bool is_pos_in_splid,
+ bool clear_fixed_this_step );
+
+ // Get the number of candiates, called after search().
+ size_t get_candidate_num();
+
+ // Get the Pinyin string stored by the engine.
+ // *decoded_len returns the length of the successfully decoded string.
+ const char *get_pystr ( size_t *decoded_len );
+
+ // Get the spelling boundaries for the first sentence candidate.
+ // Number of spellings will be returned. The number of valid elements in
+ // spl_start is one more than the return value because the last one is used
+ // to indicate the beginning of the next un-input speling.
+ // For a Pinyin "women", the returned value is 2, spl_start is [0, 2, 5] .
+ size_t get_spl_start ( const uint16 *&spl_start );
+
+ // Get one candiate string. If full sentence candidate is available, it will
+ // be the first one.
+ char16 *get_candidate ( size_t cand_id, char16 *cand_str, size_t max_len );
+
+ // Get the first candiate, which is a "full sentence".
+ // retstr_len is not NULL, it will be used to return the string length.
+ // If only_unfixed is true, only unfixed part will be fetched.
+ char16 *get_candidate0 ( char16 *cand_str, size_t max_len,
+ uint16 *retstr_len, bool only_unfixed );
+
+ // Choose a candidate. The decoder will do a search after the fixed position.
+ size_t choose ( size_t cand_id );
+
+ // Cancel the last choosing operation, and return the new number of choices.
+ size_t cancel_last_choice();
+
+ // Get the length of fixed Hanzis.
+ size_t get_fixedlen();
+
+ size_t get_predicts ( const char16 fixed_buf[],
+ char16 predict_buf[][kMaxPredictSize + 1],
+ size_t buf_len );
+ };
}
#endif // PINYINIME_ANDPY_INCLUDE_MATRIXSEARCH_H__
diff --git a/jni/include/mystdlib.h b/jni/include/mystdlib.h
index dfcf980..976d208 100755
--- a/jni/include/mystdlib.h
+++ b/jni/include/mystdlib.h
@@ -21,12 +21,12 @@
namespace ime_pinyin {
-void myqsort(void *p, size_t n, size_t es,
- int (*cmp)(const void *, const void *));
+ void myqsort ( void *p, size_t n, size_t es,
+ int ( *cmp ) ( const void *, const void * ) );
-void *mybsearch(const void *key, const void *base,
- size_t nmemb, size_t size,
- int (*compar)(const void *, const void *));
+ void *mybsearch ( const void *key, const void *base,
+ size_t nmemb, size_t size,
+ int ( *compar ) ( const void *, const void * ) );
}
#endif // PINYINIME_INCLUDE_MYSTDLIB_H__
diff --git a/jni/include/ngram.h b/jni/include/ngram.h
index ad6c304..a740b7e 100755
--- a/jni/include/ngram.h
+++ b/jni/include/ngram.h
@@ -23,74 +23,74 @@
namespace ime_pinyin {
-typedef unsigned char CODEBOOK_TYPE;
+ typedef unsigned char CODEBOOK_TYPE;
-static const size_t kCodeBookSize = 256;
+ static const size_t kCodeBookSize = 256;
-class NGram {
- public:
- // The maximum score of a lemma item.
- static const LmaScoreType kMaxScore = 0x3fff;
+ class NGram {
+ public:
+ // The maximum score of a lemma item.
+ static const LmaScoreType kMaxScore = 0x3fff;
- // In order to reduce the storage size, the original log value is amplified by
- // kScoreAmplifier, and we use LmaScoreType to store.
- // After this process, an item with a lower score has a higher frequency.
- static const int kLogValueAmplifier = -800;
+ // In order to reduce the storage size, the original log value is amplified by
+ // kScoreAmplifier, and we use LmaScoreType to store.
+ // After this process, an item with a lower score has a higher frequency.
+ static const int kLogValueAmplifier = -800;
- // System words' total frequency. It is not the real total frequency, instead,
- // It is only used to adjust system lemmas' scores when the user dictionary's
- // total frequency changes.
- // In this version, frequencies of system lemmas are fixed. We are considering
- // to make them changable in next version.
- static const size_t kSysDictTotalFreq = 100000000;
+ // System words' total frequency. It is not the real total frequency, instead,
+ // It is only used to adjust system lemmas' scores when the user dictionary's
+ // total frequency changes.
+ // In this version, frequencies of system lemmas are fixed. We are considering
+ // to make them changable in next version.
+ static const size_t kSysDictTotalFreq = 100000000;
- private:
+ private:
- static NGram* instance_;
+ static NGram *instance_;
- bool initialized_;
- size_t idx_num_;
+ bool initialized_;
+ size_t idx_num_;
- size_t total_freq_none_sys_;
+ size_t total_freq_none_sys_;
- // Score compensation for system dictionary lemmas.
- // Because after user adds some user lemmas, the total frequency changes, and
- // we use this value to normalize the score.
- float sys_score_compensation_;
+ // Score compensation for system dictionary lemmas.
+ // Because after user adds some user lemmas, the total frequency changes, and
+ // we use this value to normalize the score.
+ float sys_score_compensation_;
#ifdef ___BUILD_MODEL___
- double *freq_codes_df_;
+ double *freq_codes_df_;
#endif
- LmaScoreType *freq_codes_;
- CODEBOOK_TYPE *lma_freq_idx_;
+ LmaScoreType *freq_codes_;
+ CODEBOOK_TYPE *lma_freq_idx_;
- public:
- NGram();
- ~NGram();
+ public:
+ NGram();
+ ~NGram();
- static NGram& get_instance();
+ static NGram &get_instance();
- bool save_ngram(FILE *fp);
- bool load_ngram(FILE *fp);
+ bool save_ngram ( FILE *fp );
+ bool load_ngram ( FILE *fp );
- // Set the total frequency of all none system dictionaries.
- void set_total_freq_none_sys(size_t freq_none_sys);
+ // Set the total frequency of all none system dictionaries.
+ void set_total_freq_none_sys ( size_t freq_none_sys );
- float get_uni_psb(LemmaIdType lma_id);
+ float get_uni_psb ( LemmaIdType lma_id );
- // Convert a probability to score. Actually, the score will be limited to
- // kMaxScore, but at runtime, we also need float expression to get accurate
- // value of the score.
- // After the conversion, a lower score indicates a higher probability of the
- // item.
- static float convert_psb_to_score(double psb);
+ // Convert a probability to score. Actually, the score will be limited to
+ // kMaxScore, but at runtime, we also need float expression to get accurate
+ // value of the score.
+ // After the conversion, a lower score indicates a higher probability of the
+ // item.
+ static float convert_psb_to_score ( double psb );
#ifdef ___BUILD_MODEL___
- // For constructing the unigram mode model.
- bool build_unigram(LemmaEntry *lemma_arr, size_t num,
- LemmaIdType next_idx_unused);
+ // For constructing the unigram mode model.
+ bool build_unigram ( LemmaEntry *lemma_arr, size_t num,
+ LemmaIdType next_idx_unused );
#endif
-};
+ };
}
#endif // PINYINIME_INCLUDE_NGRAM_H__
diff --git a/jni/include/pinyinime.h b/jni/include/pinyinime.h
index 0744ec7..bc2844b 100755
--- a/jni/include/pinyinime.h
+++ b/jni/include/pinyinime.h
@@ -24,185 +24,185 @@
extern "C" {
#endif
- namespace ime_pinyin {
-
- /**
- * Open the decoder engine via the system and user dictionary file names.
- *
- * @param fn_sys_dict The file name of the system dictionary.
- * @param fn_usr_dict The file name of the user dictionary.
- * @return true if open the decoder engine successfully.
- */
- bool im_open_decoder(const char *fn_sys_dict, const char *fn_usr_dict);
-
- /**
- * Open the decoder engine via the system dictionary FD and user dictionary
- * file name. Because on Android, the system dictionary is embedded in the
- * whole application apk file.
- *
- * @param sys_fd The file in which the system dictionary is embedded.
- * @param start_offset The starting position of the system dictionary in the
- * file sys_fd.
- * @param length The length of the system dictionary in the file sys_fd,
- * counted in byte.
- * @return true if succeed.
- */
- bool im_open_decoder_fd(int sys_fd, long start_offset, long length,
- const char *fn_usr_dict);
-
- /**
- * Close the decoder engine.
- */
- void im_close_decoder();
-
- /**
- * Set maximum limitations for decoding. If this function is not called,
- * default values will be used. For example, due to screen size limitation,
- * the UI engine of the IME can only show a certain number of letters(input)
- * to decode, and a certain number of Chinese characters(output). If after
- * user adds a new letter, the input or the output string is longer than the
- * limitations, the engine will discard the recent letter.
- *
- * @param max_sps_len Maximum length of the spelling string(Pinyin string).
- * @max_hzs_len Maximum length of the decoded Chinese character string.
- */
- void im_set_max_lens(size_t max_sps_len, size_t max_hzs_len);
-
- /**
- * Flush cached data to persistent memory. Because at runtime, in order to
- * achieve best performance, some data is only store in memory.
- */
- void im_flush_cache();
-
- /**
- * Use a spelling string(Pinyin string) to search. The engine will try to do
- * an incremental search based on its previous search result, so if the new
- * string has the same prefix with the previous one stored in the decoder,
- * the decoder will only continue the search from the end of the prefix.
- * If the caller needs to do a brand new search, please call im_reset_search()
- * first. Calling im_search() is equivalent to calling im_add_letter() one by
- * one.
- *
- * @param sps_buf The spelling string buffer to decode.
- * @param sps_len The length of the spelling string buffer.
- * @return The number of candidates.
- */
- size_t im_search(const char* sps_buf, size_t sps_len);
-
- /**
- * Make a delete operation in the current search result, and make research if
- * necessary.
- *
- * @param pos The posistion of char in spelling string to delete, or the
- * position of spelling id in result string to delete.
- * @param is_pos_in_splid Indicate whether the pos parameter is the position
- * in the spelling string, or the position in the result spelling id string.
- * @return The number of candidates.
- */
- size_t im_delsearch(size_t pos, bool is_pos_in_splid,
- bool clear_fixed_this_step);
-
- /**
- * Reset the previous search result.
- */
- void im_reset_search();
-
- /**
- * Add a Pinyin letter to the current spelling string kept by decoder. If the
- * decoder fails in adding the letter, it will do nothing. im_get_sps_str()
- * can be used to get the spelling string kept by decoder currently.
- *
- * @param ch The letter to add.
- * @return The number of candidates.
- */
- size_t im_add_letter(char ch);
-
- /**
- * Get the spelling string kept by the decoder.
- *
- * @param decoded_len Used to return how many characters in the spelling
- * string is successfully parsed.
- * @return The spelling string kept by the decoder.
- */
- const char *im_get_sps_str(size_t *decoded_len);
-
- /**
- * Get a candidate(or choice) string.
- *
- * @param cand_id The id to get a candidate. Started from 0. Usually, id 0
- * is a sentence-level candidate.
- * @param cand_str The buffer to store the candidate.
- * @param max_len The maximum length of the buffer.
- * @return cand_str if succeeds, otherwise NULL.
- */
- char16* im_get_candidate(size_t cand_id, char16* cand_str,
- size_t max_len);
-
- /**
- * Get the segmentation information(the starting positions) of the spelling
- * string.
- *
- * @param spl_start Used to return the starting posistions.
- * @return The number of spelling ids. If it is L, there will be L+1 valid
- * elements in spl_start, and spl_start[L] is the posistion after the end of
- * the last spelling id.
- */
- size_t im_get_spl_start_pos(const uint16 *&spl_start);
-
- /**
- * Choose a candidate and make it fixed. If the candidate does not match
- * the end of all spelling ids, new candidates will be provided from the
- * first unfixed position. If the candidate matches the end of the all
- * spelling ids, there will be only one new candidates, or the whole fixed
- * sentence.
- *
- * @param cand_id The id of candidate to select and make it fixed.
- * @return The number of candidates. If after the selection, the whole result
- * string has been fixed, there will be only one candidate.
- */
- size_t im_choose(size_t cand_id);
-
- /**
- * Cancel the last selection, or revert the last operation of im_choose().
- *
- * @return The number of candidates.
- */
- size_t im_cancel_last_choice();
-
- /**
- * Get the number of fixed spelling ids, or Chinese characters.
- *
- * @return The number of fixed spelling ids, of Chinese characters.
- */
- size_t im_get_fixed_len();
-
- /**
- * Cancel the input state and reset the search workspace.
- */
- bool im_cancel_input();
-
- /**
- * Get prediction candiates based on the given fixed Chinese string as the
- * history.
- *
- * @param his_buf The history buffer to do the prediction. It should be ended
- * with '\0'.
- * @param pre_buf Used to return prediction result list.
- * @return The number of predicted result string.
- */
- size_t im_get_predicts(const char16 *his_buf,
- char16 (*&pre_buf)[kMaxPredictSize + 1]);
-
- /**
- * Enable Shengmus in ShouZiMu mode.
- */
- void im_enable_shm_as_szm(bool enable);
-
- /**
- * Enable Yunmus in ShouZiMu mode.
- */
- void im_enable_ym_as_szm(bool enable);
-}
+ namespace ime_pinyin {
+
+ /**
+ * Open the decoder engine via the system and user dictionary file names.
+ *
+ * @param fn_sys_dict The file name of the system dictionary.
+ * @param fn_usr_dict The file name of the user dictionary.
+ * @return true if open the decoder engine successfully.
+ */
+ bool im_open_decoder ( const char *fn_sys_dict, const char *fn_usr_dict );
+
+ /**
+ * Open the decoder engine via the system dictionary FD and user dictionary
+ * file name. Because on Android, the system dictionary is embedded in the
+ * whole application apk file.
+ *
+ * @param sys_fd The file in which the system dictionary is embedded.
+ * @param start_offset The starting position of the system dictionary in the
+ * file sys_fd.
+ * @param length The length of the system dictionary in the file sys_fd,
+ * counted in byte.
+ * @return true if succeed.
+ */
+ bool im_open_decoder_fd ( int sys_fd, long start_offset, long length,
+ const char *fn_usr_dict );
+
+ /**
+ * Close the decoder engine.
+ */
+ void im_close_decoder();
+
+ /**
+ * Set maximum limitations for decoding. If this function is not called,
+ * default values will be used. For example, due to screen size limitation,
+ * the UI engine of the IME can only show a certain number of letters(input)
+ * to decode, and a certain number of Chinese characters(output). If after
+ * user adds a new letter, the input or the output string is longer than the
+ * limitations, the engine will discard the recent letter.
+ *
+ * @param max_sps_len Maximum length of the spelling string(Pinyin string).
+ * @max_hzs_len Maximum length of the decoded Chinese character string.
+ */
+ void im_set_max_lens ( size_t max_sps_len, size_t max_hzs_len );
+
+ /**
+ * Flush cached data to persistent memory. Because at runtime, in order to
+ * achieve best performance, some data is only store in memory.
+ */
+ void im_flush_cache();
+
+ /**
+ * Use a spelling string(Pinyin string) to search. The engine will try to do
+ * an incremental search based on its previous search result, so if the new
+ * string has the same prefix with the previous one stored in the decoder,
+ * the decoder will only continue the search from the end of the prefix.
+ * If the caller needs to do a brand new search, please call im_reset_search()
+ * first. Calling im_search() is equivalent to calling im_add_letter() one by
+ * one.
+ *
+ * @param sps_buf The spelling string buffer to decode.
+ * @param sps_len The length of the spelling string buffer.
+ * @return The number of candidates.
+ */
+ size_t im_search ( const char *sps_buf, size_t sps_len );
+
+ /**
+ * Make a delete operation in the current search result, and make research if
+ * necessary.
+ *
+ * @param pos The posistion of char in spelling string to delete, or the
+ * position of spelling id in result string to delete.
+ * @param is_pos_in_splid Indicate whether the pos parameter is the position
+ * in the spelling string, or the position in the result spelling id string.
+ * @return The number of candidates.
+ */
+ size_t im_delsearch ( size_t pos, bool is_pos_in_splid,
+ bool clear_fixed_this_step );
+
+ /**
+ * Reset the previous search result.
+ */
+ void im_reset_search();
+
+ /**
+ * Add a Pinyin letter to the current spelling string kept by decoder. If the
+ * decoder fails in adding the letter, it will do nothing. im_get_sps_str()
+ * can be used to get the spelling string kept by decoder currently.
+ *
+ * @param ch The letter to add.
+ * @return The number of candidates.
+ */
+ size_t im_add_letter ( char ch );
+
+ /**
+ * Get the spelling string kept by the decoder.
+ *
+ * @param decoded_len Used to return how many characters in the spelling
+ * string is successfully parsed.
+ * @return The spelling string kept by the decoder.
+ */
+ const char *im_get_sps_str ( size_t *decoded_len );
+
+ /**
+ * Get a candidate(or choice) string.
+ *
+ * @param cand_id The id to get a candidate. Started from 0. Usually, id 0
+ * is a sentence-level candidate.
+ * @param cand_str The buffer to store the candidate.
+ * @param max_len The maximum length of the buffer.
+ * @return cand_str if succeeds, otherwise NULL.
+ */
+ char16 *im_get_candidate ( size_t cand_id, char16 *cand_str,
+ size_t max_len );
+
+ /**
+ * Get the segmentation information(the starting positions) of the spelling
+ * string.
+ *
+ * @param spl_start Used to return the starting posistions.
+ * @return The number of spelling ids. If it is L, there will be L+1 valid
+ * elements in spl_start, and spl_start[L] is the posistion after the end of
+ * the last spelling id.
+ */
+ size_t im_get_spl_start_pos ( const uint16 *&spl_start );
+
+ /**
+ * Choose a candidate and make it fixed. If the candidate does not match
+ * the end of all spelling ids, new candidates will be provided from the
+ * first unfixed position. If the candidate matches the end of the all
+ * spelling ids, there will be only one new candidates, or the whole fixed
+ * sentence.
+ *
+ * @param cand_id The id of candidate to select and make it fixed.
+ * @return The number of candidates. If after the selection, the whole result
+ * string has been fixed, there will be only one candidate.
+ */
+ size_t im_choose ( size_t cand_id );
+
+ /**
+ * Cancel the last selection, or revert the last operation of im_choose().
+ *
+ * @return The number of candidates.
+ */
+ size_t im_cancel_last_choice();
+
+ /**
+ * Get the number of fixed spelling ids, or Chinese characters.
+ *
+ * @return The number of fixed spelling ids, of Chinese characters.
+ */
+ size_t im_get_fixed_len();
+
+ /**
+ * Cancel the input state and reset the search workspace.
+ */
+ bool im_cancel_input();
+
+ /**
+ * Get prediction candiates based on the given fixed Chinese string as the
+ * history.
+ *
+ * @param his_buf The history buffer to do the prediction. It should be ended
+ * with '\0'.
+ * @param pre_buf Used to return prediction result list.
+ * @return The number of predicted result string.
+ */
+ size_t im_get_predicts ( const char16 *his_buf,
+ char16 ( *&pre_buf ) [kMaxPredictSize + 1] );
+
+ /**
+ * Enable Shengmus in ShouZiMu mode.
+ */
+ void im_enable_shm_as_szm ( bool enable );
+
+ /**
+ * Enable Yunmus in ShouZiMu mode.
+ */
+ void im_enable_ym_as_szm ( bool enable );
+ }
#ifdef __cplusplus
}
diff --git a/jni/include/searchutility.h b/jni/include/searchutility.h
index f135710..e33b2b0 100755
--- a/jni/include/searchutility.h
+++ b/jni/include/searchutility.h
@@ -22,120 +22,120 @@
namespace ime_pinyin {
-// Type used to identify the size of a pool, such as id pool, etc.
-typedef uint16 PoolPosType;
-
-// Type used to identify a parsing mile stone in an atom dictionary.
-typedef uint16 MileStoneHandle;
-
-// Type used to express a lemma and its probability score.
-typedef struct {
- size_t id:(kLemmaIdSize * 8);
- size_t lma_len:4;
- uint16 psb; // The score, the lower psb, the higher possibility.
- // For single character items, we may also need Hanzi.
- // For multiple characer items, ignore it.
- char16 hanzi;
-} LmaPsbItem, *PLmaPsbItem;
-
-// LmaPsbItem extended with string.
-typedef struct {
- LmaPsbItem lpi;
- char16 str[kMaxLemmaSize + 1];
-} LmaPsbStrItem, *PLmaPsbStrItem;
-
-
-typedef struct {
- float psb;
- char16 pre_hzs[kMaxPredictSize];
- uint16 his_len; // The length of the history used to do the prediction.
-} NPredictItem, *PNPredictItem;
-
-// Parameter structure used to extend in a dictionary. All dictionaries
-// receives the same DictExtPara and a dictionary specific MileStoneHandle for
-// extending.
-//
-// When the user inputs a new character, AtomDictBase::extend_dict() will be
-// called at least once for each dictionary.
-//
-// For example, when the user inputs "wm", extend_dict() will be called twice,
-// and the DictExtPara parameter are as follows respectively:
-// 1. splids = {w, m}; splids_extended = 1; ext_len = 1; step_no = 1;
-// splid_end_split = false; id_start = wa(the first id start with 'w');
-// id_num = number of ids starting with 'w'.
-// 2. splids = {m}; splids_extended = 0; ext_len = 1; step_no = 1;
-// splid_end_split = false; id_start = wa; id_num = number of ids starting with
-// 'w'.
-//
-// For string "women", one of the cases of the DictExtPara parameter is:
-// splids = {wo, men}, splids_extended = 1, ext_len = 3 (length of "men"),
-// step_no = 4; splid_end_split = false; id_start = men, id_num = 1.
-//
-typedef struct {
- // Spelling ids for extending, there are splids_extended + 1 ids in the
- // buffer.
- // For a normal lemma, there can only be kMaxLemmaSize spelling ids in max,
- // but for a composing phrase, there can kMaxSearchSteps spelling ids.
- uint16 splids[kMaxSearchSteps];
-
- // Number of ids that have been used before. splids[splids_extended] is the
- // newly added id for the current extension.
- uint16 splids_extended;
-
- // The step span of the extension. It is also the size of the string for
- // the newly added spelling id.
- uint16 ext_len;
-
- // The step number for the current extension. It is also the ending position
- // in the input Pinyin string for the substring of spelling ids in splids[].
- // For example, when the user inputs "women", step_no = 4.
- // This parameter may useful to manage the MileStoneHandle list for each
- // step. When the user deletes a character from the string, MileStoneHandle
- // objects for the the steps after that character should be reset; when the
- // user begins a new string, all MileStoneHandle objects should be reset.
- uint16 step_no;
-
- // Indicate whether the newly added spelling ends with a splitting character
- bool splid_end_split;
-
- // If the newly added id is a half id, id_start is the first id of the
- // corresponding full ids; if the newly added id is a full id, id_start is
- // that id.
- uint16 id_start;
-
- // If the newly added id is a half id, id_num is the number of corresponding
- // ids; if it is a full id, id_num == 1.
- uint16 id_num;
-}DictExtPara, *PDictExtPara;
-
-bool is_system_lemma(LemmaIdType lma_id);
-bool is_user_lemma(LemmaIdType lma_id);
-bool is_composing_lemma(LemmaIdType lma_id);
-
-int cmp_lpi_with_psb(const void *p1, const void *p2);
-int cmp_lpi_with_unified_psb(const void *p1, const void *p2);
-int cmp_lpi_with_id(const void *p1, const void *p2);
-int cmp_lpi_with_hanzi(const void *p1, const void *p2);
-
-int cmp_lpsi_with_str(const void *p1, const void *p2);
-
-int cmp_hanzis_1(const void *p1, const void *p2);
-int cmp_hanzis_2(const void *p1, const void *p2);
-int cmp_hanzis_3(const void *p1, const void *p2);
-int cmp_hanzis_4(const void *p1, const void *p2);
-int cmp_hanzis_5(const void *p1, const void *p2);
-int cmp_hanzis_6(const void *p1, const void *p2);
-int cmp_hanzis_7(const void *p1, const void *p2);
-int cmp_hanzis_8(const void *p1, const void *p2);
-
-int cmp_npre_by_score(const void *p1, const void *p2);
-int cmp_npre_by_hislen_score(const void *p1, const void *p2);
-int cmp_npre_by_hanzi_score(const void *p1, const void *p2);
-
-
-size_t remove_duplicate_npre(NPredictItem *npre_items, size_t npre_num);
-
-size_t align_to_size_t(size_t size);
+ // Type used to identify the size of a pool, such as id pool, etc.
+ typedef uint16 PoolPosType;
+
+ // Type used to identify a parsing mile stone in an atom dictionary.
+ typedef uint16 MileStoneHandle;
+
+ // Type used to express a lemma and its probability score.
+ typedef struct {
+ size_t id: ( kLemmaIdSize * 8 );
+ size_t lma_len: 4;
+ uint16 psb; // The score, the lower psb, the higher possibility.
+ // For single character items, we may also need Hanzi.
+ // For multiple characer items, ignore it.
+ char16 hanzi;
+ } LmaPsbItem, *PLmaPsbItem;
+
+ // LmaPsbItem extended with string.
+ typedef struct {
+ LmaPsbItem lpi;
+ char16 str[kMaxLemmaSize + 1];
+ } LmaPsbStrItem, *PLmaPsbStrItem;
+
+
+ typedef struct {
+ float psb;
+ char16 pre_hzs[kMaxPredictSize];
+ uint16 his_len; // The length of the history used to do the prediction.
+ } NPredictItem, *PNPredictItem;
+
+ // Parameter structure used to extend in a dictionary. All dictionaries
+ // receives the same DictExtPara and a dictionary specific MileStoneHandle for
+ // extending.
+ //
+ // When the user inputs a new character, AtomDictBase::extend_dict() will be
+ // called at least once for each dictionary.
+ //
+ // For example, when the user inputs "wm", extend_dict() will be called twice,
+ // and the DictExtPara parameter are as follows respectively:
+ // 1. splids = {w, m}; splids_extended = 1; ext_len = 1; step_no = 1;
+ // splid_end_split = false; id_start = wa(the first id start with 'w');
+ // id_num = number of ids starting with 'w'.
+ // 2. splids = {m}; splids_extended = 0; ext_len = 1; step_no = 1;
+ // splid_end_split = false; id_start = wa; id_num = number of ids starting with
+ // 'w'.
+ //
+ // For string "women", one of the cases of the DictExtPara parameter is:
+ // splids = {wo, men}, splids_extended = 1, ext_len = 3 (length of "men"),
+ // step_no = 4; splid_end_split = false; id_start = men, id_num = 1.
+ //
+ typedef struct {
+ // Spelling ids for extending, there are splids_extended + 1 ids in the
+ // buffer.
+ // For a normal lemma, there can only be kMaxLemmaSize spelling ids in max,
+ // but for a composing phrase, there can kMaxSearchSteps spelling ids.
+ uint16 splids[kMaxSearchSteps];
+
+ // Number of ids that have been used before. splids[splids_extended] is the
+ // newly added id for the current extension.
+ uint16 splids_extended;
+
+ // The step span of the extension. It is also the size of the string for
+ // the newly added spelling id.
+ uint16 ext_len;
+
+ // The step number for the current extension. It is also the ending position
+ // in the input Pinyin string for the substring of spelling ids in splids[].
+ // For example, when the user inputs "women", step_no = 4.
+ // This parameter may useful to manage the MileStoneHandle list for each
+ // step. When the user deletes a character from the string, MileStoneHandle
+ // objects for the the steps after that character should be reset; when the
+ // user begins a new string, all MileStoneHandle objects should be reset.
+ uint16 step_no;
+
+ // Indicate whether the newly added spelling ends with a splitting character
+ bool splid_end_split;
+
+ // If the newly added id is a half id, id_start is the first id of the
+ // corresponding full ids; if the newly added id is a full id, id_start is
+ // that id.
+ uint16 id_start;
+
+ // If the newly added id is a half id, id_num is the number of corresponding
+ // ids; if it is a full id, id_num == 1.
+ uint16 id_num;
+ } DictExtPara, *PDictExtPara;
+
+ bool is_system_lemma ( LemmaIdType lma_id );
+ bool is_user_lemma ( LemmaIdType lma_id );
+ bool is_composing_lemma ( LemmaIdType lma_id );
+
+ int cmp_lpi_with_psb ( const void *p1, const void *p2 );
+ int cmp_lpi_with_unified_psb ( const void *p1, const void *p2 );
+ int cmp_lpi_with_id ( const void *p1, const void *p2 );
+ int cmp_lpi_with_hanzi ( const void *p1, const void *p2 );
+
+ int cmp_lpsi_with_str ( const void *p1, const void *p2 );
+
+ int cmp_hanzis_1 ( const void *p1, const void *p2 );
+ int cmp_hanzis_2 ( const void *p1, const void *p2 );
+ int cmp_hanzis_3 ( const void *p1, const void *p2 );
+ int cmp_hanzis_4 ( const void *p1, const void *p2 );
+ int cmp_hanzis_5 ( const void *p1, const void *p2 );
+ int cmp_hanzis_6 ( const void *p1, const void *p2 );
+ int cmp_hanzis_7 ( const void *p1, const void *p2 );
+ int cmp_hanzis_8 ( const void *p1, const void *p2 );
+
+ int cmp_npre_by_score ( const void *p1, const void *p2 );
+ int cmp_npre_by_hislen_score ( const void *p1, const void *p2 );
+ int cmp_npre_by_hanzi_score ( const void *p1, const void *p2 );
+
+
+ size_t remove_duplicate_npre ( NPredictItem *npre_items, size_t npre_num );
+
+ size_t align_to_size_t ( size_t size );
} // namespace
diff --git a/jni/include/spellingtable.h b/jni/include/spellingtable.h
index fd79c6e..c8d8830 100755
--- a/jni/include/spellingtable.h
+++ b/jni/include/spellingtable.h
@@ -24,87 +24,87 @@ namespace ime_pinyin {
#ifdef ___BUILD_MODEL___
-const size_t kMaxSpellingSize = kMaxPinyinSize;
-
-typedef struct {
- char str[kMaxSpellingSize + 1];
- double freq;
-} RawSpelling, *PRawSpelling;
-
-// This class is used to store the spelling strings
-// The length of the input spelling string should be less or equal to the
-// spelling_size_ (set by init_table). If the input string is too long,
-// we only keep its first spelling_size_ chars.
-class SpellingTable {
- private:
- static const size_t kNotSupportNum = 3;
- static const char kNotSupportList[kNotSupportNum][kMaxSpellingSize + 1];
-
- bool need_score_;
-
- size_t spelling_max_num_;
-
- RawSpelling *raw_spellings_;
-
- // Used to store spelling strings. If the spelling table needs to calculate
- // score, an extra char after each spelling string is the score.
- // An item with a lower score has a higher probability.
- char *spelling_buf_;
- size_t spelling_size_;
-
- double total_freq_;
-
- size_t spelling_num_;
-
- double score_amplifier_;
-
- unsigned char average_score_;
-
- // If frozen is true, put_spelling() and contain() are not allowed to call.
- bool frozen_;
-
- size_t get_hash_pos(const char* spelling_str);
- size_t hash_pos_next(size_t hash_pos);
- void free_resource();
- public:
- SpellingTable();
- ~SpellingTable();
-
- // pure_spl_size is the pure maximum spelling string size. For example,
- // "zhuang" is the longgest item in Pinyin, so pure_spl_size should be 6.
- // spl_max_num is the maximum number of spelling strings to store.
- // need_score is used to indicate whether the caller needs to calculate a
- // score for each spelling.
- bool init_table(size_t pure_spl_size, size_t spl_max_num, bool need_score);
-
- // Put a spelling string to the table.
- // It always returns false if called after arrange() withtout a new
- // init_table() operation.
- // freq is the spelling's occuring count.
- // If the spelling has been in the table, occuring count will accumulated.
- bool put_spelling(const char* spelling_str, double spl_count);
-
- // Test whether a spelling string is in the table.
- // It always returns false, when being called after arrange() withtout a new
- // init_table() operation.
- bool contain(const char* spelling_str);
-
- // Sort the spelling strings and put them from the begin of the buffer.
- // Return the pointer of the sorted spelling strings.
- // item_size and spl_num return the item size and number of spelling.
- // Because each spelling uses a '\0' as terminator, the returned item_size is
- // at least one char longer than the spl_size parameter specified by
- // init_table(). If the table is initialized to calculate score, item_size
- // will be increased by 1, and current_spl_str[item_size - 1] stores an
- // unsinged char score.
- // An item with a lower score has a higher probability.
- // Do not call put_spelling() and contains() after arrange().
- const char* arrange(size_t *item_size, size_t *spl_num);
-
- float get_score_amplifier();
-
- unsigned char get_average_score();
-};
+ const size_t kMaxSpellingSize = kMaxPinyinSize;
+
+ typedef struct {
+ char str[kMaxSpellingSize + 1];
+ double freq;
+ } RawSpelling, *PRawSpelling;
+
+ // This class is used to store the spelling strings
+ // The length of the input spelling string should be less or equal to the
+ // spelling_size_ (set by init_table). If the input string is too long,
+ // we only keep its first spelling_size_ chars.
+ class SpellingTable {
+ private:
+ static const size_t kNotSupportNum = 3;
+ static const char kNotSupportList[kNotSupportNum][kMaxSpellingSize + 1];
+
+ bool need_score_;
+
+ size_t spelling_max_num_;
+
+ RawSpelling *raw_spellings_;
+
+ // Used to store spelling strings. If the spelling table needs to calculate
+ // score, an extra char after each spelling string is the score.
+ // An item with a lower score has a higher probability.
+ char *spelling_buf_;
+ size_t spelling_size_;
+
+ double total_freq_;
+
+ size_t spelling_num_;
+
+ double score_amplifier_;
+
+ unsigned char average_score_;
+
+ // If frozen is true, put_spelling() and contain() are not allowed to call.
+ bool frozen_;
+
+ size_t get_hash_pos ( const char *spelling_str );
+ size_t hash_pos_next ( size_t hash_pos );
+ void free_resource();
+ public:
+ SpellingTable();
+ ~SpellingTable();
+
+ // pure_spl_size is the pure maximum spelling string size. For example,
+ // "zhuang" is the longgest item in Pinyin, so pure_spl_size should be 6.
+ // spl_max_num is the maximum number of spelling strings to store.
+ // need_score is used to indicate whether the caller needs to calculate a
+ // score for each spelling.
+ bool init_table ( size_t pure_spl_size, size_t spl_max_num, bool need_score );
+
+ // Put a spelling string to the table.
+ // It always returns false if called after arrange() withtout a new
+ // init_table() operation.
+ // freq is the spelling's occuring count.
+ // If the spelling has been in the table, occuring count will accumulated.
+ bool put_spelling ( const char *spelling_str, double spl_count );
+
+ // Test whether a spelling string is in the table.
+ // It always returns false, when being called after arrange() withtout a new
+ // init_table() operation.
+ bool contain ( const char *spelling_str );
+
+ // Sort the spelling strings and put them from the begin of the buffer.
+ // Return the pointer of the sorted spelling strings.
+ // item_size and spl_num return the item size and number of spelling.
+ // Because each spelling uses a '\0' as terminator, the returned item_size is
+ // at least one char longer than the spl_size parameter specified by
+ // init_table(). If the table is initialized to calculate score, item_size
+ // will be increased by 1, and current_spl_str[item_size - 1] stores an
+ // unsinged char score.
+ // An item with a lower score has a higher probability.
+ // Do not call put_spelling() and contains() after arrange().
+ const char *arrange ( size_t *item_size, size_t *spl_num );
+
+ float get_score_amplifier();
+
+ unsigned char get_average_score();
+ };
#endif // ___BUILD_MODEL___
}
diff --git a/jni/include/spellingtrie.h b/jni/include/spellingtrie.h
index 4438757..249e3a5 100755
--- a/jni/include/spellingtrie.h
+++ b/jni/include/spellingtrie.h
@@ -23,236 +23,236 @@
namespace ime_pinyin {
-static const unsigned short kFullSplIdStart = kHalfSpellingIdNum + 1;
-
-// Node used for the trie of spellings
-struct SpellingNode {
- SpellingNode *first_son;
- // The spelling id for each node. If you need more bits to store
- // spelling id, please adjust this structure.
- uint16 spelling_idx:11;
- uint16 num_of_son:5;
- char char_this_node;
- unsigned char score;
-};
-
-class SpellingTrie {
- private:
- static const int kMaxYmNum = 64;
- static const size_t kValidSplCharNum = 26;
-
- static const uint16 kHalfIdShengmuMask = 0x01;
- static const uint16 kHalfIdYunmuMask = 0x02;
- static const uint16 kHalfIdSzmMask = 0x04;
-
- // Map from half spelling id to single char.
- // For half ids of Zh/Ch/Sh, map to z/c/s (low case) respectively.
- // For example, 1 to 'A', 2 to 'B', 3 to 'C', 4 to 'c', 5 to 'D', ...,
- // 28 to 'Z', 29 to 'z'.
- // [0] is not used to achieve better efficiency.
- static const char kHalfId2Sc_[kFullSplIdStart + 1];
-
- static unsigned char char_flags_[];
- static SpellingTrie* instance_;
-
- // The spelling table
- char *spelling_buf_;
-
- // The size of longest spelling string, includes '\0' and an extra char to
- // store score. For example, "zhuang" is the longgest item in Pinyin list,
- // so spelling_size_ is 8.
- // Structure: The string ended with '\0' + score char.
- // An item with a lower score has a higher probability.
- size_t spelling_size_;
-
- // Number of full spelling ids.
- size_t spelling_num_;
-
- float score_amplifier_;
- unsigned char average_score_;
-
- // The Yunmu id list for the spelling ids (for half ids of Shengmu,
- // the Yunmu id is 0).
- // The length of the list is spelling_num_ + kFullSplIdStart,
- // so that spl_ym_ids_[splid] is the Yunmu id of the splid.
- uint8 *spl_ym_ids_;
-
- // The Yunmu table.
- // Each Yunmu will be assigned with Yunmu id from 1.
- char *ym_buf_;
- size_t ym_size_; // The size of longest Yunmu string, '\0'included.
- size_t ym_num_;
-
- // The spelling string just queried
- char *splstr_queried_;
-
- // The spelling string just queried
- char16 *splstr16_queried_;
-
- // The root node of the spelling tree
- SpellingNode* root_;
-
- // If a none qwerty key such as a fnction key like ENTER is given, this node
- // will be used to indicate that this is not a QWERTY node.
- SpellingNode* dumb_node_;
-
- // If a splitter key is pressed, this node will be used to indicate that this
- // is a splitter key.
- SpellingNode* splitter_node_;
-
- // Used to get the first level sons.
- SpellingNode* level1_sons_[kValidSplCharNum];
-
- // The full spl_id range for specific half id.
- // h2f means half to full.
- // A half id can be a ShouZiMu id (id to represent the first char of a full
- // spelling, including Shengmu and Yunmu), or id of zh/ch/sh.
- // [1..kFullSplIdStart-1] is the arrange of half id.
- uint16 h2f_start_[kFullSplIdStart];
- uint16 h2f_num_[kFullSplIdStart];
-
- // Map from full id to half id.
- uint16 *f2h_;
+ static const unsigned short kFullSplIdStart = kHalfSpellingIdNum + 1;
+
+ // Node used for the trie of spellings
+ struct SpellingNode {
+ SpellingNode *first_son;
+ // The spelling id for each node. If you need more bits to store
+ // spelling id, please adjust this structure.
+ uint16 spelling_idx: 11;
+ uint16 num_of_son: 5;
+ char char_this_node;
+ unsigned char score;
+ };
+
+ class SpellingTrie {
+ private:
+ static const int kMaxYmNum = 64;
+ static const size_t kValidSplCharNum = 26;
+
+ static const uint16 kHalfIdShengmuMask = 0x01;
+ static const uint16 kHalfIdYunmuMask = 0x02;
+ static const uint16 kHalfIdSzmMask = 0x04;
+
+ // Map from half spelling id to single char.
+ // For half ids of Zh/Ch/Sh, map to z/c/s (low case) respectively.
+ // For example, 1 to 'A', 2 to 'B', 3 to 'C', 4 to 'c', 5 to 'D', ...,
+ // 28 to 'Z', 29 to 'z'.
+ // [0] is not used to achieve better efficiency.
+ static const char kHalfId2Sc_[kFullSplIdStart + 1];
+
+ static unsigned char char_flags_[];
+ static SpellingTrie *instance_;
+
+ // The spelling table
+ char *spelling_buf_;
+
+ // The size of longest spelling string, includes '\0' and an extra char to
+ // store score. For example, "zhuang" is the longgest item in Pinyin list,
+ // so spelling_size_ is 8.
+ // Structure: The string ended with '\0' + score char.
+ // An item with a lower score has a higher probability.
+ size_t spelling_size_;
+
+ // Number of full spelling ids.
+ size_t spelling_num_;
+
+ float score_amplifier_;
+ unsigned char average_score_;
+
+ // The Yunmu id list for the spelling ids (for half ids of Shengmu,
+ // the Yunmu id is 0).
+ // The length of the list is spelling_num_ + kFullSplIdStart,
+ // so that spl_ym_ids_[splid] is the Yunmu id of the splid.
+ uint8 *spl_ym_ids_;
+
+ // The Yunmu table.
+ // Each Yunmu will be assigned with Yunmu id from 1.
+ char *ym_buf_;
+ size_t ym_size_; // The size of longest Yunmu string, '\0'included.
+ size_t ym_num_;
+
+ // The spelling string just queried
+ char *splstr_queried_;
+
+ // The spelling string just queried
+ char16 *splstr16_queried_;
+
+ // The root node of the spelling tree
+ SpellingNode *root_;
+
+ // If a none qwerty key such as a fnction key like ENTER is given, this node
+ // will be used to indicate that this is not a QWERTY node.
+ SpellingNode *dumb_node_;
+
+ // If a splitter key is pressed, this node will be used to indicate that this
+ // is a splitter key.
+ SpellingNode *splitter_node_;
+
+ // Used to get the first level sons.
+ SpellingNode *level1_sons_[kValidSplCharNum];
+
+ // The full spl_id range for specific half id.
+ // h2f means half to full.
+ // A half id can be a ShouZiMu id (id to represent the first char of a full
+ // spelling, including Shengmu and Yunmu), or id of zh/ch/sh.
+ // [1..kFullSplIdStart-1] is the arrange of half id.
+ uint16 h2f_start_[kFullSplIdStart];
+ uint16 h2f_num_[kFullSplIdStart];
+
+ // Map from full id to half id.
+ uint16 *f2h_;
#ifdef ___BUILD_MODEL___
- // How many node used to build the trie.
- size_t node_num_;
+ // How many node used to build the trie.
+ size_t node_num_;
#endif
- SpellingTrie();
+ SpellingTrie();
- void free_son_trie(SpellingNode* node);
+ void free_son_trie ( SpellingNode *node );
- // Construct a subtree using a subset of the spelling array (from
- // item_star to item_end).
- // Member spelliing_buf_ and spelling_size_ should be valid.
- // parent is used to update its num_of_son and score.
- SpellingNode* construct_spellings_subset(size_t item_start, size_t item_end,
- size_t level, SpellingNode *parent);
- bool build_f2h();
+ // Construct a subtree using a subset of the spelling array (from
+ // item_star to item_end).
+ // Member spelliing_buf_ and spelling_size_ should be valid.
+ // parent is used to update its num_of_son and score.
+ SpellingNode *construct_spellings_subset ( size_t item_start, size_t item_end,
+ size_t level, SpellingNode *parent );
+ bool build_f2h();
- // The caller should guarantee ch >= 'A' && ch <= 'Z'
- bool is_shengmu_char(char ch) const;
+ // The caller should guarantee ch >= 'A' && ch <= 'Z'
+ bool is_shengmu_char ( char ch ) const;
- // The caller should guarantee ch >= 'A' && ch <= 'Z'
- bool is_yunmu_char(char ch) const;
+ // The caller should guarantee ch >= 'A' && ch <= 'Z'
+ bool is_yunmu_char ( char ch ) const;
#ifdef ___BUILD_MODEL___
- // Given a spelling string, return its Yunmu string.
- // The caller guaratees spl_str is valid.
- const char* get_ym_str(const char *spl_str);
+ // Given a spelling string, return its Yunmu string.
+ // The caller guaratees spl_str is valid.
+ const char *get_ym_str ( const char *spl_str );
- // Build the Yunmu list, and the mapping relation between the full ids and the
- // Yunmu ids. This functin is called after the spelling trie is built.
- bool build_ym_info();
+ // Build the Yunmu list, and the mapping relation between the full ids and the
+ // Yunmu ids. This functin is called after the spelling trie is built.
+ bool build_ym_info();
#endif
- friend class SpellingParser;
- friend class SmartSplParser;
- friend class SmartSplParser2;
+ friend class SpellingParser;
+ friend class SmartSplParser;
+ friend class SmartSplParser2;
- public:
- ~SpellingTrie();
+ public:
+ ~SpellingTrie();
- inline static bool is_valid_spl_char(char ch) {
- return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
- }
+ inline static bool is_valid_spl_char ( char ch ) {
+ return ( ch >= 'a' && ch <= 'z' ) || ( ch >= 'A' && ch <= 'Z' );
+ }
- // The caller guarantees that the two chars are valid spelling chars.
- inline static bool is_same_spl_char(char ch1, char ch2) {
- return ch1 == ch2 || ch1 - ch2 == 'a' - 'A' || ch2 - ch1 == 'a' - 'A';
- }
+ // The caller guarantees that the two chars are valid spelling chars.
+ inline static bool is_same_spl_char ( char ch1, char ch2 ) {
+ return ch1 == ch2 || ch1 - ch2 == 'a' - 'A' || ch2 - ch1 == 'a' - 'A';
+ }
- // Construct the tree from the input pinyin array
- // The given string list should have been sorted.
- // score_amplifier is used to convert a possibility value into score.
- // average_score is the average_score of all spellings. The dumb node is
- // assigned with this score.
- bool construct(const char* spelling_arr, size_t item_size, size_t item_num,
- float score_amplifier, unsigned char average_score);
+ // Construct the tree from the input pinyin array
+ // The given string list should have been sorted.
+ // score_amplifier is used to convert a possibility value into score.
+ // average_score is the average_score of all spellings. The dumb node is
+ // assigned with this score.
+ bool construct ( const char *spelling_arr, size_t item_size, size_t item_num,
+ float score_amplifier, unsigned char average_score );
- // Test if the given id is a valid spelling id.
- // If function returns true, the given splid may be updated like this:
- // When 'A' is not enabled in ShouZiMu mode, the parsing result for 'A' is
- // first given as a half id 1, but because 'A' is a one-char Yunmu and
- // it is a valid id, it needs to updated to its corresponding full id.
- bool if_valid_id_update(uint16 *splid) const;
+ // Test if the given id is a valid spelling id.
+ // If function returns true, the given splid may be updated like this:
+ // When 'A' is not enabled in ShouZiMu mode, the parsing result for 'A' is
+ // first given as a half id 1, but because 'A' is a one-char Yunmu and
+ // it is a valid id, it needs to updated to its corresponding full id.
+ bool if_valid_id_update ( uint16 *splid ) const;
- // Test if the given id is a half id.
- bool is_half_id(uint16 splid) const;
+ // Test if the given id is a half id.
+ bool is_half_id ( uint16 splid ) const;
- bool is_full_id(uint16 splid) const;
+ bool is_full_id ( uint16 splid ) const;
- // Test if the given id is a one-char Yunmu id (obviously, it is also a half
- // id), such as 'A', 'E' and 'O'.
- bool is_half_id_yunmu(uint16 splid) const;
+ // Test if the given id is a one-char Yunmu id (obviously, it is also a half
+ // id), such as 'A', 'E' and 'O'.
+ bool is_half_id_yunmu ( uint16 splid ) const;
- // Test if this char is a ShouZiMu char. This ShouZiMu char may be not enabled.
- // For Pinyin, only i/u/v is not a ShouZiMu char.
- // The caller should guarantee that ch >= 'A' && ch <= 'Z'
- bool is_szm_char(char ch) const;
+ // Test if this char is a ShouZiMu char. This ShouZiMu char may be not enabled.
+ // For Pinyin, only i/u/v is not a ShouZiMu char.
+ // The caller should guarantee that ch >= 'A' && ch <= 'Z'
+ bool is_szm_char ( char ch ) const;
- // Test If this char is enabled in ShouZiMu mode.
- // The caller should guarantee that ch >= 'A' && ch <= 'Z'
- bool szm_is_enabled(char ch) const;
+ // Test If this char is enabled in ShouZiMu mode.
+ // The caller should guarantee that ch >= 'A' && ch <= 'Z'
+ bool szm_is_enabled ( char ch ) const;
- // Enable/disable Shengmus in ShouZiMu mode(using the first char of a spelling
- // to input).
- void szm_enable_shm(bool enable);
+ // Enable/disable Shengmus in ShouZiMu mode(using the first char of a spelling
+ // to input).
+ void szm_enable_shm ( bool enable );
- // Enable/disable Yunmus in ShouZiMu mode.
- void szm_enable_ym(bool enable);
+ // Enable/disable Yunmus in ShouZiMu mode.
+ void szm_enable_ym ( bool enable );
- // Test if this char is enabled in ShouZiMu mode.
- // The caller should guarantee ch >= 'A' && ch <= 'Z'
- bool is_szm_enabled(char ch) const;
+ // Test if this char is enabled in ShouZiMu mode.
+ // The caller should guarantee ch >= 'A' && ch <= 'Z'
+ bool is_szm_enabled ( char ch ) const;
- // Return the number of full ids for the given half id.
- uint16 half2full_num(uint16 half_id) const;
+ // Return the number of full ids for the given half id.
+ uint16 half2full_num ( uint16 half_id ) const;
- // Return the number of full ids for the given half id, and fill spl_id_start
- // to return the first full id.
- uint16 half_to_full(uint16 half_id, uint16 *spl_id_start) const;
+ // Return the number of full ids for the given half id, and fill spl_id_start
+ // to return the first full id.
+ uint16 half_to_full ( uint16 half_id, uint16 *spl_id_start ) const;
- // Return the corresponding half id for the given full id.
- // Not frequently used, low efficient.
- // Return 0 if fails.
- uint16 full_to_half(uint16 full_id) const;
+ // Return the corresponding half id for the given full id.
+ // Not frequently used, low efficient.
+ // Return 0 if fails.
+ uint16 full_to_half ( uint16 full_id ) const;
- // To test whether a half id is compatible with a full id.
- // Generally, when half_id == full_to_half(full_id), return true.
- // But for "Zh, Ch, Sh", if fussy mode is on, half id for 'Z' is compatible
- // with a full id like "Zhe". (Fussy mode is not ready).
- bool half_full_compatible(uint16 half_id, uint16 full_id) const;
+ // To test whether a half id is compatible with a full id.
+ // Generally, when half_id == full_to_half(full_id), return true.
+ // But for "Zh, Ch, Sh", if fussy mode is on, half id for 'Z' is compatible
+ // with a full id like "Zhe". (Fussy mode is not ready).
+ bool half_full_compatible ( uint16 half_id, uint16 full_id ) const;
- static const SpellingTrie* get_cpinstance();
+ static const SpellingTrie *get_cpinstance();
- static SpellingTrie& get_instance();
+ static SpellingTrie &get_instance();
- // Save to the file stream
- bool save_spl_trie(FILE *fp);
+ // Save to the file stream
+ bool save_spl_trie ( FILE *fp );
- // Load from the file stream
- bool load_spl_trie(FILE *fp);
+ // Load from the file stream
+ bool load_spl_trie ( FILE *fp );
- // Get the number of spellings
- size_t get_spelling_num();
+ // Get the number of spellings
+ size_t get_spelling_num();
- // Return the Yunmu id for the given Yunmu string.
- // If the string is not valid, return 0;
- uint8 get_ym_id(const char* ym_str);
+ // Return the Yunmu id for the given Yunmu string.
+ // If the string is not valid, return 0;
+ uint8 get_ym_id ( const char *ym_str );
- // Get the readonly Pinyin string for a given spelling id
- const char* get_spelling_str(uint16 splid);
+ // Get the readonly Pinyin string for a given spelling id
+ const char *get_spelling_str ( uint16 splid );
- // Get the readonly Pinyin string for a given spelling id
- const char16* get_spelling_str16(uint16 splid);
+ // Get the readonly Pinyin string for a given spelling id
+ const char16 *get_spelling_str16 ( uint16 splid );
- // Get Pinyin string for a given spelling id. Return the length of the
- // string, and fill-in '\0' at the end.
- size_t get_spelling_str16(uint16 splid, char16 *splstr16,
- size_t splstr16_len);
-};
+ // Get Pinyin string for a given spelling id. Return the length of the
+ // string, and fill-in '\0' at the end.
+ size_t get_spelling_str16 ( uint16 splid, char16 *splstr16,
+ size_t splstr16_len );
+ };
}
#endif // PINYINIME_INCLUDE_SPELLINGTRIE_H__
diff --git a/jni/include/splparser.h b/jni/include/splparser.h
index d783bd7..9df41ea 100755
--- a/jni/include/splparser.h
+++ b/jni/include/splparser.h
@@ -22,75 +22,75 @@
namespace ime_pinyin {
-class SpellingParser {
- protected:
- const SpellingTrie *spl_trie_;
+ class SpellingParser {
+ protected:
+ const SpellingTrie *spl_trie_;
- public:
- SpellingParser();
+ public:
+ SpellingParser();
- // Given a string, parse it into a spelling id stream.
- // If the whole string are sucessfully parsed, last_is_pre will be true;
- // if the whole string is not fullly parsed, last_is_pre will return whether
- // the last part of the string is a prefix of a full spelling string. For
- // example, given string "zhengzhon", "zhon" is not a valid speling, but it is
- // the prefix of "zhong".
- //
- // If splstr starts with a character not in ['a'-z'] (it is a split char),
- // return 0.
- // Split char can only appear in the middle of the string or at the end.
- uint16 splstr_to_idxs(const char *splstr, uint16 str_len, uint16 splidx[],
- uint16 start_pos[], uint16 max_size, bool &last_is_pre);
+ // Given a string, parse it into a spelling id stream.
+ // If the whole string are sucessfully parsed, last_is_pre will be true;
+ // if the whole string is not fullly parsed, last_is_pre will return whether
+ // the last part of the string is a prefix of a full spelling string. For
+ // example, given string "zhengzhon", "zhon" is not a valid speling, but it is
+ // the prefix of "zhong".
+ //
+ // If splstr starts with a character not in ['a'-z'] (it is a split char),
+ // return 0.
+ // Split char can only appear in the middle of the string or at the end.
+ uint16 splstr_to_idxs ( const char *splstr, uint16 str_len, uint16 splidx[],
+ uint16 start_pos[], uint16 max_size, bool &last_is_pre );
- // Similar to splstr_to_idxs(), the only difference is that splstr_to_idxs()
- // convert single-character Yunmus into half ids, while this function converts
- // them into full ids.
- uint16 splstr_to_idxs_f(const char *splstr, uint16 str_len, uint16 splidx[],
- uint16 start_pos[], uint16 max_size, bool &last_is_pre);
+ // Similar to splstr_to_idxs(), the only difference is that splstr_to_idxs()
+ // convert single-character Yunmus into half ids, while this function converts
+ // them into full ids.
+ uint16 splstr_to_idxs_f ( const char *splstr, uint16 str_len, uint16 splidx[],
+ uint16 start_pos[], uint16 max_size, bool &last_is_pre );
- // Similar to splstr_to_idxs(), the only difference is that this function
- // uses char16 instead of char8.
- uint16 splstr16_to_idxs(const char16 *splstr, uint16 str_len, uint16 splidx[],
- uint16 start_pos[], uint16 max_size, bool &last_is_pre);
+ // Similar to splstr_to_idxs(), the only difference is that this function
+ // uses char16 instead of char8.
+ uint16 splstr16_to_idxs ( const char16 *splstr, uint16 str_len, uint16 splidx[],
+ uint16 start_pos[], uint16 max_size, bool &last_is_pre );
- // Similar to splstr_to_idxs_f(), the only difference is that this function
- // uses char16 instead of char8.
- uint16 splstr16_to_idxs_f(const char16 *splstr16, uint16 str_len,
- uint16 splidx[], uint16 start_pos[],
- uint16 max_size, bool &last_is_pre);
+ // Similar to splstr_to_idxs_f(), the only difference is that this function
+ // uses char16 instead of char8.
+ uint16 splstr16_to_idxs_f ( const char16 *splstr16, uint16 str_len,
+ uint16 splidx[], uint16 start_pos[],
+ uint16 max_size, bool &last_is_pre );
- // If the given string is a spelling, return the id, others, return 0.
- // If the give string is a single char Yunmus like "A", and the char is
- // enabled in ShouZiMu mode, the returned spelling id will be a half id.
- // When the returned spelling id is a half id, *is_pre returns whether it
- // is a prefix of a full spelling string.
- uint16 get_splid_by_str(const char *splstr, uint16 str_len, bool *is_pre);
+ // If the given string is a spelling, return the id, others, return 0.
+ // If the give string is a single char Yunmus like "A", and the char is
+ // enabled in ShouZiMu mode, the returned spelling id will be a half id.
+ // When the returned spelling id is a half id, *is_pre returns whether it
+ // is a prefix of a full spelling string.
+ uint16 get_splid_by_str ( const char *splstr, uint16 str_len, bool *is_pre );
- // If the given string is a spelling, return the id, others, return 0.
- // If the give string is a single char Yunmus like "a", no matter the char
- // is enabled in ShouZiMu mode or not, the returned spelling id will be
- // a full id.
- // When the returned spelling id is a half id, *p_is_pre returns whether it
- // is a prefix of a full spelling string.
- uint16 get_splid_by_str_f(const char *splstr, uint16 str_len, bool *is_pre);
+ // If the given string is a spelling, return the id, others, return 0.
+ // If the give string is a single char Yunmus like "a", no matter the char
+ // is enabled in ShouZiMu mode or not, the returned spelling id will be
+ // a full id.
+ // When the returned spelling id is a half id, *p_is_pre returns whether it
+ // is a prefix of a full spelling string.
+ uint16 get_splid_by_str_f ( const char *splstr, uint16 str_len, bool *is_pre );
- // Splitter chars are not included.
- bool is_valid_to_parse(char ch);
+ // Splitter chars are not included.
+ bool is_valid_to_parse ( char ch );
- // When auto-correction is not enabled, get_splid_by_str() will be called to
- // return the single result. When auto-correction is enabled, this function
- // will be called to get the results. Auto-correction is not ready.
- // full_id_num returns number of full spelling ids.
- // is_pre returns whether the given string is the prefix of a full spelling
- // string.
- // If splstr starts with a character not in [a-zA-Z] (it is a split char),
- // return 0.
- // Split char can only appear in the middle of the string or at the end.
- // The caller should guarantee NULL != splstr && str_len > 0 && NULL != splidx
- uint16 get_splids_parallel(const char *splstr, uint16 str_len,
- uint16 splidx[], uint16 max_size,
- uint16 &full_id_num, bool &is_pre);
-};
+ // When auto-correction is not enabled, get_splid_by_str() will be called to
+ // return the single result. When auto-correction is enabled, this function
+ // will be called to get the results. Auto-correction is not ready.
+ // full_id_num returns number of full spelling ids.
+ // is_pre returns whether the given string is the prefix of a full spelling
+ // string.
+ // If splstr starts with a character not in [a-zA-Z] (it is a split char),
+ // return 0.
+ // Split char can only appear in the middle of the string or at the end.
+ // The caller should guarantee NULL != splstr && str_len > 0 && NULL != splidx
+ uint16 get_splids_parallel ( const char *splstr, uint16 str_len,
+ uint16 splidx[], uint16 max_size,
+ uint16 &full_id_num, bool &is_pre );
+ };
}
#endif // PINYINIME_INCLUDE_SPLPARSER_H__
diff --git a/jni/include/sync.h b/jni/include/sync.h
index bf42d1f..d123b62 100755
--- a/jni/include/sync.h
+++ b/jni/include/sync.h
@@ -25,58 +25,58 @@
namespace ime_pinyin {
-// Class for user dictionary synchronization
-// This class is not thread safe
-// Normal invoking flow will be
-// begin() ->
-// put_lemmas() x N ->
-// {
-// get_lemmas() ->
-// [ get_last_got_count() ] ->
-// clear_last_got() ->
-// } x N ->
-// finish()
-class Sync {
- public:
- Sync();
- ~Sync();
-
- static const int kUserDictMaxLemmaCount = 5000;
- static const int kUserDictMaxLemmaSize = 200000;
- static const int kUserDictRatio = 20;
-
- bool begin(const char * filename);
-
- // Merge lemmas downloaded from sync server into local dictionary
- // lemmas, lemmas string encoded in UTF16LE
- // len, length of lemmas string
- // Return how many lemmas merged successfully
- int put_lemmas(char16 * lemmas, int len);
-
- // Get local new user lemmas into UTF16LE string
- // str, buffer ptr to store new user lemmas
- // size, size of buffer
- // Return length of returned buffer in measure of UTF16LE
- int get_lemmas(char16 * str, int size);
-
- // Return lemmas count in last get_lemmas()
- int get_last_got_count();
-
- // Return total lemmas count need get_lemmas()
- int get_total_count();
-
- // Clear lemmas got by recent get_lemmas()
- void clear_last_got();
-
- void finish();
-
- int get_capacity();
-
- private:
- UserDict * userdict_;
- char * dictfile_;
- int last_count_;
-};
+ // Class for user dictionary synchronization
+ // This class is not thread safe
+ // Normal invoking flow will be
+ // begin() ->
+ // put_lemmas() x N ->
+ // {
+ // get_lemmas() ->
+ // [ get_last_got_count() ] ->
+ // clear_last_got() ->
+ // } x N ->
+ // finish()
+ class Sync {
+ public:
+ Sync();
+ ~Sync();
+
+ static const int kUserDictMaxLemmaCount = 5000;
+ static const int kUserDictMaxLemmaSize = 200000;
+ static const int kUserDictRatio = 20;
+
+ bool begin ( const char *filename );
+
+ // Merge lemmas downloaded from sync server into local dictionary
+ // lemmas, lemmas string encoded in UTF16LE
+ // len, length of lemmas string
+ // Return how many lemmas merged successfully
+ int put_lemmas ( char16 *lemmas, int len );
+
+ // Get local new user lemmas into UTF16LE string
+ // str, buffer ptr to store new user lemmas
+ // size, size of buffer
+ // Return length of returned buffer in measure of UTF16LE
+ int get_lemmas ( char16 *str, int size );
+
+ // Return lemmas count in last get_lemmas()
+ int get_last_got_count();
+
+ // Return total lemmas count need get_lemmas()
+ int get_total_count();
+
+ // Clear lemmas got by recent get_lemmas()
+ void clear_last_got();
+
+ void finish();
+
+ int get_capacity();
+
+ private:
+ UserDict *userdict_;
+ char *dictfile_;
+ int last_count_;
+ };
}
diff --git a/jni/include/userdict.h b/jni/include/userdict.h
index 02da218..22048d4 100755
--- a/jni/include/userdict.h
+++ b/jni/include/userdict.h
@@ -29,400 +29,400 @@
namespace ime_pinyin {
-class UserDict : public AtomDictBase {
- public:
- UserDict();
- ~UserDict();
+ class UserDict : public AtomDictBase {
+ public:
+ UserDict();
+ ~UserDict();
- bool load_dict(const char *file_name, LemmaIdType start_id,
- LemmaIdType end_id);
+ bool load_dict ( const char *file_name, LemmaIdType start_id,
+ LemmaIdType end_id );
- bool close_dict();
+ bool close_dict();
- size_t number_of_lemmas();
+ size_t number_of_lemmas();
- void reset_milestones(uint16 from_step, MileStoneHandle from_handle);
+ void reset_milestones ( uint16 from_step, MileStoneHandle from_handle );
- MileStoneHandle extend_dict(MileStoneHandle from_handle,
- const DictExtPara *dep, LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num);
+ MileStoneHandle extend_dict ( MileStoneHandle from_handle,
+ const DictExtPara *dep, LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num );
- size_t get_lpis(const uint16 *splid_str, uint16 splid_str_len,
- LmaPsbItem *lpi_items, size_t lpi_max);
+ size_t get_lpis ( const uint16 *splid_str, uint16 splid_str_len,
+ LmaPsbItem *lpi_items, size_t lpi_max );
- uint16 get_lemma_str(LemmaIdType id_lemma, char16* str_buf,
- uint16 str_max);
+ uint16 get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf,
+ uint16 str_max );
- uint16 get_lemma_splids(LemmaIdType id_lemma, uint16 *splids,
- uint16 splids_max, bool arg_valid);
+ uint16 get_lemma_splids ( LemmaIdType id_lemma, uint16 *splids,
+ uint16 splids_max, bool arg_valid );
- size_t predict(const char16 last_hzs[], uint16 hzs_len,
- NPredictItem *npre_items, size_t npre_max,
- size_t b4_used);
+ size_t predict ( const char16 last_hzs[], uint16 hzs_len,
+ NPredictItem *npre_items, size_t npre_max,
+ size_t b4_used );
- // Full spelling ids are required
- LemmaIdType put_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count);
+ // Full spelling ids are required
+ LemmaIdType put_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count );
- LemmaIdType update_lemma(LemmaIdType lemma_id, int16 delta_count,
- bool selected);
+ LemmaIdType update_lemma ( LemmaIdType lemma_id, int16 delta_count,
+ bool selected );
- LemmaIdType get_lemma_id(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len);
+ LemmaIdType get_lemma_id ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len );
- LmaScoreType get_lemma_score(LemmaIdType lemma_id);
+ LmaScoreType get_lemma_score ( LemmaIdType lemma_id );
- LmaScoreType get_lemma_score(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len);
+ LmaScoreType get_lemma_score ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len );
- bool remove_lemma(LemmaIdType lemma_id);
+ bool remove_lemma ( LemmaIdType lemma_id );
- size_t get_total_lemma_count();
- void set_total_lemma_count_of_others(size_t count);
+ size_t get_total_lemma_count();
+ void set_total_lemma_count_of_others ( size_t count );
- void flush_cache();
+ void flush_cache();
- void set_limit(uint32 max_lemma_count, uint32 max_lemma_size,
- uint32 reclaim_ratio);
+ void set_limit ( uint32 max_lemma_count, uint32 max_lemma_size,
+ uint32 reclaim_ratio );
- void reclaim();
+ void reclaim();
- void defragment();
+ void defragment();
#ifdef ___SYNC_ENABLED___
- void clear_sync_lemmas(unsigned int start, unsigned int end);
-
- int get_sync_count();
-
- LemmaIdType put_lemma_no_sync(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count, uint64 lmt);
- /**
- * Add lemmas encoded in UTF-16LE into dictionary without adding sync flag.
- *
- * @param lemmas in format of 'wo men,WM,0.32;da jia,DJ,0.12'
- * @param len length of lemmas string in UTF-16LE
- * @return newly added lemma count
- */
- int put_lemmas_no_sync_from_utf16le_string(char16 * lemmas, int len);
-
- /**
- * Get lemmas need sync to a UTF-16LE string of above format.
- * Note: input buffer (str) must not be too small. If str is too small to
- * contain single one lemma, there might be a dead loop.
- *
- * @param str buffer to write lemmas
- * @param size buffer size in UTF-16LE
- * @param count output value of lemma returned
- * @return UTF-16LE string length
- */
- int get_sync_lemmas_in_utf16le_string_from_beginning(
- char16 * str, int size, int * count);
+ void clear_sync_lemmas ( unsigned int start, unsigned int end );
+
+ int get_sync_count();
+
+ LemmaIdType put_lemma_no_sync ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count, uint64 lmt );
+ /**
+ * Add lemmas encoded in UTF-16LE into dictionary without adding sync flag.
+ *
+ * @param lemmas in format of 'wo men,WM,0.32;da jia,DJ,0.12'
+ * @param len length of lemmas string in UTF-16LE
+ * @return newly added lemma count
+ */
+ int put_lemmas_no_sync_from_utf16le_string ( char16 *lemmas, int len );
+
+ /**
+ * Get lemmas need sync to a UTF-16LE string of above format.
+ * Note: input buffer (str) must not be too small. If str is too small to
+ * contain single one lemma, there might be a dead loop.
+ *
+ * @param str buffer to write lemmas
+ * @param size buffer size in UTF-16LE
+ * @param count output value of lemma returned
+ * @return UTF-16LE string length
+ */
+ int get_sync_lemmas_in_utf16le_string_from_beginning (
+ char16 *str, int size, int *count );
#endif
- struct UserDictStat {
- uint32 version;
- const char * file_name;
- struct timeval load_time;
- struct timeval last_update;
- uint32 disk_size;
- uint32 lemma_count;
- uint32 lemma_size;
- uint32 delete_count;
- uint32 delete_size;
+ struct UserDictStat {
+ uint32 version;
+ const char *file_name;
+ struct timeval load_time;
+ struct timeval last_update;
+ uint32 disk_size;
+ uint32 lemma_count;
+ uint32 lemma_size;
+ uint32 delete_count;
+ uint32 delete_size;
#ifdef ___SYNC_ENABLED___
- uint32 sync_count;
+ uint32 sync_count;
#endif
- uint32 reclaim_ratio;
- uint32 limit_lemma_count;
- uint32 limit_lemma_size;
- };
-
- bool state(UserDictStat * stat);
-
- private:
- uint32 total_other_nfreq_;
- struct timeval load_time_;
- LemmaIdType start_id_;
- uint32 version_;
- uint8 * lemmas_;
-
- // In-Memory-Only flag for each lemma
- static const uint8 kUserDictLemmaFlagRemove = 1;
- // Inuse lemmas' offset
- uint32 * offsets_;
- // Highest bit in offset tells whether corresponding lemma is removed
- static const uint32 kUserDictOffsetFlagRemove = (1 << 31);
- // Maximum possible for the offset
- static const uint32 kUserDictOffsetMask = ~(kUserDictOffsetFlagRemove);
- // Bit width for last modified time, from 1 to 16
- static const uint32 kUserDictLMTBitWidth = 16;
- // Granularity for last modified time in second
- static const uint32 kUserDictLMTGranularity = 60 * 60 * 24 * 7;
- // Maximum frequency count
- static const uint16 kUserDictMaxFrequency = 0xFFFF;
+ uint32 reclaim_ratio;
+ uint32 limit_lemma_count;
+ uint32 limit_lemma_size;
+ };
+
+ bool state ( UserDictStat *stat );
+
+ private:
+ uint32 total_other_nfreq_;
+ struct timeval load_time_;
+ LemmaIdType start_id_;
+ uint32 version_;
+ uint8 *lemmas_;
+
+ // In-Memory-Only flag for each lemma
+ static const uint8 kUserDictLemmaFlagRemove = 1;
+ // Inuse lemmas' offset
+ uint32 *offsets_;
+ // Highest bit in offset tells whether corresponding lemma is removed
+ static const uint32 kUserDictOffsetFlagRemove = ( 1 << 31 );
+ // Maximum possible for the offset
+ static const uint32 kUserDictOffsetMask = ~ ( kUserDictOffsetFlagRemove );
+ // Bit width for last modified time, from 1 to 16
+ static const uint32 kUserDictLMTBitWidth = 16;
+ // Granularity for last modified time in second
+ static const uint32 kUserDictLMTGranularity = 60 * 60 * 24 * 7;
+ // Maximum frequency count
+ static const uint16 kUserDictMaxFrequency = 0xFFFF;
#define COARSE_UTC(year, month, day, hour, minute, second) \
- ( \
- (year - 1970) * 365 * 24 * 60 * 60 + \
- (month - 1) * 30 * 24 * 60 * 60 + \
- (day - 1) * 24 * 60 * 60 + \
- (hour - 0) * 60 * 60 + \
- (minute - 0) * 60 + \
- (second - 0) \
- )
- static const uint64 kUserDictLMTSince = COARSE_UTC(2009, 1, 1, 0, 0, 0);
-
- // Correspond to offsets_
- uint32 * scores_;
- // Following two fields are only valid in memory
- uint32 * ids_;
+ ( \
+ (year - 1970) * 365 * 24 * 60 * 60 + \
+ (month - 1) * 30 * 24 * 60 * 60 + \
+ (day - 1) * 24 * 60 * 60 + \
+ (hour - 0) * 60 * 60 + \
+ (minute - 0) * 60 + \
+ (second - 0) \
+ )
+ static const uint64 kUserDictLMTSince = COARSE_UTC ( 2009, 1, 1, 0, 0, 0 );
+
+ // Correspond to offsets_
+ uint32 *scores_;
+ // Following two fields are only valid in memory
+ uint32 *ids_;
#ifdef ___PREDICT_ENABLED___
- uint32 * predicts_;
+ uint32 *predicts_;
#endif
#ifdef ___SYNC_ENABLED___
- uint32 * syncs_;
- size_t sync_count_size_;
+ uint32 *syncs_;
+ size_t sync_count_size_;
#endif
- uint32 * offsets_by_id_;
-
- size_t lemma_count_left_;
- size_t lemma_size_left_;
-
- const char * dict_file_;
-
- // Be sure size is 4xN
- struct UserDictInfo {
- // When limitation reached, how much percentage will be reclaimed (1 ~ 100)
- uint32 reclaim_ratio;
- // maximum lemma count, 0 means no limitation
- uint32 limit_lemma_count;
- // Maximum lemma size, it's different from
- // whole disk file size or in-mem dict size
- // 0 means no limitation
- uint32 limit_lemma_size;
- // Total lemma count including deleted and inuse
- // Also indicate offsets_ size
- uint32 lemma_count;
- // Total size of lemmas including used and freed
- uint32 lemma_size;
- // Freed lemma count
- uint32 free_count;
- // Freed lemma size in byte
- uint32 free_size;
+ uint32 *offsets_by_id_;
+
+ size_t lemma_count_left_;
+ size_t lemma_size_left_;
+
+ const char *dict_file_;
+
+ // Be sure size is 4xN
+ struct UserDictInfo {
+ // When limitation reached, how much percentage will be reclaimed (1 ~ 100)
+ uint32 reclaim_ratio;
+ // maximum lemma count, 0 means no limitation
+ uint32 limit_lemma_count;
+ // Maximum lemma size, it's different from
+ // whole disk file size or in-mem dict size
+ // 0 means no limitation
+ uint32 limit_lemma_size;
+ // Total lemma count including deleted and inuse
+ // Also indicate offsets_ size
+ uint32 lemma_count;
+ // Total size of lemmas including used and freed
+ uint32 lemma_size;
+ // Freed lemma count
+ uint32 free_count;
+ // Freed lemma size in byte
+ uint32 free_size;
#ifdef ___SYNC_ENABLED___
- uint32 sync_count;
+ uint32 sync_count;
#endif
- int32 total_nfreq;
- } dict_info_;
+ int32 total_nfreq;
+ } dict_info_;
- static const uint32 kUserDictVersion = 0x0ABCDEF0;
+ static const uint32 kUserDictVersion = 0x0ABCDEF0;
- static const uint32 kUserDictPreAlloc = 32;
- static const uint32 kUserDictAverageNchar = 8;
+ static const uint32 kUserDictPreAlloc = 32;
+ static const uint32 kUserDictAverageNchar = 8;
- enum UserDictState {
- // Keep in order
- USER_DICT_NONE = 0,
- USER_DICT_SYNC,
+ enum UserDictState {
+ // Keep in order
+ USER_DICT_NONE = 0,
+ USER_DICT_SYNC,
#ifdef ___SYNC_ENABLED___
- USER_DICT_SYNC_DIRTY,
+ USER_DICT_SYNC_DIRTY,
#endif
- USER_DICT_SCORE_DIRTY,
- USER_DICT_OFFSET_DIRTY,
- USER_DICT_LEMMA_DIRTY,
+ USER_DICT_SCORE_DIRTY,
+ USER_DICT_OFFSET_DIRTY,
+ USER_DICT_LEMMA_DIRTY,
- USER_DICT_DEFRAGMENTED,
- } state_;
+ USER_DICT_DEFRAGMENTED,
+ } state_;
- struct UserDictSearchable {
- uint16 splids_len;
- uint16 splid_start[kMaxLemmaSize];
- uint16 splid_count[kMaxLemmaSize];
- // Compact inital letters for both FuzzyCompareSpellId and cache system
- uint32 signature[kMaxLemmaSize / 4];
- };
+ struct UserDictSearchable {
+ uint16 splids_len;
+ uint16 splid_start[kMaxLemmaSize];
+ uint16 splid_count[kMaxLemmaSize];
+ // Compact inital letters for both FuzzyCompareSpellId and cache system
+ uint32 signature[kMaxLemmaSize / 4];
+ };
#ifdef ___CACHE_ENABLED___
- enum UserDictCacheType {
- USER_DICT_CACHE,
- USER_DICT_MISS_CACHE,
- };
+ enum UserDictCacheType {
+ USER_DICT_CACHE,
+ USER_DICT_MISS_CACHE,
+ };
- static const int kUserDictCacheSize = 4;
- static const int kUserDictMissCacheSize = kMaxLemmaSize - 1;
+ static const int kUserDictCacheSize = 4;
+ static const int kUserDictMissCacheSize = kMaxLemmaSize - 1;
- struct UserDictMissCache {
- uint32 signatures[kUserDictMissCacheSize][kMaxLemmaSize / 4];
- uint16 head, tail;
- } miss_caches_[kMaxLemmaSize];
+ struct UserDictMissCache {
+ uint32 signatures[kUserDictMissCacheSize][kMaxLemmaSize / 4];
+ uint16 head, tail;
+ } miss_caches_[kMaxLemmaSize];
- struct UserDictCache {
- uint32 signatures[kUserDictCacheSize][kMaxLemmaSize / 4];
- uint32 offsets[kUserDictCacheSize];
- uint32 lengths[kUserDictCacheSize];
- // Ring buffer
- uint16 head, tail;
- } caches_[kMaxLemmaSize];
+ struct UserDictCache {
+ uint32 signatures[kUserDictCacheSize][kMaxLemmaSize / 4];
+ uint32 offsets[kUserDictCacheSize];
+ uint32 lengths[kUserDictCacheSize];
+ // Ring buffer
+ uint16 head, tail;
+ } caches_[kMaxLemmaSize];
- void cache_init();
+ void cache_init();
- void cache_push(UserDictCacheType type,
- UserDictSearchable *searchable,
- uint32 offset, uint32 length);
+ void cache_push ( UserDictCacheType type,
+ UserDictSearchable *searchable,
+ uint32 offset, uint32 length );
- bool cache_hit(UserDictSearchable *searchable,
- uint32 *offset, uint32 *length);
+ bool cache_hit ( UserDictSearchable *searchable,
+ uint32 *offset, uint32 *length );
- bool load_cache(UserDictSearchable *searchable,
- uint32 *offset, uint32 *length);
+ bool load_cache ( UserDictSearchable *searchable,
+ uint32 *offset, uint32 *length );
- void save_cache(UserDictSearchable *searchable,
- uint32 offset, uint32 length);
+ void save_cache ( UserDictSearchable *searchable,
+ uint32 offset, uint32 length );
- void reset_cache();
+ void reset_cache();
- bool load_miss_cache(UserDictSearchable *searchable);
+ bool load_miss_cache ( UserDictSearchable *searchable );
- void save_miss_cache(UserDictSearchable *searchable);
+ void save_miss_cache ( UserDictSearchable *searchable );
- void reset_miss_cache();
+ void reset_miss_cache();
#endif
- LmaScoreType translate_score(int f);
+ LmaScoreType translate_score ( int f );
- int extract_score_freq(int raw_score);
+ int extract_score_freq ( int raw_score );
- uint64 extract_score_lmt(int raw_score);
+ uint64 extract_score_lmt ( int raw_score );
- inline int build_score(uint64 lmt, int freq);
+ inline int build_score ( uint64 lmt, int freq );
- inline int64 utf16le_atoll(uint16 *s, int len);
+ inline int64 utf16le_atoll ( uint16 *s, int len );
- inline int utf16le_lltoa(int64 v, uint16 *s, int size);
+ inline int utf16le_lltoa ( int64 v, uint16 *s, int size );
- LemmaIdType _put_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count, uint64 lmt);
+ LemmaIdType _put_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count, uint64 lmt );
- size_t _get_lpis(const uint16 *splid_str, uint16 splid_str_len,
- LmaPsbItem *lpi_items, size_t lpi_max, bool * need_extend);
+ size_t _get_lpis ( const uint16 *splid_str, uint16 splid_str_len,
+ LmaPsbItem *lpi_items, size_t lpi_max, bool *need_extend );
- int _get_lemma_score(char16 lemma_str[], uint16 splids[], uint16 lemma_len);
+ int _get_lemma_score ( char16 lemma_str[], uint16 splids[], uint16 lemma_len );
- int _get_lemma_score(LemmaIdType lemma_id);
+ int _get_lemma_score ( LemmaIdType lemma_id );
- int is_fuzzy_prefix_spell_id(const uint16 * id1, uint16 len1,
- const UserDictSearchable *searchable);
+ int is_fuzzy_prefix_spell_id ( const uint16 *id1, uint16 len1,
+ const UserDictSearchable *searchable );
- bool is_prefix_spell_id(const uint16 * fullids,
- uint16 fulllen, const UserDictSearchable *searchable);
+ bool is_prefix_spell_id ( const uint16 *fullids,
+ uint16 fulllen, const UserDictSearchable *searchable );
- uint32 get_dict_file_size(UserDictInfo * info);
+ uint32 get_dict_file_size ( UserDictInfo *info );
- bool reset(const char *file);
+ bool reset ( const char *file );
- bool validate(const char *file);
+ bool validate ( const char *file );
- bool load(const char *file, LemmaIdType start_id);
+ bool load ( const char *file, LemmaIdType start_id );
- bool is_valid_state();
+ bool is_valid_state();
- bool is_valid_lemma_id(LemmaIdType id);
+ bool is_valid_lemma_id ( LemmaIdType id );
- LemmaIdType get_max_lemma_id();
+ LemmaIdType get_max_lemma_id();
- void set_lemma_flag(uint32 offset, uint8 flag);
+ void set_lemma_flag ( uint32 offset, uint8 flag );
- char get_lemma_flag(uint32 offset);
+ char get_lemma_flag ( uint32 offset );
- char get_lemma_nchar(uint32 offset);
+ char get_lemma_nchar ( uint32 offset );
- uint16 * get_lemma_spell_ids(uint32 offset);
+ uint16 *get_lemma_spell_ids ( uint32 offset );
- uint16 * get_lemma_word(uint32 offset);
+ uint16 *get_lemma_word ( uint32 offset );
- // Prepare searchable to fasten locate process
- void prepare_locate(UserDictSearchable *searchable,
- const uint16 * splids, uint16 len);
+ // Prepare searchable to fasten locate process
+ void prepare_locate ( UserDictSearchable *searchable,
+ const uint16 *splids, uint16 len );
- // Compare initial letters only
- int32 fuzzy_compare_spell_id(const uint16 * id1, uint16 len1,
- const UserDictSearchable *searchable);
+ // Compare initial letters only
+ int32 fuzzy_compare_spell_id ( const uint16 *id1, uint16 len1,
+ const UserDictSearchable *searchable );
- // Compare exactly two spell ids
- // First argument must be a full id spell id
- bool equal_spell_id(const uint16 * fullids,
- uint16 fulllen, const UserDictSearchable *searchable);
+ // Compare exactly two spell ids
+ // First argument must be a full id spell id
+ bool equal_spell_id ( const uint16 *fullids,
+ uint16 fulllen, const UserDictSearchable *searchable );
- // Find first item by initial letters
- int32 locate_first_in_offsets(const UserDictSearchable *searchable);
+ // Find first item by initial letters
+ int32 locate_first_in_offsets ( const UserDictSearchable *searchable );
- LemmaIdType append_a_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count, uint64 lmt);
+ LemmaIdType append_a_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count, uint64 lmt );
- // Check if a lemma is in dictionary
- int32 locate_in_offsets(char16 lemma_str[],
- uint16 splid_str[], uint16 lemma_len);
+ // Check if a lemma is in dictionary
+ int32 locate_in_offsets ( char16 lemma_str[],
+ uint16 splid_str[], uint16 lemma_len );
- bool remove_lemma_by_offset_index(int offset_index);
+ bool remove_lemma_by_offset_index ( int offset_index );
#ifdef ___PREDICT_ENABLED___
- uint32 locate_where_to_insert_in_predicts(const uint16 * words,
- int lemma_len);
+ uint32 locate_where_to_insert_in_predicts ( const uint16 *words,
+ int lemma_len );
- int32 locate_first_in_predicts(const uint16 * words, int lemma_len);
+ int32 locate_first_in_predicts ( const uint16 *words, int lemma_len );
- void remove_lemma_from_predict_list(uint32 offset);
+ void remove_lemma_from_predict_list ( uint32 offset );
#endif
#ifdef ___SYNC_ENABLED___
- void queue_lemma_for_sync(LemmaIdType id);
+ void queue_lemma_for_sync ( LemmaIdType id );
- void remove_lemma_from_sync_list(uint32 offset);
+ void remove_lemma_from_sync_list ( uint32 offset );
- void write_back_sync(int fd);
+ void write_back_sync ( int fd );
#endif
- void write_back_score(int fd);
- void write_back_offset(int fd);
- void write_back_lemma(int fd);
- void write_back_all(int fd);
- void write_back();
-
- struct UserDictScoreOffsetPair {
- int score;
- uint32 offset_index;
- };
-
- inline void swap(UserDictScoreOffsetPair * sop, int i, int j);
-
- void shift_down(UserDictScoreOffsetPair * sop, int i, int n);
-
- // On-disk format for each lemma
- // +-------------+
- // | Version (4) |
- // +-------------+
- // +-----------+-----------+--------------------+-------------------+
- // | Spare (1) | Nchar (1) | Splids (2 x Nchar) | Lemma (2 x Nchar) |
- // +-----------+-----------+--------------------+-------------------+
- // ...
- // +-----------------------+ +-------------+ <---Offset of offset
- // | Offset1 by_splids (4) | ... | OffsetN (4) |
- // +-----------------------+ +-------------+
+ void write_back_score ( int fd );
+ void write_back_offset ( int fd );
+ void write_back_lemma ( int fd );
+ void write_back_all ( int fd );
+ void write_back();
+
+ struct UserDictScoreOffsetPair {
+ int score;
+ uint32 offset_index;
+ };
+
+ inline void swap ( UserDictScoreOffsetPair *sop, int i, int j );
+
+ void shift_down ( UserDictScoreOffsetPair *sop, int i, int n );
+
+ // On-disk format for each lemma
+ // +-------------+
+ // | Version (4) |
+ // +-------------+
+ // +-----------+-----------+--------------------+-------------------+
+ // | Spare (1) | Nchar (1) | Splids (2 x Nchar) | Lemma (2 x Nchar) |
+ // +-----------+-----------+--------------------+-------------------+
+ // ...
+ // +-----------------------+ +-------------+ <---Offset of offset
+ // | Offset1 by_splids (4) | ... | OffsetN (4) |
+ // +-----------------------+ +-------------+
#ifdef ___PREDICT_ENABLED___
- // +----------------------+ +-------------+
- // | Offset1 by_lemma (4) | ... | OffsetN (4) |
- // +----------------------+ +-------------+
+ // +----------------------+ +-------------+
+ // | Offset1 by_lemma (4) | ... | OffsetN (4) |
+ // +----------------------+ +-------------+
#endif
- // +------------+ +------------+
- // | Score1 (4) | ... | ScoreN (4) |
- // +------------+ +------------+
+ // +------------+ +------------+
+ // | Score1 (4) | ... | ScoreN (4) |
+ // +------------+ +------------+
#ifdef ___SYNC_ENABLED___
- // +-------------+ +-------------+
- // | NewAdd1 (4) | ... | NewAddN (4) |
- // +-------------+ +-------------+
+ // +-------------+ +-------------+
+ // | NewAdd1 (4) | ... | NewAddN (4) |
+ // +-------------+ +-------------+
#endif
- // +----------------+
- // | Dict Info (4x) |
- // +----------------+
-};
+ // +----------------+
+ // | Dict Info (4x) |
+ // +----------------+
+ };
}
#endif
diff --git a/jni/include/utf16char.h b/jni/include/utf16char.h
index 7e957db..f466d41 100755
--- a/jni/include/utf16char.h
+++ b/jni/include/utf16char.h
@@ -22,34 +22,34 @@
namespace ime_pinyin {
#ifdef __cplusplus
-extern "C" {
+ extern "C" {
#endif
- typedef unsigned short char16;
+ typedef unsigned short char16;
- // Get a token from utf16_str,
- // Returned pointer is a '\0'-terminated utf16 string, or NULL
- // *utf16_str_next returns the next part of the string for further tokenizing
- char16* utf16_strtok(char16 *utf16_str, size_t *token_size,
- char16 **utf16_str_next);
+ // Get a token from utf16_str,
+ // Returned pointer is a '\0'-terminated utf16 string, or NULL
+ // *utf16_str_next returns the next part of the string for further tokenizing
+ char16 *utf16_strtok ( char16 *utf16_str, size_t *token_size,
+ char16 **utf16_str_next );
- int utf16_atoi(const char16 *utf16_str);
+ int utf16_atoi ( const char16 *utf16_str );
- float utf16_atof(const char16 *utf16_str);
+ float utf16_atof ( const char16 *utf16_str );
- size_t utf16_strlen(const char16 *utf16_str);
+ size_t utf16_strlen ( const char16 *utf16_str );
- int utf16_strcmp(const char16 *str1, const char16 *str2);
- int utf16_strncmp(const char16 *str1, const char16 *str2, size_t size);
+ int utf16_strcmp ( const char16 *str1, const char16 *str2 );
+ int utf16_strncmp ( const char16 *str1, const char16 *str2, size_t size );
- char16* utf16_strcpy(char16 *dst, const char16 *src);
- char16* utf16_strncpy(char16 *dst, const char16 *src, size_t size);
+ char16 *utf16_strcpy ( char16 *dst, const char16 *src );
+ char16 *utf16_strncpy ( char16 *dst, const char16 *src, size_t size );
- char* utf16_strcpy_tochar(char *dst, const char16 *src);
+ char *utf16_strcpy_tochar ( char *dst, const char16 *src );
#ifdef __cplusplus
-}
+ }
#endif
}
diff --git a/jni/include/utf16reader.h b/jni/include/utf16reader.h
index b6d6719..02de634 100755
--- a/jni/include/utf16reader.h
+++ b/jni/include/utf16reader.h
@@ -22,27 +22,27 @@
namespace ime_pinyin {
-class Utf16Reader {
- private:
- FILE *fp_;
- char16 *buffer_;
- size_t buffer_total_len_;
- size_t buffer_next_pos_;
-
- // Always less than buffer_total_len_ - buffer_next_pos_
- size_t buffer_valid_len_;
-
- public:
- Utf16Reader();
- ~Utf16Reader();
-
- // filename is the name of the file to open.
- // buffer_len specifies how long buffer should be allocated to speed up the
- // future reading
- bool open(const char* filename, size_t buffer_len);
- char16* readline(char16* read_buf, size_t max_len);
- bool close();
-};
+ class Utf16Reader {
+ private:
+ FILE *fp_;
+ char16 *buffer_;
+ size_t buffer_total_len_;
+ size_t buffer_next_pos_;
+
+ // Always less than buffer_total_len_ - buffer_next_pos_
+ size_t buffer_valid_len_;
+
+ public:
+ Utf16Reader();
+ ~Utf16Reader();
+
+ // filename is the name of the file to open.
+ // buffer_len specifies how long buffer should be allocated to speed up the
+ // future reading
+ bool open ( const char *filename, size_t buffer_len );
+ char16 *readline ( char16 *read_buf, size_t max_len );
+ bool close();
+ };
}
#endif // PINYINIME_INCLUDE_UTF16READER_H__
diff --git a/jni/share/dictbuilder.cpp b/jni/share/dictbuilder.cpp
index 6f0bd4f..8dadd7c 100755
--- a/jni/share/dictbuilder.cpp
+++ b/jni/share/dictbuilder.cpp
@@ -33,1037 +33,877 @@ namespace ime_pinyin {
#ifdef ___BUILD_MODEL___
-static const size_t kReadBufLen = 512;
-static const size_t kSplTableHashLen = 2000;
-
-// Compare a SingleCharItem, first by Hanzis, then by spelling ids, then by
-// frequencies.
-int cmp_scis_hz_splid_freq(const void* p1, const void* p2) {
- const SingleCharItem *s1, *s2;
- s1 = static_cast<const SingleCharItem*>(p1);
- s2 = static_cast<const SingleCharItem*>(p2);
-
- if (s1->hz < s2->hz)
- return -1;
- if (s1->hz > s2->hz)
- return 1;
-
- if (s1->splid.half_splid < s2->splid.half_splid)
- return -1;
- if (s1->splid.half_splid > s2->splid.half_splid)
- return 1;
-
- if (s1->splid.full_splid < s2->splid.full_splid)
- return -1;
- if (s1->splid.full_splid > s2->splid.full_splid)
- return 1;
-
- if (s1->freq > s2->freq)
- return -1;
- if (s1->freq < s2->freq)
- return 1;
- return 0;
-}
-
-int cmp_scis_hz_splid(const void* p1, const void* p2) {
- const SingleCharItem *s1, *s2;
- s1 = static_cast<const SingleCharItem*>(p1);
- s2 = static_cast<const SingleCharItem*>(p2);
-
- if (s1->hz < s2->hz)
- return -1;
- if (s1->hz > s2->hz)
- return 1;
-
- if (s1->splid.half_splid < s2->splid.half_splid)
- return -1;
- if (s1->splid.half_splid > s2->splid.half_splid)
- return 1;
-
- if (s1->splid.full_splid < s2->splid.full_splid)
- return -1;
- if (s1->splid.full_splid > s2->splid.full_splid)
- return 1;
-
- return 0;
-}
-
-int cmp_lemma_entry_hzs(const void* p1, const void* p2) {
- size_t size1 = utf16_strlen(((const LemmaEntry*)p1)->hanzi_str);
- size_t size2 = utf16_strlen(((const LemmaEntry*)p2)->hanzi_str);
- if (size1 < size2)
- return -1;
- else if (size1 > size2)
- return 1;
-
- return utf16_strcmp(((const LemmaEntry*)p1)->hanzi_str,
- ((const LemmaEntry*)p2)->hanzi_str);
-}
-
-int compare_char16(const void* p1, const void* p2) {
- if (*((const char16*)p1) < *((const char16*)p2))
- return -1;
- if (*((const char16*)p1) > *((const char16*)p2))
- return 1;
- return 0;
-}
-
-int compare_py(const void* p1, const void* p2) {
- int ret = utf16_strcmp(((const LemmaEntry*)p1)->spl_idx_arr,
- ((const LemmaEntry*)p2)->spl_idx_arr);
-
- if (0 != ret)
- return ret;
-
- return static_cast<int>(((const LemmaEntry*)p2)->freq) -
- static_cast<int>(((const LemmaEntry*)p1)->freq);
-}
-
-// First hanzi, if the same, then Pinyin
-int cmp_lemma_entry_hzspys(const void* p1, const void* p2) {
- size_t size1 = utf16_strlen(((const LemmaEntry*)p1)->hanzi_str);
- size_t size2 = utf16_strlen(((const LemmaEntry*)p2)->hanzi_str);
- if (size1 < size2)
- return -1;
- else if (size1 > size2)
- return 1;
- int ret = utf16_strcmp(((const LemmaEntry*)p1)->hanzi_str,
- ((const LemmaEntry*)p2)->hanzi_str);
-
- if (0 != ret)
- return ret;
-
- ret = utf16_strcmp(((const LemmaEntry*)p1)->spl_idx_arr,
- ((const LemmaEntry*)p2)->spl_idx_arr);
- return ret;
-}
-
-int compare_splid2(const void* p1, const void* p2) {
- int ret = utf16_strcmp(((const LemmaEntry*)p1)->spl_idx_arr,
- ((const LemmaEntry*)p2)->spl_idx_arr);
- return ret;
-}
-
-DictBuilder::DictBuilder() {
- lemma_arr_ = NULL;
- lemma_num_ = 0;
-
- scis_ = NULL;
- scis_num_ = 0;
-
- lma_nodes_le0_ = NULL;
- lma_nodes_ge1_ = NULL;
-
- lma_nds_used_num_le0_ = 0;
- lma_nds_used_num_ge1_ = 0;
-
- homo_idx_buf_ = NULL;
- homo_idx_num_eq1_ = 0;
- homo_idx_num_gt1_ = 0;
-
- top_lmas_ = NULL;
- top_lmas_num_ = 0;
-
- spl_table_ = NULL;
- spl_parser_ = NULL;
-}
-
-DictBuilder::~DictBuilder() {
- free_resource();
-}
-
-bool DictBuilder::alloc_resource(size_t lma_num) {
- if (0 == lma_num)
- return false;
-
- free_resource();
-
- lemma_num_ = lma_num;
- lemma_arr_ = new LemmaEntry[lemma_num_];
-
- top_lmas_num_ = 0;
- top_lmas_ = new LemmaEntry[kTopScoreLemmaNum];
-
- // New the scis_ buffer to the possible maximum size.
- scis_num_ = lemma_num_ * kMaxLemmaSize;
- scis_ = new SingleCharItem[scis_num_];
-
- // The root and first level nodes is less than kMaxSpellingNum + 1
- lma_nds_used_num_le0_ = 0;
- lma_nodes_le0_ = new LmaNodeLE0[kMaxSpellingNum + 1];
-
- // Other nodes is less than lemma_num
- lma_nds_used_num_ge1_ = 0;
- lma_nodes_ge1_ = new LmaNodeGE1[lemma_num_];
-
- homo_idx_buf_ = new LemmaIdType[lemma_num_];
- spl_table_ = new SpellingTable();
- spl_parser_ = new SpellingParser();
-
- if (NULL == lemma_arr_ || NULL == top_lmas_ ||
- NULL == scis_ || NULL == spl_table_ ||
- NULL == spl_parser_ || NULL == lma_nodes_le0_ ||
- NULL == lma_nodes_ge1_ || NULL == homo_idx_buf_) {
- free_resource();
- return false;
- }
-
- memset(lemma_arr_, 0, sizeof(LemmaEntry) * lemma_num_);
- memset(scis_, 0, sizeof(SingleCharItem) * scis_num_);
- memset(lma_nodes_le0_, 0, sizeof(LmaNodeLE0) * (kMaxSpellingNum + 1));
- memset(lma_nodes_ge1_, 0, sizeof(LmaNodeGE1) * lemma_num_);
- memset(homo_idx_buf_, 0, sizeof(LemmaIdType) * lemma_num_);
- spl_table_->init_table(kMaxPinyinSize, kSplTableHashLen, true);
-
- return true;
-}
-
-char16* DictBuilder::read_valid_hanzis(const char *fn_validhzs, size_t *num) {
- if (NULL == fn_validhzs || NULL == num)
- return NULL;
-
- *num = 0;
- FILE *fp = fopen(fn_validhzs, "rb");
- if (NULL == fp)
- return NULL;
-
- char16 utf16header;
- if (fread(&utf16header, sizeof(char16), 1, fp) != 1 ||
- 0xfeff != utf16header) {
- fclose(fp);
- return NULL;
- }
-
- fseek(fp, 0, SEEK_END);
- *num = ftell(fp) / sizeof(char16);
- assert(*num >= 1);
- *num -= 1;
-
- char16 *hzs = new char16[*num];
- if (NULL == hzs) {
- fclose(fp);
- return NULL;
- }
-
- fseek(fp, 2, SEEK_SET);
-
- if (fread(hzs, sizeof(char16), *num, fp) != *num) {
- fclose(fp);
- delete [] hzs;
- return NULL;
- }
- fclose(fp);
-
- myqsort(hzs, *num, sizeof(char16), compare_char16);
- return hzs;
-}
-
-bool DictBuilder::hz_in_hanzis_list(const char16 *hzs, size_t hzs_len,
- char16 hz) {
- if (NULL == hzs)
- return false;
-
- char16 *found;
- found = static_cast<char16*>(
- mybsearch(&hz, hzs, hzs_len, sizeof(char16), compare_char16));
- if (NULL == found)
- return false;
-
- assert(*found == hz);
- return true;
-}
-
-// The caller makes sure that the parameters are valid.
-bool DictBuilder::str_in_hanzis_list(const char16 *hzs, size_t hzs_len,
- const char16 *str, size_t str_len) {
- if (NULL == hzs || NULL == str)
- return false;
-
- for (size_t pos = 0; pos < str_len; pos++) {
- if (!hz_in_hanzis_list(hzs, hzs_len, str[pos]))
- return false;
- }
- return true;
-}
-
-void DictBuilder::get_top_lemmas() {
- top_lmas_num_ = 0;
- if (NULL == lemma_arr_)
- return;
-
- for (size_t pos = 0; pos < lemma_num_; pos++) {
- if (0 == top_lmas_num_) {
- top_lmas_[0] = lemma_arr_[pos];
- top_lmas_num_ = 1;
- continue;
+ static const size_t kReadBufLen = 512;
+ static const size_t kSplTableHashLen = 2000;
+
+ // Compare a SingleCharItem, first by Hanzis, then by spelling ids, then by
+ // frequencies.
+ int cmp_scis_hz_splid_freq ( const void *p1, const void *p2 ) {
+ const SingleCharItem *s1, *s2;
+ s1 = static_cast<const SingleCharItem *> ( p1 );
+ s2 = static_cast<const SingleCharItem *> ( p2 );
+ if ( s1->hz < s2->hz )
+ { return -1; }
+ if ( s1->hz > s2->hz )
+ { return 1; }
+ if ( s1->splid.half_splid < s2->splid.half_splid )
+ { return -1; }
+ if ( s1->splid.half_splid > s2->splid.half_splid )
+ { return 1; }
+ if ( s1->splid.full_splid < s2->splid.full_splid )
+ { return -1; }
+ if ( s1->splid.full_splid > s2->splid.full_splid )
+ { return 1; }
+ if ( s1->freq > s2->freq )
+ { return -1; }
+ if ( s1->freq < s2->freq )
+ { return 1; }
+ return 0;
}
- if (lemma_arr_[pos].freq > top_lmas_[top_lmas_num_ - 1].freq) {
- if (kTopScoreLemmaNum > top_lmas_num_)
- top_lmas_num_ += 1;
-
- size_t move_pos;
- for (move_pos = top_lmas_num_ - 1; move_pos > 0; move_pos--) {
- top_lmas_[move_pos] = top_lmas_[move_pos - 1];
- if (0 == move_pos - 1 ||
- (move_pos - 1 > 0 &&
- top_lmas_[move_pos - 2].freq > lemma_arr_[pos].freq)) {
- break;
- }
- }
- assert(move_pos > 0);
- top_lmas_[move_pos - 1] = lemma_arr_[pos];
- } else if (kTopScoreLemmaNum > top_lmas_num_) {
- top_lmas_[top_lmas_num_] = lemma_arr_[pos];
- top_lmas_num_ += 1;
+ int cmp_scis_hz_splid ( const void *p1, const void *p2 ) {
+ const SingleCharItem *s1, *s2;
+ s1 = static_cast<const SingleCharItem *> ( p1 );
+ s2 = static_cast<const SingleCharItem *> ( p2 );
+ if ( s1->hz < s2->hz )
+ { return -1; }
+ if ( s1->hz > s2->hz )
+ { return 1; }
+ if ( s1->splid.half_splid < s2->splid.half_splid )
+ { return -1; }
+ if ( s1->splid.half_splid > s2->splid.half_splid )
+ { return 1; }
+ if ( s1->splid.full_splid < s2->splid.full_splid )
+ { return -1; }
+ if ( s1->splid.full_splid > s2->splid.full_splid )
+ { return 1; }
+ return 0;
}
- }
- if (kPrintDebug0) {
- printf("\n------Top Lemmas------------------\n");
- for (size_t pos = 0; pos < top_lmas_num_; pos++) {
- printf("--%d, idx:%06d, score:%.5f\n", pos, top_lmas_[pos].idx_by_hz,
- top_lmas_[pos].freq);
+ int cmp_lemma_entry_hzs ( const void *p1, const void *p2 ) {
+ size_t size1 = utf16_strlen ( ( ( const LemmaEntry * ) p1 )->hanzi_str );
+ size_t size2 = utf16_strlen ( ( ( const LemmaEntry * ) p2 )->hanzi_str );
+ if ( size1 < size2 )
+ { return -1; }
+ else if ( size1 > size2 )
+ { return 1; }
+ return utf16_strcmp ( ( ( const LemmaEntry * ) p1 )->hanzi_str,
+ ( ( const LemmaEntry * ) p2 )->hanzi_str );
}
- }
-}
-
-void DictBuilder::free_resource() {
- if (NULL != lemma_arr_)
- delete [] lemma_arr_;
-
- if (NULL != scis_)
- delete [] scis_;
-
- if (NULL != lma_nodes_le0_)
- delete [] lma_nodes_le0_;
-
- if (NULL != lma_nodes_ge1_)
- delete [] lma_nodes_ge1_;
-
- if (NULL != homo_idx_buf_)
- delete [] homo_idx_buf_;
-
- if (NULL != spl_table_)
- delete spl_table_;
-
- if (NULL != spl_parser_)
- delete spl_parser_;
-
- lemma_arr_ = NULL;
- scis_ = NULL;
- lma_nodes_le0_ = NULL;
- lma_nodes_ge1_ = NULL;
- homo_idx_buf_ = NULL;
- spl_table_ = NULL;
- spl_parser_ = NULL;
-
- lemma_num_ = 0;
- lma_nds_used_num_le0_ = 0;
- lma_nds_used_num_ge1_ = 0;
- homo_idx_num_eq1_ = 0;
- homo_idx_num_gt1_ = 0;
-}
-
-size_t DictBuilder::read_raw_dict(const char* fn_raw,
- const char *fn_validhzs,
- size_t max_item) {
- if (NULL == fn_raw) return 0;
-
- Utf16Reader utf16_reader;
- if (!utf16_reader.open(fn_raw, kReadBufLen * 10))
- return false;
- char16 read_buf[kReadBufLen];
-
- // Read the number of lemmas in the file
- size_t lemma_num = 240000;
-
- // allocate resource required
- if (!alloc_resource(lemma_num)) {
- utf16_reader.close();
- }
-
- // Read the valid Hanzi list.
- char16 *valid_hzs = NULL;
- size_t valid_hzs_num = 0;
- valid_hzs = read_valid_hanzis(fn_validhzs, &valid_hzs_num);
-
- // Begin reading the lemma entries
- for (size_t i = 0; i < max_item; i++) {
- // read next entry
- if (!utf16_reader.readline(read_buf, kReadBufLen)) {
- lemma_num = i;
- break;
+ int compare_char16 ( const void *p1, const void *p2 ) {
+ if ( * ( ( const char16 * ) p1 ) < * ( ( const char16 * ) p2 ) )
+ { return -1; }
+ if ( * ( ( const char16 * ) p1 ) > * ( ( const char16 * ) p2 ) )
+ { return 1; }
+ return 0;
}
- size_t token_size;
- char16 *token;
- char16 *to_tokenize = read_buf;
-
- // Get the Hanzi string
- token = utf16_strtok(to_tokenize, &token_size, &to_tokenize);
- if (NULL == token) {
- free_resource();
- utf16_reader.close();
- return false;
+ int compare_py ( const void *p1, const void *p2 ) {
+ int ret = utf16_strcmp ( ( ( const LemmaEntry * ) p1 )->spl_idx_arr,
+ ( ( const LemmaEntry * ) p2 )->spl_idx_arr );
+ if ( 0 != ret )
+ { return ret; }
+ return static_cast<int> ( ( ( const LemmaEntry * ) p2 )->freq ) -
+ static_cast<int> ( ( ( const LemmaEntry * ) p1 )->freq );
}
- size_t lemma_size = utf16_strlen(token);
-
- if (lemma_size > kMaxLemmaSize) {
- i--;
- continue;
+ // First hanzi, if the same, then Pinyin
+ int cmp_lemma_entry_hzspys ( const void *p1, const void *p2 ) {
+ size_t size1 = utf16_strlen ( ( ( const LemmaEntry * ) p1 )->hanzi_str );
+ size_t size2 = utf16_strlen ( ( ( const LemmaEntry * ) p2 )->hanzi_str );
+ if ( size1 < size2 )
+ { return -1; }
+ else if ( size1 > size2 )
+ { return 1; }
+ int ret = utf16_strcmp ( ( ( const LemmaEntry * ) p1 )->hanzi_str,
+ ( ( const LemmaEntry * ) p2 )->hanzi_str );
+ if ( 0 != ret )
+ { return ret; }
+ ret = utf16_strcmp ( ( ( const LemmaEntry * ) p1 )->spl_idx_arr,
+ ( ( const LemmaEntry * ) p2 )->spl_idx_arr );
+ return ret;
}
- if (lemma_size > 4) {
- i--;
- continue;
+ int compare_splid2 ( const void *p1, const void *p2 ) {
+ int ret = utf16_strcmp ( ( ( const LemmaEntry * ) p1 )->spl_idx_arr,
+ ( ( const LemmaEntry * ) p2 )->spl_idx_arr );
+ return ret;
}
- // Copy to the lemma entry
- utf16_strcpy(lemma_arr_[i].hanzi_str, token);
-
- lemma_arr_[i].hz_str_len = token_size;
-
- // Get the freq string
- token = utf16_strtok(to_tokenize, &token_size, &to_tokenize);
- if (NULL == token) {
- free_resource();
- utf16_reader.close();
- return false;
- }
- lemma_arr_[i].freq = utf16_atof(token);
-
- if (lemma_size > 1 && lemma_arr_[i].freq < 60) {
- i--;
- continue;
+ DictBuilder::DictBuilder() {
+ lemma_arr_ = NULL;
+ lemma_num_ = 0;
+ scis_ = NULL;
+ scis_num_ = 0;
+ lma_nodes_le0_ = NULL;
+ lma_nodes_ge1_ = NULL;
+ lma_nds_used_num_le0_ = 0;
+ lma_nds_used_num_ge1_ = 0;
+ homo_idx_buf_ = NULL;
+ homo_idx_num_eq1_ = 0;
+ homo_idx_num_gt1_ = 0;
+ top_lmas_ = NULL;
+ top_lmas_num_ = 0;
+ spl_table_ = NULL;
+ spl_parser_ = NULL;
}
- // Get GBK mark, if no valid Hanzi list available, all items which contains
- // GBK characters will be discarded. Otherwise, all items which contains
- // characters outside of the valid Hanzi list will be discarded.
- token = utf16_strtok(to_tokenize, &token_size, &to_tokenize);
- assert(NULL != token);
- int gbk_flag = utf16_atoi(token);
- if (NULL == valid_hzs || 0 == valid_hzs_num) {
- if (0 != gbk_flag) {
- i--;
- continue;
- }
- } else {
- if (!str_in_hanzis_list(valid_hzs, valid_hzs_num,
- lemma_arr_[i].hanzi_str, lemma_arr_[i].hz_str_len)) {
- i--;
- continue;
- }
+ DictBuilder::~DictBuilder() {
+ free_resource();
}
- // Get spelling String
- bool spelling_not_support = false;
- for (size_t hz_pos = 0; hz_pos < (size_t)lemma_arr_[i].hz_str_len;
- hz_pos++) {
- // Get a Pinyin
- token = utf16_strtok(to_tokenize, &token_size, &to_tokenize);
- if (NULL == token) {
+ bool DictBuilder::alloc_resource ( size_t lma_num ) {
+ if ( 0 == lma_num )
+ { return false; }
free_resource();
- utf16_reader.close();
- return false;
- }
-
- assert(utf16_strlen(token) <= kMaxPinyinSize);
-
- utf16_strcpy_tochar(lemma_arr_[i].pinyin_str[hz_pos], token);
-
- format_spelling_str(lemma_arr_[i].pinyin_str[hz_pos]);
-
- // Put the pinyin to the spelling table
- if (!spl_table_->put_spelling(lemma_arr_[i].pinyin_str[hz_pos],
- lemma_arr_[i].freq)) {
- spelling_not_support = true;
- break;
- }
+ lemma_num_ = lma_num;
+ lemma_arr_ = new LemmaEntry[lemma_num_];
+ top_lmas_num_ = 0;
+ top_lmas_ = new LemmaEntry[kTopScoreLemmaNum];
+ // New the scis_ buffer to the possible maximum size.
+ scis_num_ = lemma_num_ * kMaxLemmaSize;
+ scis_ = new SingleCharItem[scis_num_];
+ // The root and first level nodes is less than kMaxSpellingNum + 1
+ lma_nds_used_num_le0_ = 0;
+ lma_nodes_le0_ = new LmaNodeLE0[kMaxSpellingNum + 1];
+ // Other nodes is less than lemma_num
+ lma_nds_used_num_ge1_ = 0;
+ lma_nodes_ge1_ = new LmaNodeGE1[lemma_num_];
+ homo_idx_buf_ = new LemmaIdType[lemma_num_];
+ spl_table_ = new SpellingTable();
+ spl_parser_ = new SpellingParser();
+ if ( NULL == lemma_arr_ || NULL == top_lmas_ ||
+ NULL == scis_ || NULL == spl_table_ ||
+ NULL == spl_parser_ || NULL == lma_nodes_le0_ ||
+ NULL == lma_nodes_ge1_ || NULL == homo_idx_buf_ ) {
+ free_resource();
+ return false;
+ }
+ memset ( lemma_arr_, 0, sizeof ( LemmaEntry ) * lemma_num_ );
+ memset ( scis_, 0, sizeof ( SingleCharItem ) * scis_num_ );
+ memset ( lma_nodes_le0_, 0, sizeof ( LmaNodeLE0 ) * ( kMaxSpellingNum + 1 ) );
+ memset ( lma_nodes_ge1_, 0, sizeof ( LmaNodeGE1 ) * lemma_num_ );
+ memset ( homo_idx_buf_, 0, sizeof ( LemmaIdType ) * lemma_num_ );
+ spl_table_->init_table ( kMaxPinyinSize, kSplTableHashLen, true );
+ return true;
}
- // The whole line must have been parsed fully, otherwise discard this one.
- token = utf16_strtok(to_tokenize, &token_size, &to_tokenize);
- if (spelling_not_support || NULL != token) {
- i--;
- continue;
+ char16 *DictBuilder::read_valid_hanzis ( const char *fn_validhzs, size_t *num ) {
+ if ( NULL == fn_validhzs || NULL == num )
+ { return NULL; }
+ *num = 0;
+ FILE *fp = fopen ( fn_validhzs, "rb" );
+ if ( NULL == fp )
+ { return NULL; }
+ char16 utf16header;
+ if ( fread ( &utf16header, sizeof ( char16 ), 1, fp ) != 1 ||
+ 0xfeff != utf16header ) {
+ fclose ( fp );
+ return NULL;
+ }
+ fseek ( fp, 0, SEEK_END );
+ *num = ftell ( fp ) / sizeof ( char16 );
+ assert ( *num >= 1 );
+ *num -= 1;
+ char16 *hzs = new char16[*num];
+ if ( NULL == hzs ) {
+ fclose ( fp );
+ return NULL;
+ }
+ fseek ( fp, 2, SEEK_SET );
+ if ( fread ( hzs, sizeof ( char16 ), *num, fp ) != *num ) {
+ fclose ( fp );
+ delete [] hzs;
+ return NULL;
+ }
+ fclose ( fp );
+ myqsort ( hzs, *num, sizeof ( char16 ), compare_char16 );
+ return hzs;
}
- }
-
- delete [] valid_hzs;
- utf16_reader.close();
-
- printf("read succesfully, lemma num: %d\n", lemma_num);
-
- return lemma_num;
-}
-
-bool DictBuilder::build_dict(const char *fn_raw,
- const char *fn_validhzs,
- DictTrie *dict_trie) {
- if (NULL == fn_raw || NULL == dict_trie)
- return false;
-
- lemma_num_ = read_raw_dict(fn_raw, fn_validhzs, 240000);
- if (0 == lemma_num_)
- return false;
-
- // Arrange the spelling table, and build a spelling tree
- // The size of an spelling. '\0' is included. If the spelling table is
- // initialized to calculate the spelling scores, the last char in the
- // spelling string will be score, and it is also included in spl_item_size.
- size_t spl_item_size;
- size_t spl_num;
- const char* spl_buf;
- spl_buf = spl_table_->arrange(&spl_item_size, &spl_num);
- if (NULL == spl_buf) {
- free_resource();
- return false;
- }
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
-
- if (!spl_trie.construct(spl_buf, spl_item_size, spl_num,
- spl_table_->get_score_amplifier(),
- spl_table_->get_average_score())) {
- free_resource();
- return false;
- }
-
- printf("spelling tree construct successfully.\n");
-
- // Convert the spelling string to idxs
- for (size_t i = 0; i < lemma_num_; i++) {
- for (size_t hz_pos = 0; hz_pos < (size_t)lemma_arr_[i].hz_str_len;
- hz_pos++) {
- uint16 spl_idxs[2];
- uint16 spl_start_pos[3];
- bool is_pre = true;
- int spl_idx_num =
- spl_parser_->splstr_to_idxs(lemma_arr_[i].pinyin_str[hz_pos],
- strlen(lemma_arr_[i].pinyin_str[hz_pos]),
- spl_idxs, spl_start_pos, 2, is_pre);
- assert(1 == spl_idx_num);
-
- if (spl_trie.is_half_id(spl_idxs[0])) {
- uint16 num = spl_trie.half_to_full(spl_idxs[0], spl_idxs);
- assert(0 != num);
- }
- lemma_arr_[i].spl_idx_arr[hz_pos] = spl_idxs[0];
+ bool DictBuilder::hz_in_hanzis_list ( const char16 *hzs, size_t hzs_len,
+ char16 hz ) {
+ if ( NULL == hzs )
+ { return false; }
+ char16 *found;
+ found = static_cast<char16 *> (
+ mybsearch ( &hz, hzs, hzs_len, sizeof ( char16 ), compare_char16 ) );
+ if ( NULL == found )
+ { return false; }
+ assert ( *found == hz );
+ return true;
}
- }
- // Sort the lemma items according to the hanzi, and give each unique item a
- // id
- sort_lemmas_by_hz();
-
- scis_num_ = build_scis();
-
- // Construct the dict list
- dict_trie->dict_list_ = new DictList();
- bool dl_success = dict_trie->dict_list_->init_list(scis_, scis_num_,
- lemma_arr_, lemma_num_);
- assert(dl_success);
+ // The caller makes sure that the parameters are valid.
+ bool DictBuilder::str_in_hanzis_list ( const char16 *hzs, size_t hzs_len,
+ const char16 *str, size_t str_len ) {
+ if ( NULL == hzs || NULL == str )
+ { return false; }
+ for ( size_t pos = 0; pos < str_len; pos++ ) {
+ if ( !hz_in_hanzis_list ( hzs, hzs_len, str[pos] ) )
+ { return false; }
+ }
+ return true;
+ }
- // Construct the NGram information
- NGram& ngram = NGram::get_instance();
- ngram.build_unigram(lemma_arr_, lemma_num_,
- lemma_arr_[lemma_num_ - 1].idx_by_hz + 1);
+ void DictBuilder::get_top_lemmas() {
+ top_lmas_num_ = 0;
+ if ( NULL == lemma_arr_ )
+ { return; }
+ for ( size_t pos = 0; pos < lemma_num_; pos++ ) {
+ if ( 0 == top_lmas_num_ ) {
+ top_lmas_[0] = lemma_arr_[pos];
+ top_lmas_num_ = 1;
+ continue;
+ }
+ if ( lemma_arr_[pos].freq > top_lmas_[top_lmas_num_ - 1].freq ) {
+ if ( kTopScoreLemmaNum > top_lmas_num_ )
+ { top_lmas_num_ += 1; }
+ size_t move_pos;
+ for ( move_pos = top_lmas_num_ - 1; move_pos > 0; move_pos-- ) {
+ top_lmas_[move_pos] = top_lmas_[move_pos - 1];
+ if ( 0 == move_pos - 1 ||
+ ( move_pos - 1 > 0 &&
+ top_lmas_[move_pos - 2].freq > lemma_arr_[pos].freq ) ) {
+ break;
+ }
+ }
+ assert ( move_pos > 0 );
+ top_lmas_[move_pos - 1] = lemma_arr_[pos];
+ } else if ( kTopScoreLemmaNum > top_lmas_num_ ) {
+ top_lmas_[top_lmas_num_] = lemma_arr_[pos];
+ top_lmas_num_ += 1;
+ }
+ }
+ if ( kPrintDebug0 ) {
+ printf ( "\n------Top Lemmas------------------\n" );
+ for ( size_t pos = 0; pos < top_lmas_num_; pos++ ) {
+ printf ( "--%d, idx:%06d, score:%.5f\n", pos, top_lmas_[pos].idx_by_hz,
+ top_lmas_[pos].freq );
+ }
+ }
+ }
- // sort the lemma items according to the spelling idx string
- myqsort(lemma_arr_, lemma_num_, sizeof(LemmaEntry), compare_py);
+ void DictBuilder::free_resource() {
+ if ( NULL != lemma_arr_ )
+ { delete [] lemma_arr_; }
+ if ( NULL != scis_ )
+ { delete [] scis_; }
+ if ( NULL != lma_nodes_le0_ )
+ { delete [] lma_nodes_le0_; }
+ if ( NULL != lma_nodes_ge1_ )
+ { delete [] lma_nodes_ge1_; }
+ if ( NULL != homo_idx_buf_ )
+ { delete [] homo_idx_buf_; }
+ if ( NULL != spl_table_ )
+ { delete spl_table_; }
+ if ( NULL != spl_parser_ )
+ { delete spl_parser_; }
+ lemma_arr_ = NULL;
+ scis_ = NULL;
+ lma_nodes_le0_ = NULL;
+ lma_nodes_ge1_ = NULL;
+ homo_idx_buf_ = NULL;
+ spl_table_ = NULL;
+ spl_parser_ = NULL;
+ lemma_num_ = 0;
+ lma_nds_used_num_le0_ = 0;
+ lma_nds_used_num_ge1_ = 0;
+ homo_idx_num_eq1_ = 0;
+ homo_idx_num_gt1_ = 0;
+ }
- get_top_lemmas();
+ size_t DictBuilder::read_raw_dict ( const char *fn_raw,
+ const char *fn_validhzs,
+ size_t max_item ) {
+ if ( NULL == fn_raw ) { return 0; }
+ Utf16Reader utf16_reader;
+ if ( !utf16_reader.open ( fn_raw, kReadBufLen * 10 ) )
+ { return false; }
+ char16 read_buf[kReadBufLen];
+ // Read the number of lemmas in the file
+ size_t lemma_num = 240000;
+ // allocate resource required
+ if ( !alloc_resource ( lemma_num ) ) {
+ utf16_reader.close();
+ }
+ // Read the valid Hanzi list.
+ char16 *valid_hzs = NULL;
+ size_t valid_hzs_num = 0;
+ valid_hzs = read_valid_hanzis ( fn_validhzs, &valid_hzs_num );
+ // Begin reading the lemma entries
+ for ( size_t i = 0; i < max_item; i++ ) {
+ // read next entry
+ if ( !utf16_reader.readline ( read_buf, kReadBufLen ) ) {
+ lemma_num = i;
+ break;
+ }
+ size_t token_size;
+ char16 *token;
+ char16 *to_tokenize = read_buf;
+ // Get the Hanzi string
+ token = utf16_strtok ( to_tokenize, &token_size, &to_tokenize );
+ if ( NULL == token ) {
+ free_resource();
+ utf16_reader.close();
+ return false;
+ }
+ size_t lemma_size = utf16_strlen ( token );
+ if ( lemma_size > kMaxLemmaSize ) {
+ i--;
+ continue;
+ }
+ if ( lemma_size > 4 ) {
+ i--;
+ continue;
+ }
+ // Copy to the lemma entry
+ utf16_strcpy ( lemma_arr_[i].hanzi_str, token );
+ lemma_arr_[i].hz_str_len = token_size;
+ // Get the freq string
+ token = utf16_strtok ( to_tokenize, &token_size, &to_tokenize );
+ if ( NULL == token ) {
+ free_resource();
+ utf16_reader.close();
+ return false;
+ }
+ lemma_arr_[i].freq = utf16_atof ( token );
+ if ( lemma_size > 1 && lemma_arr_[i].freq < 60 ) {
+ i--;
+ continue;
+ }
+ // Get GBK mark, if no valid Hanzi list available, all items which contains
+ // GBK characters will be discarded. Otherwise, all items which contains
+ // characters outside of the valid Hanzi list will be discarded.
+ token = utf16_strtok ( to_tokenize, &token_size, &to_tokenize );
+ assert ( NULL != token );
+ int gbk_flag = utf16_atoi ( token );
+ if ( NULL == valid_hzs || 0 == valid_hzs_num ) {
+ if ( 0 != gbk_flag ) {
+ i--;
+ continue;
+ }
+ } else {
+ if ( !str_in_hanzis_list ( valid_hzs, valid_hzs_num,
+ lemma_arr_[i].hanzi_str, lemma_arr_[i].hz_str_len ) ) {
+ i--;
+ continue;
+ }
+ }
+ // Get spelling String
+ bool spelling_not_support = false;
+ for ( size_t hz_pos = 0; hz_pos < ( size_t ) lemma_arr_[i].hz_str_len;
+ hz_pos++ ) {
+ // Get a Pinyin
+ token = utf16_strtok ( to_tokenize, &token_size, &to_tokenize );
+ if ( NULL == token ) {
+ free_resource();
+ utf16_reader.close();
+ return false;
+ }
+ assert ( utf16_strlen ( token ) <= kMaxPinyinSize );
+ utf16_strcpy_tochar ( lemma_arr_[i].pinyin_str[hz_pos], token );
+ format_spelling_str ( lemma_arr_[i].pinyin_str[hz_pos] );
+ // Put the pinyin to the spelling table
+ if ( !spl_table_->put_spelling ( lemma_arr_[i].pinyin_str[hz_pos],
+ lemma_arr_[i].freq ) ) {
+ spelling_not_support = true;
+ break;
+ }
+ }
+ // The whole line must have been parsed fully, otherwise discard this one.
+ token = utf16_strtok ( to_tokenize, &token_size, &to_tokenize );
+ if ( spelling_not_support || NULL != token ) {
+ i--;
+ continue;
+ }
+ }
+ delete [] valid_hzs;
+ utf16_reader.close();
+ printf ( "read succesfully, lemma num: %d\n", lemma_num );
+ return lemma_num;
+ }
+ bool DictBuilder::build_dict ( const char *fn_raw,
+ const char *fn_validhzs,
+ DictTrie *dict_trie ) {
+ if ( NULL == fn_raw || NULL == dict_trie )
+ { return false; }
+ lemma_num_ = read_raw_dict ( fn_raw, fn_validhzs, 240000 );
+ if ( 0 == lemma_num_ )
+ { return false; }
+ // Arrange the spelling table, and build a spelling tree
+ // The size of an spelling. '\0' is included. If the spelling table is
+ // initialized to calculate the spelling scores, the last char in the
+ // spelling string will be score, and it is also included in spl_item_size.
+ size_t spl_item_size;
+ size_t spl_num;
+ const char *spl_buf;
+ spl_buf = spl_table_->arrange ( &spl_item_size, &spl_num );
+ if ( NULL == spl_buf ) {
+ free_resource();
+ return false;
+ }
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ if ( !spl_trie.construct ( spl_buf, spl_item_size, spl_num,
+ spl_table_->get_score_amplifier(),
+ spl_table_->get_average_score() ) ) {
+ free_resource();
+ return false;
+ }
+ printf ( "spelling tree construct successfully.\n" );
+ // Convert the spelling string to idxs
+ for ( size_t i = 0; i < lemma_num_; i++ ) {
+ for ( size_t hz_pos = 0; hz_pos < ( size_t ) lemma_arr_[i].hz_str_len;
+ hz_pos++ ) {
+ uint16 spl_idxs[2];
+ uint16 spl_start_pos[3];
+ bool is_pre = true;
+ int spl_idx_num =
+ spl_parser_->splstr_to_idxs ( lemma_arr_[i].pinyin_str[hz_pos],
+ strlen ( lemma_arr_[i].pinyin_str[hz_pos] ),
+ spl_idxs, spl_start_pos, 2, is_pre );
+ assert ( 1 == spl_idx_num );
+ if ( spl_trie.is_half_id ( spl_idxs[0] ) ) {
+ uint16 num = spl_trie.half_to_full ( spl_idxs[0], spl_idxs );
+ assert ( 0 != num );
+ }
+ lemma_arr_[i].spl_idx_arr[hz_pos] = spl_idxs[0];
+ }
+ }
+ // Sort the lemma items according to the hanzi, and give each unique item a
+ // id
+ sort_lemmas_by_hz();
+ scis_num_ = build_scis();
+ // Construct the dict list
+ dict_trie->dict_list_ = new DictList();
+ bool dl_success = dict_trie->dict_list_->init_list ( scis_, scis_num_,
+ lemma_arr_, lemma_num_ );
+ assert ( dl_success );
+ // Construct the NGram information
+ NGram &ngram = NGram::get_instance();
+ ngram.build_unigram ( lemma_arr_, lemma_num_,
+ lemma_arr_[lemma_num_ - 1].idx_by_hz + 1 );
+ // sort the lemma items according to the spelling idx string
+ myqsort ( lemma_arr_, lemma_num_, sizeof ( LemmaEntry ), compare_py );
+ get_top_lemmas();
#ifdef ___DO_STATISTICS___
- stat_init();
+ stat_init();
#endif
-
- lma_nds_used_num_le0_ = 1; // The root node
- bool dt_success = construct_subset(static_cast<void*>(lma_nodes_le0_),
- lemma_arr_, 0, lemma_num_, 0);
- if (!dt_success) {
- free_resource();
- return false;
- }
-
+ lma_nds_used_num_le0_ = 1; // The root node
+ bool dt_success = construct_subset ( static_cast<void *> ( lma_nodes_le0_ ),
+ lemma_arr_, 0, lemma_num_, 0 );
+ if ( !dt_success ) {
+ free_resource();
+ return false;
+ }
#ifdef ___DO_STATISTICS___
- stat_print();
+ stat_print();
#endif
-
- // Move the node data and homo data to the DictTrie
- dict_trie->root_ = new LmaNodeLE0[lma_nds_used_num_le0_];
- dict_trie->nodes_ge1_ = new LmaNodeGE1[lma_nds_used_num_ge1_];
- size_t lma_idx_num = homo_idx_num_eq1_ + homo_idx_num_gt1_ + top_lmas_num_;
- dict_trie->lma_idx_buf_ = new unsigned char[lma_idx_num * kLemmaIdSize];
- assert(NULL != dict_trie->root_);
- assert(NULL != dict_trie->lma_idx_buf_);
- dict_trie->lma_node_num_le0_ = lma_nds_used_num_le0_;
- dict_trie->lma_node_num_ge1_ = lma_nds_used_num_ge1_;
- dict_trie->lma_idx_buf_len_ = lma_idx_num * kLemmaIdSize;
- dict_trie->top_lmas_num_ = top_lmas_num_;
-
- memcpy(dict_trie->root_, lma_nodes_le0_,
- sizeof(LmaNodeLE0) * lma_nds_used_num_le0_);
- memcpy(dict_trie->nodes_ge1_, lma_nodes_ge1_,
- sizeof(LmaNodeGE1) * lma_nds_used_num_ge1_);
-
- for (size_t pos = 0; pos < homo_idx_num_eq1_ + homo_idx_num_gt1_; pos++) {
- id_to_charbuf(dict_trie->lma_idx_buf_ + pos * kLemmaIdSize,
- homo_idx_buf_[pos]);
- }
-
- for (size_t pos = homo_idx_num_eq1_ + homo_idx_num_gt1_;
- pos < lma_idx_num; pos++) {
- LemmaIdType idx =
- top_lmas_[pos - homo_idx_num_eq1_ - homo_idx_num_gt1_].idx_by_hz;
- id_to_charbuf(dict_trie->lma_idx_buf_ + pos * kLemmaIdSize, idx);
- }
-
- if (kPrintDebug0) {
- printf("homo_idx_num_eq1_: %d\n", homo_idx_num_eq1_);
- printf("homo_idx_num_gt1_: %d\n", homo_idx_num_gt1_);
- printf("top_lmas_num_: %d\n", top_lmas_num_);
- }
-
- free_resource();
-
- if (kPrintDebug0) {
- printf("Building dict succeds\n");
- }
- return dt_success;
-}
-
-void DictBuilder::id_to_charbuf(unsigned char *buf, LemmaIdType id) {
- if (NULL == buf) return;
- for (size_t pos = 0; pos < kLemmaIdSize; pos++) {
- (buf)[pos] = (unsigned char)(id >> (pos * 8));
- }
-}
-
-void DictBuilder::set_son_offset(LmaNodeGE1 *node, size_t offset) {
- node->son_1st_off_l = static_cast<uint16>(offset);
- node->son_1st_off_h = static_cast<unsigned char>(offset >> 16);
-}
-
-void DictBuilder:: set_homo_id_buf_offset(LmaNodeGE1 *node, size_t offset) {
- node->homo_idx_buf_off_l = static_cast<uint16>(offset);
- node->homo_idx_buf_off_h = static_cast<unsigned char>(offset >> 16);
-
-}
-
-// All spelling strings will be converted to upper case, except that
-// spellings started with "ZH"/"CH"/"SH" will be converted to
-// "Zh"/"Ch"/"Sh"
-void DictBuilder::format_spelling_str(char *spl_str) {
- if (NULL == spl_str)
- return;
-
- uint16 pos = 0;
- while ('\0' != spl_str[pos]) {
- if (spl_str[pos] >= 'a' && spl_str[pos] <= 'z')
- spl_str[pos] = spl_str[pos] - 'a' + 'A';
-
- if (1 == pos && 'H' == spl_str[pos]) {
- if ('C' == spl_str[0] || 'S' == spl_str[0] || 'Z' == spl_str[0]) {
- spl_str[pos] = 'h';
- }
+ // Move the node data and homo data to the DictTrie
+ dict_trie->root_ = new LmaNodeLE0[lma_nds_used_num_le0_];
+ dict_trie->nodes_ge1_ = new LmaNodeGE1[lma_nds_used_num_ge1_];
+ size_t lma_idx_num = homo_idx_num_eq1_ + homo_idx_num_gt1_ + top_lmas_num_;
+ dict_trie->lma_idx_buf_ = new unsigned char[lma_idx_num * kLemmaIdSize];
+ assert ( NULL != dict_trie->root_ );
+ assert ( NULL != dict_trie->lma_idx_buf_ );
+ dict_trie->lma_node_num_le0_ = lma_nds_used_num_le0_;
+ dict_trie->lma_node_num_ge1_ = lma_nds_used_num_ge1_;
+ dict_trie->lma_idx_buf_len_ = lma_idx_num * kLemmaIdSize;
+ dict_trie->top_lmas_num_ = top_lmas_num_;
+ memcpy ( dict_trie->root_, lma_nodes_le0_,
+ sizeof ( LmaNodeLE0 ) * lma_nds_used_num_le0_ );
+ memcpy ( dict_trie->nodes_ge1_, lma_nodes_ge1_,
+ sizeof ( LmaNodeGE1 ) * lma_nds_used_num_ge1_ );
+ for ( size_t pos = 0; pos < homo_idx_num_eq1_ + homo_idx_num_gt1_; pos++ ) {
+ id_to_charbuf ( dict_trie->lma_idx_buf_ + pos * kLemmaIdSize,
+ homo_idx_buf_[pos] );
+ }
+ for ( size_t pos = homo_idx_num_eq1_ + homo_idx_num_gt1_;
+ pos < lma_idx_num; pos++ ) {
+ LemmaIdType idx =
+ top_lmas_[pos - homo_idx_num_eq1_ - homo_idx_num_gt1_].idx_by_hz;
+ id_to_charbuf ( dict_trie->lma_idx_buf_ + pos * kLemmaIdSize, idx );
+ }
+ if ( kPrintDebug0 ) {
+ printf ( "homo_idx_num_eq1_: %d\n", homo_idx_num_eq1_ );
+ printf ( "homo_idx_num_gt1_: %d\n", homo_idx_num_gt1_ );
+ printf ( "top_lmas_num_: %d\n", top_lmas_num_ );
+ }
+ free_resource();
+ if ( kPrintDebug0 ) {
+ printf ( "Building dict succeds\n" );
+ }
+ return dt_success;
}
- pos++;
- }
-}
-
-LemmaIdType DictBuilder::sort_lemmas_by_hz() {
- if (NULL == lemma_arr_ || 0 == lemma_num_)
- return 0;
- myqsort(lemma_arr_, lemma_num_, sizeof(LemmaEntry), cmp_lemma_entry_hzs);
-
- lemma_arr_[0].idx_by_hz = 1;
- LemmaIdType idx_max = 1;
- for (size_t i = 1; i < lemma_num_; i++) {
- if (utf16_strcmp(lemma_arr_[i].hanzi_str, lemma_arr_[i-1].hanzi_str)) {
- idx_max++;
- lemma_arr_[i].idx_by_hz = idx_max;
- } else {
- idx_max++;
- lemma_arr_[i].idx_by_hz = idx_max;
+ void DictBuilder::id_to_charbuf ( unsigned char *buf, LemmaIdType id ) {
+ if ( NULL == buf ) { return; }
+ for ( size_t pos = 0; pos < kLemmaIdSize; pos++ ) {
+ ( buf ) [pos] = ( unsigned char ) ( id >> ( pos * 8 ) );
+ }
}
- }
- return idx_max + 1;
-}
-
-size_t DictBuilder::build_scis() {
- if (NULL == scis_ || lemma_num_ * kMaxLemmaSize > scis_num_)
- return 0;
-
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
-
- // This first one is blank, because id 0 is invalid.
- scis_[0].freq = 0;
- scis_[0].hz = 0;
- scis_[0].splid.full_splid = 0;
- scis_[0].splid.half_splid = 0;
- scis_num_ = 1;
- // Copy the hanzis to the buffer
- for (size_t pos = 0; pos < lemma_num_; pos++) {
- size_t hz_num = lemma_arr_[pos].hz_str_len;
- for (size_t hzpos = 0; hzpos < hz_num; hzpos++) {
- scis_[scis_num_].hz = lemma_arr_[pos].hanzi_str[hzpos];
- scis_[scis_num_].splid.full_splid = lemma_arr_[pos].spl_idx_arr[hzpos];
- scis_[scis_num_].splid.half_splid =
- spl_trie.full_to_half(scis_[scis_num_].splid.full_splid);
- if (1 == hz_num)
- scis_[scis_num_].freq = lemma_arr_[pos].freq;
- else
- scis_[scis_num_].freq = 0.000001;
- scis_num_++;
+ void DictBuilder::set_son_offset ( LmaNodeGE1 *node, size_t offset ) {
+ node->son_1st_off_l = static_cast<uint16> ( offset );
+ node->son_1st_off_h = static_cast<unsigned char> ( offset >> 16 );
}
- }
-
- myqsort(scis_, scis_num_, sizeof(SingleCharItem), cmp_scis_hz_splid_freq);
-
- // Remove repeated items
- size_t unique_scis_num = 1;
- for (size_t pos = 1; pos < scis_num_; pos++) {
- if (scis_[pos].hz == scis_[pos - 1].hz &&
- scis_[pos].splid.full_splid == scis_[pos - 1].splid.full_splid)
- continue;
- scis_[unique_scis_num] = scis_[pos];
- scis_[unique_scis_num].splid.half_splid =
- spl_trie.full_to_half(scis_[pos].splid.full_splid);
- unique_scis_num++;
- }
-
- scis_num_ = unique_scis_num;
-
- // Update the lemma list.
- for (size_t pos = 0; pos < lemma_num_; pos++) {
- size_t hz_num = lemma_arr_[pos].hz_str_len;
- for (size_t hzpos = 0; hzpos < hz_num; hzpos++) {
- SingleCharItem key;
- key.hz = lemma_arr_[pos].hanzi_str[hzpos];
- key.splid.full_splid = lemma_arr_[pos].spl_idx_arr[hzpos];
- key.splid.half_splid = spl_trie.full_to_half(key.splid.full_splid);
-
- SingleCharItem *found;
- found = static_cast<SingleCharItem*>(mybsearch(&key, scis_,
- unique_scis_num,
- sizeof(SingleCharItem),
- cmp_scis_hz_splid));
-
- assert(found);
- lemma_arr_[pos].hanzi_scis_ids[hzpos] =
- static_cast<uint16>(found - scis_);
- lemma_arr_[pos].spl_idx_arr[hzpos] = found->splid.full_splid;
+ void DictBuilder:: set_homo_id_buf_offset ( LmaNodeGE1 *node, size_t offset ) {
+ node->homo_idx_buf_off_l = static_cast<uint16> ( offset );
+ node->homo_idx_buf_off_h = static_cast<unsigned char> ( offset >> 16 );
}
- }
- return scis_num_;
-}
-
-bool DictBuilder::construct_subset(void* parent, LemmaEntry* lemma_arr,
- size_t item_start, size_t item_end,
- size_t level) {
- if (level >= kMaxLemmaSize || item_end <= item_start)
- return false;
-
- // 1. Scan for how many sons
- size_t parent_son_num = 0;
- // LemmaNode *son_1st = NULL;
- // parent.num_of_son = 0;
+ // All spelling strings will be converted to upper case, except that
+ // spellings started with "ZH"/"CH"/"SH" will be converted to
+ // "Zh"/"Ch"/"Sh"
+ void DictBuilder::format_spelling_str ( char *spl_str ) {
+ if ( NULL == spl_str )
+ { return; }
+ uint16 pos = 0;
+ while ( '\0' != spl_str[pos] ) {
+ if ( spl_str[pos] >= 'a' && spl_str[pos] <= 'z' )
+ { spl_str[pos] = spl_str[pos] - 'a' + 'A'; }
+ if ( 1 == pos && 'H' == spl_str[pos] ) {
+ if ( 'C' == spl_str[0] || 'S' == spl_str[0] || 'Z' == spl_str[0] ) {
+ spl_str[pos] = 'h';
+ }
+ }
+ pos++;
+ }
+ }
- LemmaEntry *lma_last_start = lemma_arr_ + item_start;
- uint16 spl_idx_node = lma_last_start->spl_idx_arr[level];
+ LemmaIdType DictBuilder::sort_lemmas_by_hz() {
+ if ( NULL == lemma_arr_ || 0 == lemma_num_ )
+ { return 0; }
+ myqsort ( lemma_arr_, lemma_num_, sizeof ( LemmaEntry ), cmp_lemma_entry_hzs );
+ lemma_arr_[0].idx_by_hz = 1;
+ LemmaIdType idx_max = 1;
+ for ( size_t i = 1; i < lemma_num_; i++ ) {
+ if ( utf16_strcmp ( lemma_arr_[i].hanzi_str, lemma_arr_[i - 1].hanzi_str ) ) {
+ idx_max++;
+ lemma_arr_[i].idx_by_hz = idx_max;
+ } else {
+ idx_max++;
+ lemma_arr_[i].idx_by_hz = idx_max;
+ }
+ }
+ return idx_max + 1;
+ }
- // Scan for how many sons to be allocaed
- for (size_t i = item_start + 1; i< item_end; i++) {
- LemmaEntry *lma_current = lemma_arr + i;
- uint16 spl_idx_current = lma_current->spl_idx_arr[level];
- if (spl_idx_current != spl_idx_node) {
- parent_son_num++;
- spl_idx_node = spl_idx_current;
+ size_t DictBuilder::build_scis() {
+ if ( NULL == scis_ || lemma_num_ * kMaxLemmaSize > scis_num_ )
+ { return 0; }
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ // This first one is blank, because id 0 is invalid.
+ scis_[0].freq = 0;
+ scis_[0].hz = 0;
+ scis_[0].splid.full_splid = 0;
+ scis_[0].splid.half_splid = 0;
+ scis_num_ = 1;
+ // Copy the hanzis to the buffer
+ for ( size_t pos = 0; pos < lemma_num_; pos++ ) {
+ size_t hz_num = lemma_arr_[pos].hz_str_len;
+ for ( size_t hzpos = 0; hzpos < hz_num; hzpos++ ) {
+ scis_[scis_num_].hz = lemma_arr_[pos].hanzi_str[hzpos];
+ scis_[scis_num_].splid.full_splid = lemma_arr_[pos].spl_idx_arr[hzpos];
+ scis_[scis_num_].splid.half_splid =
+ spl_trie.full_to_half ( scis_[scis_num_].splid.full_splid );
+ if ( 1 == hz_num )
+ { scis_[scis_num_].freq = lemma_arr_[pos].freq; }
+ else
+ { scis_[scis_num_].freq = 0.000001; }
+ scis_num_++;
+ }
+ }
+ myqsort ( scis_, scis_num_, sizeof ( SingleCharItem ), cmp_scis_hz_splid_freq );
+ // Remove repeated items
+ size_t unique_scis_num = 1;
+ for ( size_t pos = 1; pos < scis_num_; pos++ ) {
+ if ( scis_[pos].hz == scis_[pos - 1].hz &&
+ scis_[pos].splid.full_splid == scis_[pos - 1].splid.full_splid )
+ { continue; }
+ scis_[unique_scis_num] = scis_[pos];
+ scis_[unique_scis_num].splid.half_splid =
+ spl_trie.full_to_half ( scis_[pos].splid.full_splid );
+ unique_scis_num++;
+ }
+ scis_num_ = unique_scis_num;
+ // Update the lemma list.
+ for ( size_t pos = 0; pos < lemma_num_; pos++ ) {
+ size_t hz_num = lemma_arr_[pos].hz_str_len;
+ for ( size_t hzpos = 0; hzpos < hz_num; hzpos++ ) {
+ SingleCharItem key;
+ key.hz = lemma_arr_[pos].hanzi_str[hzpos];
+ key.splid.full_splid = lemma_arr_[pos].spl_idx_arr[hzpos];
+ key.splid.half_splid = spl_trie.full_to_half ( key.splid.full_splid );
+ SingleCharItem *found;
+ found = static_cast<SingleCharItem *> ( mybsearch ( &key, scis_,
+ unique_scis_num,
+ sizeof ( SingleCharItem ),
+ cmp_scis_hz_splid ) );
+ assert ( found );
+ lemma_arr_[pos].hanzi_scis_ids[hzpos] =
+ static_cast<uint16> ( found - scis_ );
+ lemma_arr_[pos].spl_idx_arr[hzpos] = found->splid.full_splid;
+ }
+ }
+ return scis_num_;
}
- }
- parent_son_num++;
+ bool DictBuilder::construct_subset ( void *parent, LemmaEntry *lemma_arr,
+ size_t item_start, size_t item_end,
+ size_t level ) {
+ if ( level >= kMaxLemmaSize || item_end <= item_start )
+ { return false; }
+ // 1. Scan for how many sons
+ size_t parent_son_num = 0;
+ // LemmaNode *son_1st = NULL;
+ // parent.num_of_son = 0;
+ LemmaEntry *lma_last_start = lemma_arr_ + item_start;
+ uint16 spl_idx_node = lma_last_start->spl_idx_arr[level];
+ // Scan for how many sons to be allocaed
+ for ( size_t i = item_start + 1; i < item_end; i++ ) {
+ LemmaEntry *lma_current = lemma_arr + i;
+ uint16 spl_idx_current = lma_current->spl_idx_arr[level];
+ if ( spl_idx_current != spl_idx_node ) {
+ parent_son_num++;
+ spl_idx_node = spl_idx_current;
+ }
+ }
+ parent_son_num++;
#ifdef ___DO_STATISTICS___
- // Use to indicate whether all nodes of this layer have no son.
- bool allson_noson = true;
-
- assert(level < kMaxLemmaSize);
- if (parent_son_num > max_sonbuf_len_[level])
- max_sonbuf_len_[level] = parent_son_num;
-
- total_son_num_[level] += parent_son_num;
- total_sonbuf_num_[level] += 1;
-
- if (parent_son_num == 1)
- sonbufs_num1_++;
- else
- sonbufs_numgt1_++;
- total_lma_node_num_ += parent_son_num;
+ // Use to indicate whether all nodes of this layer have no son.
+ bool allson_noson = true;
+ assert ( level < kMaxLemmaSize );
+ if ( parent_son_num > max_sonbuf_len_[level] )
+ { max_sonbuf_len_[level] = parent_son_num; }
+ total_son_num_[level] += parent_son_num;
+ total_sonbuf_num_[level] += 1;
+ if ( parent_son_num == 1 )
+ { sonbufs_num1_++; }
+ else
+ { sonbufs_numgt1_++; }
+ total_lma_node_num_ += parent_son_num;
#endif
-
- // 2. Update the parent's information
- // Update the parent's son list;
- LmaNodeLE0 *son_1st_le0 = NULL; // only one of le0 or ge1 is used
- LmaNodeGE1 *son_1st_ge1 = NULL; // only one of le0 or ge1 is used.
- if (0 == level) { // the parent is root
- (static_cast<LmaNodeLE0*>(parent))->son_1st_off =
- lma_nds_used_num_le0_;
- son_1st_le0 = lma_nodes_le0_ + lma_nds_used_num_le0_;
- lma_nds_used_num_le0_ += parent_son_num;
-
- assert(parent_son_num <= 65535);
- (static_cast<LmaNodeLE0*>(parent))->num_of_son =
- static_cast<uint16>(parent_son_num);
- } else if (1 == level) { // the parent is a son of root
- (static_cast<LmaNodeLE0*>(parent))->son_1st_off =
- lma_nds_used_num_ge1_;
- son_1st_ge1 = lma_nodes_ge1_ + lma_nds_used_num_ge1_;
- lma_nds_used_num_ge1_ += parent_son_num;
-
- assert(parent_son_num <= 65535);
- (static_cast<LmaNodeLE0*>(parent))->num_of_son =
- static_cast<uint16>(parent_son_num);
- } else {
- set_son_offset((static_cast<LmaNodeGE1*>(parent)),
- lma_nds_used_num_ge1_);
- son_1st_ge1 = lma_nodes_ge1_ + lma_nds_used_num_ge1_;
- lma_nds_used_num_ge1_ += parent_son_num;
-
- assert(parent_son_num <= 255);
- (static_cast<LmaNodeGE1*>(parent))->num_of_son =
- (unsigned char)parent_son_num;
- }
-
- // 3. Now begin to construct the son one by one
- size_t son_pos = 0;
-
- lma_last_start = lemma_arr_ + item_start;
- spl_idx_node = lma_last_start->spl_idx_arr[level];
-
- size_t homo_num = 0;
- if (lma_last_start->spl_idx_arr[level + 1] == 0)
- homo_num = 1;
-
- size_t item_start_next = item_start;
-
- for (size_t i = item_start + 1; i < item_end; i++) {
- LemmaEntry* lma_current = lemma_arr_ + i;
- uint16 spl_idx_current = lma_current->spl_idx_arr[level];
-
- if (spl_idx_current == spl_idx_node) {
- if (lma_current->spl_idx_arr[level + 1] == 0)
- homo_num++;
- } else {
- // Construct a node
- LmaNodeLE0 *node_cur_le0 = NULL; // only one of them is valid
- LmaNodeGE1 *node_cur_ge1 = NULL;
- if (0 == level) {
- node_cur_le0 = son_1st_le0 + son_pos;
- node_cur_le0->spl_idx = spl_idx_node;
- node_cur_le0->homo_idx_buf_off = homo_idx_num_eq1_ + homo_idx_num_gt1_;
- node_cur_le0->son_1st_off = 0;
- homo_idx_num_eq1_ += homo_num;
- } else {
- node_cur_ge1 = son_1st_ge1 + son_pos;
- node_cur_ge1->spl_idx = spl_idx_node;
-
- set_homo_id_buf_offset(node_cur_ge1,
- (homo_idx_num_eq1_ + homo_idx_num_gt1_));
- set_son_offset(node_cur_ge1, 0);
- homo_idx_num_gt1_ += homo_num;
- }
-
- if (homo_num > 0) {
- LemmaIdType* idx_buf = homo_idx_buf_ + homo_idx_num_eq1_ +
- homo_idx_num_gt1_ - homo_num;
- if (0 == level) {
- assert(homo_num <= 65535);
- node_cur_le0->num_of_homo = static_cast<uint16>(homo_num);
+ // 2. Update the parent's information
+ // Update the parent's son list;
+ LmaNodeLE0 *son_1st_le0 = NULL; // only one of le0 or ge1 is used
+ LmaNodeGE1 *son_1st_ge1 = NULL; // only one of le0 or ge1 is used.
+ if ( 0 == level ) { // the parent is root
+ ( static_cast<LmaNodeLE0 *> ( parent ) )->son_1st_off =
+ lma_nds_used_num_le0_;
+ son_1st_le0 = lma_nodes_le0_ + lma_nds_used_num_le0_;
+ lma_nds_used_num_le0_ += parent_son_num;
+ assert ( parent_son_num <= 65535 );
+ ( static_cast<LmaNodeLE0 *> ( parent ) )->num_of_son =
+ static_cast<uint16> ( parent_son_num );
+ } else if ( 1 == level ) { // the parent is a son of root
+ ( static_cast<LmaNodeLE0 *> ( parent ) )->son_1st_off =
+ lma_nds_used_num_ge1_;
+ son_1st_ge1 = lma_nodes_ge1_ + lma_nds_used_num_ge1_;
+ lma_nds_used_num_ge1_ += parent_son_num;
+ assert ( parent_son_num <= 65535 );
+ ( static_cast<LmaNodeLE0 *> ( parent ) )->num_of_son =
+ static_cast<uint16> ( parent_son_num );
} else {
- assert(homo_num <= 255);
- node_cur_ge1->num_of_homo = (unsigned char)homo_num;
+ set_son_offset ( ( static_cast<LmaNodeGE1 *> ( parent ) ),
+ lma_nds_used_num_ge1_ );
+ son_1st_ge1 = lma_nodes_ge1_ + lma_nds_used_num_ge1_;
+ lma_nds_used_num_ge1_ += parent_son_num;
+ assert ( parent_son_num <= 255 );
+ ( static_cast<LmaNodeGE1 *> ( parent ) )->num_of_son =
+ ( unsigned char ) parent_son_num;
}
-
- for (size_t homo_pos = 0; homo_pos < homo_num; homo_pos++) {
- idx_buf[homo_pos] = lemma_arr_[item_start_next + homo_pos].idx_by_hz;
- }
-
+ // 3. Now begin to construct the son one by one
+ size_t son_pos = 0;
+ lma_last_start = lemma_arr_ + item_start;
+ spl_idx_node = lma_last_start->spl_idx_arr[level];
+ size_t homo_num = 0;
+ if ( lma_last_start->spl_idx_arr[level + 1] == 0 )
+ { homo_num = 1; }
+ size_t item_start_next = item_start;
+ for ( size_t i = item_start + 1; i < item_end; i++ ) {
+ LemmaEntry *lma_current = lemma_arr_ + i;
+ uint16 spl_idx_current = lma_current->spl_idx_arr[level];
+ if ( spl_idx_current == spl_idx_node ) {
+ if ( lma_current->spl_idx_arr[level + 1] == 0 )
+ { homo_num++; }
+ } else {
+ // Construct a node
+ LmaNodeLE0 *node_cur_le0 = NULL; // only one of them is valid
+ LmaNodeGE1 *node_cur_ge1 = NULL;
+ if ( 0 == level ) {
+ node_cur_le0 = son_1st_le0 + son_pos;
+ node_cur_le0->spl_idx = spl_idx_node;
+ node_cur_le0->homo_idx_buf_off = homo_idx_num_eq1_ + homo_idx_num_gt1_;
+ node_cur_le0->son_1st_off = 0;
+ homo_idx_num_eq1_ += homo_num;
+ } else {
+ node_cur_ge1 = son_1st_ge1 + son_pos;
+ node_cur_ge1->spl_idx = spl_idx_node;
+ set_homo_id_buf_offset ( node_cur_ge1,
+ ( homo_idx_num_eq1_ + homo_idx_num_gt1_ ) );
+ set_son_offset ( node_cur_ge1, 0 );
+ homo_idx_num_gt1_ += homo_num;
+ }
+ if ( homo_num > 0 ) {
+ LemmaIdType *idx_buf = homo_idx_buf_ + homo_idx_num_eq1_ +
+ homo_idx_num_gt1_ - homo_num;
+ if ( 0 == level ) {
+ assert ( homo_num <= 65535 );
+ node_cur_le0->num_of_homo = static_cast<uint16> ( homo_num );
+ } else {
+ assert ( homo_num <= 255 );
+ node_cur_ge1->num_of_homo = ( unsigned char ) homo_num;
+ }
+ for ( size_t homo_pos = 0; homo_pos < homo_num; homo_pos++ ) {
+ idx_buf[homo_pos] = lemma_arr_[item_start_next + homo_pos].idx_by_hz;
+ }
#ifdef ___DO_STATISTICS___
- if (homo_num > max_homobuf_len_[level])
- max_homobuf_len_[level] = homo_num;
-
- total_homo_num_[level] += homo_num;
+ if ( homo_num > max_homobuf_len_[level] )
+ { max_homobuf_len_[level] = homo_num; }
+ total_homo_num_[level] += homo_num;
#endif
- }
-
- if (i - item_start_next > homo_num) {
- void *next_parent;
- if (0 == level)
- next_parent = static_cast<void*>(node_cur_le0);
- else
- next_parent = static_cast<void*>(node_cur_ge1);
- construct_subset(next_parent, lemma_arr,
- item_start_next + homo_num, i, level + 1);
+ }
+ if ( i - item_start_next > homo_num ) {
+ void *next_parent;
+ if ( 0 == level )
+ { next_parent = static_cast<void *> ( node_cur_le0 ); }
+ else
+ { next_parent = static_cast<void *> ( node_cur_ge1 ); }
+ construct_subset ( next_parent, lemma_arr,
+ item_start_next + homo_num, i, level + 1 );
#ifdef ___DO_STATISTICS___
-
- total_node_hasson_[level] += 1;
- allson_noson = false;
+ total_node_hasson_[level] += 1;
+ allson_noson = false;
#endif
- }
-
- // for the next son
- lma_last_start = lma_current;
- spl_idx_node = spl_idx_current;
- item_start_next = i;
- homo_num = 0;
- if (lma_current->spl_idx_arr[level + 1] == 0)
- homo_num = 1;
-
- son_pos++;
- }
- }
-
- // 4. The last one to construct
- LmaNodeLE0 *node_cur_le0 = NULL; // only one of them is valid
- LmaNodeGE1 *node_cur_ge1 = NULL;
- if (0 == level) {
- node_cur_le0 = son_1st_le0 + son_pos;
- node_cur_le0->spl_idx = spl_idx_node;
- node_cur_le0->homo_idx_buf_off = homo_idx_num_eq1_ + homo_idx_num_gt1_;
- node_cur_le0->son_1st_off = 0;
- homo_idx_num_eq1_ += homo_num;
- } else {
- node_cur_ge1 = son_1st_ge1 + son_pos;
- node_cur_ge1->spl_idx = spl_idx_node;
-
- set_homo_id_buf_offset(node_cur_ge1,
- (homo_idx_num_eq1_ + homo_idx_num_gt1_));
- set_son_offset(node_cur_ge1, 0);
- homo_idx_num_gt1_ += homo_num;
- }
-
- if (homo_num > 0) {
- LemmaIdType* idx_buf = homo_idx_buf_ + homo_idx_num_eq1_ +
- homo_idx_num_gt1_ - homo_num;
- if (0 == level) {
- assert(homo_num <= 65535);
- node_cur_le0->num_of_homo = static_cast<uint16>(homo_num);
- } else {
- assert(homo_num <= 255);
- node_cur_ge1->num_of_homo = (unsigned char)homo_num;
- }
-
- for (size_t homo_pos = 0; homo_pos < homo_num; homo_pos++) {
- idx_buf[homo_pos] = lemma_arr[item_start_next + homo_pos].idx_by_hz;
- }
-
+ }
+ // for the next son
+ lma_last_start = lma_current;
+ spl_idx_node = spl_idx_current;
+ item_start_next = i;
+ homo_num = 0;
+ if ( lma_current->spl_idx_arr[level + 1] == 0 )
+ { homo_num = 1; }
+ son_pos++;
+ }
+ }
+ // 4. The last one to construct
+ LmaNodeLE0 *node_cur_le0 = NULL; // only one of them is valid
+ LmaNodeGE1 *node_cur_ge1 = NULL;
+ if ( 0 == level ) {
+ node_cur_le0 = son_1st_le0 + son_pos;
+ node_cur_le0->spl_idx = spl_idx_node;
+ node_cur_le0->homo_idx_buf_off = homo_idx_num_eq1_ + homo_idx_num_gt1_;
+ node_cur_le0->son_1st_off = 0;
+ homo_idx_num_eq1_ += homo_num;
+ } else {
+ node_cur_ge1 = son_1st_ge1 + son_pos;
+ node_cur_ge1->spl_idx = spl_idx_node;
+ set_homo_id_buf_offset ( node_cur_ge1,
+ ( homo_idx_num_eq1_ + homo_idx_num_gt1_ ) );
+ set_son_offset ( node_cur_ge1, 0 );
+ homo_idx_num_gt1_ += homo_num;
+ }
+ if ( homo_num > 0 ) {
+ LemmaIdType *idx_buf = homo_idx_buf_ + homo_idx_num_eq1_ +
+ homo_idx_num_gt1_ - homo_num;
+ if ( 0 == level ) {
+ assert ( homo_num <= 65535 );
+ node_cur_le0->num_of_homo = static_cast<uint16> ( homo_num );
+ } else {
+ assert ( homo_num <= 255 );
+ node_cur_ge1->num_of_homo = ( unsigned char ) homo_num;
+ }
+ for ( size_t homo_pos = 0; homo_pos < homo_num; homo_pos++ ) {
+ idx_buf[homo_pos] = lemma_arr[item_start_next + homo_pos].idx_by_hz;
+ }
#ifdef ___DO_STATISTICS___
- if (homo_num > max_homobuf_len_[level])
- max_homobuf_len_[level] = homo_num;
-
- total_homo_num_[level] += homo_num;
+ if ( homo_num > max_homobuf_len_[level] )
+ { max_homobuf_len_[level] = homo_num; }
+ total_homo_num_[level] += homo_num;
#endif
- }
-
- if (item_end - item_start_next > homo_num) {
- void *next_parent;
- if (0 == level)
- next_parent = static_cast<void*>(node_cur_le0);
- else
- next_parent = static_cast<void*>(node_cur_ge1);
- construct_subset(next_parent, lemma_arr,
- item_start_next + homo_num, item_end, level + 1);
+ }
+ if ( item_end - item_start_next > homo_num ) {
+ void *next_parent;
+ if ( 0 == level )
+ { next_parent = static_cast<void *> ( node_cur_le0 ); }
+ else
+ { next_parent = static_cast<void *> ( node_cur_ge1 ); }
+ construct_subset ( next_parent, lemma_arr,
+ item_start_next + homo_num, item_end, level + 1 );
#ifdef ___DO_STATISTICS___
-
- total_node_hasson_[level] += 1;
- allson_noson = false;
+ total_node_hasson_[level] += 1;
+ allson_noson = false;
#endif
- }
-
+ }
#ifdef ___DO_STATISTICS___
- if (allson_noson) {
- total_sonbuf_allnoson_[level] += 1;
- total_node_in_sonbuf_allnoson_[level] += parent_son_num;
- }
+ if ( allson_noson ) {
+ total_sonbuf_allnoson_[level] += 1;
+ total_node_in_sonbuf_allnoson_[level] += parent_son_num;
+ }
#endif
-
- assert(son_pos + 1 == parent_son_num);
- return true;
-}
+ assert ( son_pos + 1 == parent_son_num );
+ return true;
+ }
#ifdef ___DO_STATISTICS___
-void DictBuilder::stat_init() {
- memset(max_sonbuf_len_, 0, sizeof(size_t) * kMaxLemmaSize);
- memset(max_homobuf_len_, 0, sizeof(size_t) * kMaxLemmaSize);
- memset(total_son_num_, 0, sizeof(size_t) * kMaxLemmaSize);
- memset(total_node_hasson_, 0, sizeof(size_t) * kMaxLemmaSize);
- memset(total_sonbuf_num_, 0, sizeof(size_t) * kMaxLemmaSize);
- memset(total_sonbuf_allnoson_, 0, sizeof(size_t) * kMaxLemmaSize);
- memset(total_node_in_sonbuf_allnoson_, 0, sizeof(size_t) * kMaxLemmaSize);
- memset(total_homo_num_, 0, sizeof(size_t) * kMaxLemmaSize);
-
- sonbufs_num1_ = 0;
- sonbufs_numgt1_ = 0;
- total_lma_node_num_ = 0;
-}
-
-void DictBuilder::stat_print() {
- printf("\n------------STAT INFO-------------\n");
- printf("[root is layer -1]\n");
- printf(".. max_sonbuf_len per layer(from layer 0):\n ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", max_sonbuf_len_[i]);
- printf("-, \n");
-
- printf(".. max_homobuf_len per layer:\n -, ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", max_homobuf_len_[i]);
- printf("\n");
-
- printf(".. total_son_num per layer:\n ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", total_son_num_[i]);
- printf("-, \n");
-
- printf(".. total_node_hasson per layer:\n 1, ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", total_node_hasson_[i]);
- printf("\n");
-
- printf(".. total_sonbuf_num per layer:\n ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", total_sonbuf_num_[i]);
- printf("-, \n");
-
- printf(".. total_sonbuf_allnoson per layer:\n ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", total_sonbuf_allnoson_[i]);
- printf("-, \n");
-
- printf(".. total_node_in_sonbuf_allnoson per layer:\n ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", total_node_in_sonbuf_allnoson_[i]);
- printf("-, \n");
-
- printf(".. total_homo_num per layer:\n 0, ");
- for (size_t i = 0; i < kMaxLemmaSize; i++)
- printf("%d, ", total_homo_num_[i]);
- printf("\n");
+ void DictBuilder::stat_init() {
+ memset ( max_sonbuf_len_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ memset ( max_homobuf_len_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ memset ( total_son_num_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ memset ( total_node_hasson_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ memset ( total_sonbuf_num_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ memset ( total_sonbuf_allnoson_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ memset ( total_node_in_sonbuf_allnoson_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ memset ( total_homo_num_, 0, sizeof ( size_t ) * kMaxLemmaSize );
+ sonbufs_num1_ = 0;
+ sonbufs_numgt1_ = 0;
+ total_lma_node_num_ = 0;
+ }
- printf(".. son buf allocation number with only 1 son: %d\n", sonbufs_num1_);
- printf(".. son buf allocation number with more than 1 son: %d\n",
- sonbufs_numgt1_);
- printf(".. total lemma node number: %d\n", total_lma_node_num_ + 1);
-}
+ void DictBuilder::stat_print() {
+ printf ( "\n------------STAT INFO-------------\n" );
+ printf ( "[root is layer -1]\n" );
+ printf ( ".. max_sonbuf_len per layer(from layer 0):\n " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", max_sonbuf_len_[i] ); }
+ printf ( "-, \n" );
+ printf ( ".. max_homobuf_len per layer:\n -, " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", max_homobuf_len_[i] ); }
+ printf ( "\n" );
+ printf ( ".. total_son_num per layer:\n " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", total_son_num_[i] ); }
+ printf ( "-, \n" );
+ printf ( ".. total_node_hasson per layer:\n 1, " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", total_node_hasson_[i] ); }
+ printf ( "\n" );
+ printf ( ".. total_sonbuf_num per layer:\n " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", total_sonbuf_num_[i] ); }
+ printf ( "-, \n" );
+ printf ( ".. total_sonbuf_allnoson per layer:\n " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", total_sonbuf_allnoson_[i] ); }
+ printf ( "-, \n" );
+ printf ( ".. total_node_in_sonbuf_allnoson per layer:\n " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", total_node_in_sonbuf_allnoson_[i] ); }
+ printf ( "-, \n" );
+ printf ( ".. total_homo_num per layer:\n 0, " );
+ for ( size_t i = 0; i < kMaxLemmaSize; i++ )
+ { printf ( "%d, ", total_homo_num_[i] ); }
+ printf ( "\n" );
+ printf ( ".. son buf allocation number with only 1 son: %d\n", sonbufs_num1_ );
+ printf ( ".. son buf allocation number with more than 1 son: %d\n",
+ sonbufs_numgt1_ );
+ printf ( ".. total lemma node number: %d\n", total_lma_node_num_ + 1 );
+ }
#endif // ___DO_STATISTICS___
#endif // ___BUILD_MODEL___
diff --git a/jni/share/dictlist.cpp b/jni/share/dictlist.cpp
index aa7905c..0c3fea3 100755
--- a/jni/share/dictlist.cpp
+++ b/jni/share/dictlist.cpp
@@ -24,423 +24,350 @@
namespace ime_pinyin {
-DictList::DictList() {
- initialized_ = false;
- scis_num_ = 0;
- scis_hz_ = NULL;
- scis_splid_ = NULL;
- buf_ = NULL;
- spl_trie_ = SpellingTrie::get_cpinstance();
-
- assert(kMaxLemmaSize == 8);
- cmp_func_[0] = cmp_hanzis_1;
- cmp_func_[1] = cmp_hanzis_2;
- cmp_func_[2] = cmp_hanzis_3;
- cmp_func_[3] = cmp_hanzis_4;
- cmp_func_[4] = cmp_hanzis_5;
- cmp_func_[5] = cmp_hanzis_6;
- cmp_func_[6] = cmp_hanzis_7;
- cmp_func_[7] = cmp_hanzis_8;
-}
-
-DictList::~DictList() {
- free_resource();
-}
-
-bool DictList::alloc_resource(size_t buf_size, size_t scis_num) {
- // Allocate memory
- buf_ = static_cast<char16*>(malloc(buf_size * sizeof(char16)));
- if (NULL == buf_)
- return false;
-
- scis_num_ = scis_num;
-
- scis_hz_ = static_cast<char16*>(malloc(scis_num_ * sizeof(char16)));
- if (NULL == scis_hz_)
- return false;
-
- scis_splid_ = static_cast<SpellingId*>
- (malloc(scis_num_ * sizeof(SpellingId)));
-
- if (NULL == scis_splid_)
- return false;
-
- return true;
-}
+ DictList::DictList() {
+ initialized_ = false;
+ scis_num_ = 0;
+ scis_hz_ = NULL;
+ scis_splid_ = NULL;
+ buf_ = NULL;
+ spl_trie_ = SpellingTrie::get_cpinstance();
+ assert ( kMaxLemmaSize == 8 );
+ cmp_func_[0] = cmp_hanzis_1;
+ cmp_func_[1] = cmp_hanzis_2;
+ cmp_func_[2] = cmp_hanzis_3;
+ cmp_func_[3] = cmp_hanzis_4;
+ cmp_func_[4] = cmp_hanzis_5;
+ cmp_func_[5] = cmp_hanzis_6;
+ cmp_func_[6] = cmp_hanzis_7;
+ cmp_func_[7] = cmp_hanzis_8;
+ }
-void DictList::free_resource() {
- if (NULL != buf_)
- free(buf_);
- buf_ = NULL;
+ DictList::~DictList() {
+ free_resource();
+ }
- if (NULL != scis_hz_)
- free(scis_hz_);
- scis_hz_ = NULL;
+ bool DictList::alloc_resource ( size_t buf_size, size_t scis_num ) {
+ // Allocate memory
+ buf_ = static_cast<char16 *> ( malloc ( buf_size * sizeof ( char16 ) ) );
+ if ( NULL == buf_ )
+ { return false; }
+ scis_num_ = scis_num;
+ scis_hz_ = static_cast<char16 *> ( malloc ( scis_num_ * sizeof ( char16 ) ) );
+ if ( NULL == scis_hz_ )
+ { return false; }
+ scis_splid_ = static_cast<SpellingId *>
+ ( malloc ( scis_num_ * sizeof ( SpellingId ) ) );
+ if ( NULL == scis_splid_ )
+ { return false; }
+ return true;
+ }
- if (NULL != scis_splid_)
- free(scis_splid_);
- scis_splid_ = NULL;
-}
+ void DictList::free_resource() {
+ if ( NULL != buf_ )
+ { free ( buf_ ); }
+ buf_ = NULL;
+ if ( NULL != scis_hz_ )
+ { free ( scis_hz_ ); }
+ scis_hz_ = NULL;
+ if ( NULL != scis_splid_ )
+ { free ( scis_splid_ ); }
+ scis_splid_ = NULL;
+ }
#ifdef ___BUILD_MODEL___
-bool DictList::init_list(const SingleCharItem *scis, size_t scis_num,
- const LemmaEntry *lemma_arr, size_t lemma_num) {
- if (NULL == scis || 0 == scis_num || NULL == lemma_arr || 0 == lemma_num)
- return false;
-
- initialized_ = false;
-
- if (NULL != buf_)
- free(buf_);
-
- // calculate the size
- size_t buf_size = calculate_size(lemma_arr, lemma_num);
- if (0 == buf_size)
- return false;
-
- if (!alloc_resource(buf_size, scis_num))
- return false;
-
- fill_scis(scis, scis_num);
-
- // Copy the related content from the array to inner buffer
- fill_list(lemma_arr, lemma_num);
-
- initialized_ = true;
- return true;
-}
-
-size_t DictList::calculate_size(const LemmaEntry* lemma_arr, size_t lemma_num) {
- size_t last_hz_len = 0;
- size_t list_size = 0;
- size_t id_num = 0;
-
- for (size_t i = 0; i < lemma_num; i++) {
- if (0 == i) {
- last_hz_len = lemma_arr[i].hz_str_len;
-
- assert(last_hz_len > 0);
- assert(lemma_arr[0].idx_by_hz == 1);
-
- id_num++;
- start_pos_[0] = 0;
- start_id_[0] = id_num;
-
- last_hz_len = 1;
- list_size += last_hz_len;
- } else {
- size_t current_hz_len = lemma_arr[i].hz_str_len;
-
- assert(current_hz_len >= last_hz_len);
+ bool DictList::init_list ( const SingleCharItem *scis, size_t scis_num,
+ const LemmaEntry *lemma_arr, size_t lemma_num ) {
+ if ( NULL == scis || 0 == scis_num || NULL == lemma_arr || 0 == lemma_num )
+ { return false; }
+ initialized_ = false;
+ if ( NULL != buf_ )
+ { free ( buf_ ); }
+ // calculate the size
+ size_t buf_size = calculate_size ( lemma_arr, lemma_num );
+ if ( 0 == buf_size )
+ { return false; }
+ if ( !alloc_resource ( buf_size, scis_num ) )
+ { return false; }
+ fill_scis ( scis, scis_num );
+ // Copy the related content from the array to inner buffer
+ fill_list ( lemma_arr, lemma_num );
+ initialized_ = true;
+ return true;
+ }
- if (current_hz_len == last_hz_len) {
- list_size += current_hz_len;
- id_num++;
- } else {
- for (size_t len = last_hz_len; len < current_hz_len - 1; len++) {
- start_pos_[len] = start_pos_[len - 1];
- start_id_[len] = start_id_[len - 1];
+ size_t DictList::calculate_size ( const LemmaEntry *lemma_arr, size_t lemma_num ) {
+ size_t last_hz_len = 0;
+ size_t list_size = 0;
+ size_t id_num = 0;
+ for ( size_t i = 0; i < lemma_num; i++ ) {
+ if ( 0 == i ) {
+ last_hz_len = lemma_arr[i].hz_str_len;
+ assert ( last_hz_len > 0 );
+ assert ( lemma_arr[0].idx_by_hz == 1 );
+ id_num++;
+ start_pos_[0] = 0;
+ start_id_[0] = id_num;
+ last_hz_len = 1;
+ list_size += last_hz_len;
+ } else {
+ size_t current_hz_len = lemma_arr[i].hz_str_len;
+ assert ( current_hz_len >= last_hz_len );
+ if ( current_hz_len == last_hz_len ) {
+ list_size += current_hz_len;
+ id_num++;
+ } else {
+ for ( size_t len = last_hz_len; len < current_hz_len - 1; len++ ) {
+ start_pos_[len] = start_pos_[len - 1];
+ start_id_[len] = start_id_[len - 1];
+ }
+ start_pos_[current_hz_len - 1] = list_size;
+ id_num++;
+ start_id_[current_hz_len - 1] = id_num;
+ last_hz_len = current_hz_len;
+ list_size += current_hz_len;
+ }
+ }
}
-
- start_pos_[current_hz_len - 1] = list_size;
-
- id_num++;
- start_id_[current_hz_len - 1] = id_num;
-
- last_hz_len = current_hz_len;
- list_size += current_hz_len;
- }
+ for ( size_t i = last_hz_len; i <= kMaxLemmaSize; i++ ) {
+ if ( 0 == i ) {
+ start_pos_[0] = 0;
+ start_id_[0] = 1;
+ } else {
+ start_pos_[i] = list_size;
+ start_id_[i] = id_num;
+ }
+ }
+ return start_pos_[kMaxLemmaSize];
}
- }
- for (size_t i = last_hz_len; i <= kMaxLemmaSize; i++) {
- if (0 == i) {
- start_pos_[0] = 0;
- start_id_[0] = 1;
- } else {
- start_pos_[i] = list_size;
- start_id_[i] = id_num;
+ void DictList::fill_scis ( const SingleCharItem *scis, size_t scis_num ) {
+ assert ( scis_num_ == scis_num );
+ for ( size_t pos = 0; pos < scis_num_; pos++ ) {
+ scis_hz_[pos] = scis[pos].hz;
+ scis_splid_[pos] = scis[pos].splid;
+ }
}
- }
-
- return start_pos_[kMaxLemmaSize];
-}
-
-void DictList::fill_scis(const SingleCharItem *scis, size_t scis_num) {
- assert(scis_num_ == scis_num);
-
- for (size_t pos = 0; pos < scis_num_; pos++) {
- scis_hz_[pos] = scis[pos].hz;
- scis_splid_[pos] = scis[pos].splid;
- }
-}
-
-void DictList::fill_list(const LemmaEntry* lemma_arr, size_t lemma_num) {
- size_t current_pos = 0;
-
- utf16_strncpy(buf_, lemma_arr[0].hanzi_str,
- lemma_arr[0].hz_str_len);
- current_pos = lemma_arr[0].hz_str_len;
-
- size_t id_num = 1;
-
- for (size_t i = 1; i < lemma_num; i++) {
- utf16_strncpy(buf_ + current_pos, lemma_arr[i].hanzi_str,
- lemma_arr[i].hz_str_len);
-
- id_num++;
- current_pos += lemma_arr[i].hz_str_len;
- }
-
- assert(current_pos == start_pos_[kMaxLemmaSize]);
- assert(id_num == start_id_[kMaxLemmaSize]);
-}
-
-char16* DictList::find_pos2_startedbyhz(char16 hz_char) {
- char16 *found_2w = static_cast<char16*>
- (mybsearch(&hz_char, buf_ + start_pos_[1],
- (start_pos_[2] - start_pos_[1]) / 2,
- sizeof(char16) * 2, cmp_hanzis_1));
- if (NULL == found_2w)
- return NULL;
-
- while (found_2w > buf_ + start_pos_[1] && *found_2w == *(found_2w - 1))
- found_2w -= 2;
+ void DictList::fill_list ( const LemmaEntry *lemma_arr, size_t lemma_num ) {
+ size_t current_pos = 0;
+ utf16_strncpy ( buf_, lemma_arr[0].hanzi_str,
+ lemma_arr[0].hz_str_len );
+ current_pos = lemma_arr[0].hz_str_len;
+ size_t id_num = 1;
+ for ( size_t i = 1; i < lemma_num; i++ ) {
+ utf16_strncpy ( buf_ + current_pos, lemma_arr[i].hanzi_str,
+ lemma_arr[i].hz_str_len );
+ id_num++;
+ current_pos += lemma_arr[i].hz_str_len;
+ }
+ assert ( current_pos == start_pos_[kMaxLemmaSize] );
+ assert ( id_num == start_id_[kMaxLemmaSize] );
+ }
- return found_2w;
-}
+ char16 *DictList::find_pos2_startedbyhz ( char16 hz_char ) {
+ char16 *found_2w = static_cast<char16 *>
+ ( mybsearch ( &hz_char, buf_ + start_pos_[1],
+ ( start_pos_[2] - start_pos_[1] ) / 2,
+ sizeof ( char16 ) * 2, cmp_hanzis_1 ) );
+ if ( NULL == found_2w )
+ { return NULL; }
+ while ( found_2w > buf_ + start_pos_[1] && *found_2w == * ( found_2w - 1 ) )
+ { found_2w -= 2; }
+ return found_2w;
+ }
#endif // ___BUILD_MODEL___
-char16* DictList::find_pos_startedbyhzs(const char16 last_hzs[],
- size_t word_len, int (*cmp_func)(const void *, const void *)) {
- char16 *found_w = static_cast<char16*>
- (mybsearch(last_hzs, buf_ + start_pos_[word_len - 1],
- (start_pos_[word_len] - start_pos_[word_len - 1])
- / word_len,
- sizeof(char16) * word_len, cmp_func));
-
- if (NULL == found_w)
- return NULL;
-
- while (found_w > buf_ + start_pos_[word_len -1] &&
- cmp_func(found_w, found_w - word_len) == 0)
- found_w -= word_len;
-
- return found_w;
-}
-
-size_t DictList::predict(const char16 last_hzs[], uint16 hzs_len,
- NPredictItem *npre_items, size_t npre_max,
- size_t b4_used) {
- assert(hzs_len <= kMaxPredictSize && hzs_len > 0);
-
- // 1. Prepare work
- int (*cmp_func)(const void *, const void *) = cmp_func_[hzs_len - 1];
-
- NGram& ngram = NGram::get_instance();
-
- size_t item_num = 0;
-
- // 2. Do prediction
- for (uint16 pre_len = 1; pre_len <= kMaxPredictSize + 1 - hzs_len;
- pre_len++) {
- uint16 word_len = hzs_len + pre_len;
- char16 *w_buf = find_pos_startedbyhzs(last_hzs, word_len, cmp_func);
- if (NULL == w_buf)
- continue;
- while (w_buf < buf_ + start_pos_[word_len] &&
- cmp_func(w_buf, last_hzs) == 0 &&
- item_num < npre_max) {
- memset(npre_items + item_num, 0, sizeof(NPredictItem));
- utf16_strncpy(npre_items[item_num].pre_hzs, w_buf + hzs_len, pre_len);
- npre_items[item_num].psb =
- ngram.get_uni_psb((size_t)(w_buf - buf_ - start_pos_[word_len - 1])
- / word_len + start_id_[word_len - 1]);
- npre_items[item_num].his_len = hzs_len;
- item_num++;
- w_buf += word_len;
+ char16 *DictList::find_pos_startedbyhzs ( const char16 last_hzs[],
+ size_t word_len, int ( *cmp_func ) ( const void *, const void * ) ) {
+ char16 *found_w = static_cast<char16 *>
+ ( mybsearch ( last_hzs, buf_ + start_pos_[word_len - 1],
+ ( start_pos_[word_len] - start_pos_[word_len - 1] )
+ / word_len,
+ sizeof ( char16 ) * word_len, cmp_func ) );
+ if ( NULL == found_w )
+ { return NULL; }
+ while ( found_w > buf_ + start_pos_[word_len - 1] &&
+ cmp_func ( found_w, found_w - word_len ) == 0 )
+ { found_w -= word_len; }
+ return found_w;
}
- }
- size_t new_num = 0;
- for (size_t i = 0; i < item_num; i++) {
- // Try to find it in the existing items
- size_t e_pos;
- for (e_pos = 1; e_pos <= b4_used; e_pos++) {
- if (utf16_strncmp((*(npre_items - e_pos)).pre_hzs, npre_items[i].pre_hzs,
- kMaxPredictSize) == 0)
- break;
+ size_t DictList::predict ( const char16 last_hzs[], uint16 hzs_len,
+ NPredictItem *npre_items, size_t npre_max,
+ size_t b4_used ) {
+ assert ( hzs_len <= kMaxPredictSize && hzs_len > 0 );
+ // 1. Prepare work
+ int ( *cmp_func ) ( const void *, const void * ) = cmp_func_[hzs_len - 1];
+ NGram &ngram = NGram::get_instance();
+ size_t item_num = 0;
+ // 2. Do prediction
+ for ( uint16 pre_len = 1; pre_len <= kMaxPredictSize + 1 - hzs_len;
+ pre_len++ ) {
+ uint16 word_len = hzs_len + pre_len;
+ char16 *w_buf = find_pos_startedbyhzs ( last_hzs, word_len, cmp_func );
+ if ( NULL == w_buf )
+ { continue; }
+ while ( w_buf < buf_ + start_pos_[word_len] &&
+ cmp_func ( w_buf, last_hzs ) == 0 &&
+ item_num < npre_max ) {
+ memset ( npre_items + item_num, 0, sizeof ( NPredictItem ) );
+ utf16_strncpy ( npre_items[item_num].pre_hzs, w_buf + hzs_len, pre_len );
+ npre_items[item_num].psb =
+ ngram.get_uni_psb ( ( size_t ) ( w_buf - buf_ - start_pos_[word_len - 1] )
+ / word_len + start_id_[word_len - 1] );
+ npre_items[item_num].his_len = hzs_len;
+ item_num++;
+ w_buf += word_len;
+ }
+ }
+ size_t new_num = 0;
+ for ( size_t i = 0; i < item_num; i++ ) {
+ // Try to find it in the existing items
+ size_t e_pos;
+ for ( e_pos = 1; e_pos <= b4_used; e_pos++ ) {
+ if ( utf16_strncmp ( ( * ( npre_items - e_pos ) ).pre_hzs, npre_items[i].pre_hzs,
+ kMaxPredictSize ) == 0 )
+ { break; }
+ }
+ if ( e_pos <= b4_used )
+ { continue; }
+ // If not found, append it to the buffer
+ npre_items[new_num] = npre_items[i];
+ new_num++;
+ }
+ return new_num;
}
- if (e_pos <= b4_used)
- continue;
-
- // If not found, append it to the buffer
- npre_items[new_num] = npre_items[i];
- new_num++;
- }
-
- return new_num;
-}
-
-uint16 DictList::get_lemma_str(LemmaIdType id_lemma, char16 *str_buf,
- uint16 str_max) {
- if (!initialized_ || id_lemma >= start_id_[kMaxLemmaSize] || NULL == str_buf
- || str_max <= 1)
- return 0;
-
- // Find the range
- for (uint16 i = 0; i < kMaxLemmaSize; i++) {
- if (i + 1 > str_max - 1)
- return 0;
- if (start_id_[i] <= id_lemma && start_id_[i + 1] > id_lemma) {
- size_t id_span = id_lemma - start_id_[i];
- uint16 *buf = buf_ + start_pos_[i] + id_span * (i + 1);
- for (uint16 len = 0; len <= i; len++) {
- str_buf[len] = buf[len];
- }
- str_buf[i+1] = (char16)'\0';
- return i + 1;
+ uint16 DictList::get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf,
+ uint16 str_max ) {
+ if ( !initialized_ || id_lemma >= start_id_[kMaxLemmaSize] || NULL == str_buf
+ || str_max <= 1 )
+ { return 0; }
+ // Find the range
+ for ( uint16 i = 0; i < kMaxLemmaSize; i++ ) {
+ if ( i + 1 > str_max - 1 )
+ { return 0; }
+ if ( start_id_[i] <= id_lemma && start_id_[i + 1] > id_lemma ) {
+ size_t id_span = id_lemma - start_id_[i];
+ uint16 *buf = buf_ + start_pos_[i] + id_span * ( i + 1 );
+ for ( uint16 len = 0; len <= i; len++ ) {
+ str_buf[len] = buf[len];
+ }
+ str_buf[i + 1] = ( char16 ) '\0';
+ return i + 1;
+ }
+ }
+ return 0;
}
- }
- return 0;
-}
-
-uint16 DictList::get_splids_for_hanzi(char16 hanzi, uint16 half_splid,
- uint16 *splids, uint16 max_splids) {
- char16 *hz_found = static_cast<char16*>
- (mybsearch(&hanzi, scis_hz_, scis_num_, sizeof(char16), cmp_hanzis_1));
- assert(NULL != hz_found && hanzi == *hz_found);
-
- // Move to the first one.
- while (hz_found > scis_hz_ && hanzi == *(hz_found - 1))
- hz_found--;
- // First try to found if strict comparison result is not zero.
- char16 *hz_f = hz_found;
- bool strict = false;
- while (hz_f < scis_hz_ + scis_num_ && hanzi == *hz_f) {
- uint16 pos = hz_f - scis_hz_;
- if (0 == half_splid || scis_splid_[pos].half_splid == half_splid) {
- strict = true;
+ uint16 DictList::get_splids_for_hanzi ( char16 hanzi, uint16 half_splid,
+ uint16 *splids, uint16 max_splids ) {
+ char16 *hz_found = static_cast<char16 *>
+ ( mybsearch ( &hanzi, scis_hz_, scis_num_, sizeof ( char16 ), cmp_hanzis_1 ) );
+ assert ( NULL != hz_found && hanzi == *hz_found );
+ // Move to the first one.
+ while ( hz_found > scis_hz_ && hanzi == * ( hz_found - 1 ) )
+ { hz_found--; }
+ // First try to found if strict comparison result is not zero.
+ char16 *hz_f = hz_found;
+ bool strict = false;
+ while ( hz_f < scis_hz_ + scis_num_ && hanzi == *hz_f ) {
+ uint16 pos = hz_f - scis_hz_;
+ if ( 0 == half_splid || scis_splid_[pos].half_splid == half_splid ) {
+ strict = true;
+ }
+ hz_f++;
+ }
+ uint16 found_num = 0;
+ while ( hz_found < scis_hz_ + scis_num_ && hanzi == *hz_found ) {
+ uint16 pos = hz_found - scis_hz_;
+ if ( 0 == half_splid ||
+ ( strict && scis_splid_[pos].half_splid == half_splid ) ||
+ ( !strict && spl_trie_->half_full_compatible ( half_splid,
+ scis_splid_[pos].full_splid ) ) ) {
+ assert ( found_num + 1 < max_splids );
+ splids[found_num] = scis_splid_[pos].full_splid;
+ found_num++;
+ }
+ hz_found++;
+ }
+ return found_num;
}
- hz_f++;
- }
- uint16 found_num = 0;
- while (hz_found < scis_hz_ + scis_num_ && hanzi == *hz_found) {
- uint16 pos = hz_found - scis_hz_;
- if (0 == half_splid ||
- (strict && scis_splid_[pos].half_splid == half_splid) ||
- (!strict && spl_trie_->half_full_compatible(half_splid,
- scis_splid_[pos].full_splid))) {
- assert(found_num + 1 < max_splids);
- splids[found_num] = scis_splid_[pos].full_splid;
- found_num++;
+ LemmaIdType DictList::get_lemma_id ( const char16 *str, uint16 str_len ) {
+ if ( NULL == str || str_len > kMaxLemmaSize )
+ { return 0; }
+ char16 *found = find_pos_startedbyhzs ( str, str_len, cmp_func_[str_len - 1] );
+ if ( NULL == found )
+ { return 0; }
+ assert ( found > buf_ );
+ assert ( static_cast<size_t> ( found - buf_ ) >= start_pos_[str_len - 1] );
+ return static_cast<LemmaIdType>
+ ( start_id_[str_len - 1] +
+ ( found - buf_ - start_pos_[str_len - 1] ) / str_len );
}
- hz_found++;
- }
-
- return found_num;
-}
-
-LemmaIdType DictList::get_lemma_id(const char16 *str, uint16 str_len) {
- if (NULL == str || str_len > kMaxLemmaSize)
- return 0;
-
- char16 *found = find_pos_startedbyhzs(str, str_len, cmp_func_[str_len - 1]);
- if (NULL == found)
- return 0;
-
- assert(found > buf_);
- assert(static_cast<size_t>(found - buf_) >= start_pos_[str_len - 1]);
- return static_cast<LemmaIdType>
- (start_id_[str_len - 1] +
- (found - buf_ - start_pos_[str_len - 1]) / str_len);
-}
-
-void DictList::convert_to_hanzis(char16 *str, uint16 str_len) {
- assert(NULL != str);
-
- for (uint16 str_pos = 0; str_pos < str_len; str_pos++) {
- str[str_pos] = scis_hz_[str[str_pos]];
- }
-}
-
-void DictList::convert_to_scis_ids(char16 *str, uint16 str_len) {
- assert(NULL != str);
- for (uint16 str_pos = 0; str_pos < str_len; str_pos++) {
- str[str_pos] = 0x100;
- }
-}
-
-bool DictList::save_list(FILE *fp) {
- if (!initialized_ || NULL == fp)
- return false;
-
- if (NULL == buf_ || 0 == start_pos_[kMaxLemmaSize] ||
- NULL == scis_hz_ || NULL == scis_splid_ || 0 == scis_num_)
- return false;
-
- if (fwrite(&scis_num_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(start_pos_, sizeof(size_t), kMaxLemmaSize + 1, fp) !=
- kMaxLemmaSize + 1)
- return false;
-
- if (fwrite(start_id_, sizeof(size_t), kMaxLemmaSize + 1, fp) !=
- kMaxLemmaSize + 1)
- return false;
-
- if (fwrite(scis_hz_, sizeof(char16), scis_num_, fp) != scis_num_)
- return false;
-
- if (fwrite(scis_splid_, sizeof(SpellingId), scis_num_, fp) != scis_num_)
- return false;
-
- if (fwrite(buf_, sizeof(char16), start_pos_[kMaxLemmaSize], fp) !=
- start_pos_[kMaxLemmaSize])
- return false;
-
- return true;
-}
-
-bool DictList::load_list(FILE *fp) {
- if (NULL == fp)
- return false;
-
- initialized_ = false;
-
- if (fread(&scis_num_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fread(start_pos_, sizeof(size_t), kMaxLemmaSize + 1, fp) !=
- kMaxLemmaSize + 1)
- return false;
-
- if (fread(start_id_, sizeof(size_t), kMaxLemmaSize + 1, fp) !=
- kMaxLemmaSize + 1)
- return false;
-
- free_resource();
-
- if (!alloc_resource(start_pos_[kMaxLemmaSize], scis_num_))
- return false;
-
- if (fread(scis_hz_, sizeof(char16), scis_num_, fp) != scis_num_)
- return false;
+ void DictList::convert_to_hanzis ( char16 *str, uint16 str_len ) {
+ assert ( NULL != str );
+ for ( uint16 str_pos = 0; str_pos < str_len; str_pos++ ) {
+ str[str_pos] = scis_hz_[str[str_pos]];
+ }
+ }
- if (fread(scis_splid_, sizeof(SpellingId), scis_num_, fp) != scis_num_)
- return false;
+ void DictList::convert_to_scis_ids ( char16 *str, uint16 str_len ) {
+ assert ( NULL != str );
+ for ( uint16 str_pos = 0; str_pos < str_len; str_pos++ ) {
+ str[str_pos] = 0x100;
+ }
+ }
- if (fread(buf_, sizeof(char16), start_pos_[kMaxLemmaSize], fp) !=
- start_pos_[kMaxLemmaSize])
- return false;
+ bool DictList::save_list ( FILE *fp ) {
+ if ( !initialized_ || NULL == fp )
+ { return false; }
+ if ( NULL == buf_ || 0 == start_pos_[kMaxLemmaSize] ||
+ NULL == scis_hz_ || NULL == scis_splid_ || 0 == scis_num_ )
+ { return false; }
+ if ( fwrite ( &scis_num_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( start_pos_, sizeof ( size_t ), kMaxLemmaSize + 1, fp ) !=
+ kMaxLemmaSize + 1 )
+ { return false; }
+ if ( fwrite ( start_id_, sizeof ( size_t ), kMaxLemmaSize + 1, fp ) !=
+ kMaxLemmaSize + 1 )
+ { return false; }
+ if ( fwrite ( scis_hz_, sizeof ( char16 ), scis_num_, fp ) != scis_num_ )
+ { return false; }
+ if ( fwrite ( scis_splid_, sizeof ( SpellingId ), scis_num_, fp ) != scis_num_ )
+ { return false; }
+ if ( fwrite ( buf_, sizeof ( char16 ), start_pos_[kMaxLemmaSize], fp ) !=
+ start_pos_[kMaxLemmaSize] )
+ { return false; }
+ return true;
+ }
- initialized_ = true;
- return true;
-}
+ bool DictList::load_list ( FILE *fp ) {
+ if ( NULL == fp )
+ { return false; }
+ initialized_ = false;
+ if ( fread ( &scis_num_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fread ( start_pos_, sizeof ( size_t ), kMaxLemmaSize + 1, fp ) !=
+ kMaxLemmaSize + 1 )
+ { return false; }
+ if ( fread ( start_id_, sizeof ( size_t ), kMaxLemmaSize + 1, fp ) !=
+ kMaxLemmaSize + 1 )
+ { return false; }
+ free_resource();
+ if ( !alloc_resource ( start_pos_[kMaxLemmaSize], scis_num_ ) )
+ { return false; }
+ if ( fread ( scis_hz_, sizeof ( char16 ), scis_num_, fp ) != scis_num_ )
+ { return false; }
+ if ( fread ( scis_splid_, sizeof ( SpellingId ), scis_num_, fp ) != scis_num_ )
+ { return false; }
+ if ( fread ( buf_, sizeof ( char16 ), start_pos_[kMaxLemmaSize], fp ) !=
+ start_pos_[kMaxLemmaSize] )
+ { return false; }
+ initialized_ = true;
+ return true;
+ }
} // namespace ime_pinyin
diff --git a/jni/share/dicttrie.cpp b/jni/share/dicttrie.cpp
index 88b819d..4566e8e 100755
--- a/jni/share/dicttrie.cpp
+++ b/jni/share/dicttrie.cpp
@@ -25,918 +25,805 @@
namespace ime_pinyin {
-DictTrie::DictTrie() {
- spl_trie_ = SpellingTrie::get_cpinstance();
-
- root_ = NULL;
- splid_le0_index_ = NULL;
- lma_node_num_le0_ = 0;
- nodes_ge1_ = NULL;
- lma_node_num_ge1_ = 0;
- lma_idx_buf_ = NULL;
- lma_idx_buf_len_ = 0;
- total_lma_num_ = 0;
- top_lmas_num_ = 0;
- dict_list_ = NULL;
-
- parsing_marks_ = NULL;
- mile_stones_ = NULL;
- reset_milestones(0, kFirstValidMileStoneHandle);
-}
-
-DictTrie::~DictTrie() {
- free_resource(true);
-}
-
-void DictTrie::free_resource(bool free_dict_list) {
- if (NULL != root_)
- free(root_);
- root_ = NULL;
-
- if (NULL != splid_le0_index_)
- free(splid_le0_index_);
- splid_le0_index_ = NULL;
-
- if (NULL != nodes_ge1_)
- free(nodes_ge1_);
- nodes_ge1_ = NULL;
-
- if (NULL != nodes_ge1_)
- free(nodes_ge1_);
- nodes_ge1_ = NULL;
-
- if (free_dict_list) {
- if (NULL != dict_list_) {
- delete dict_list_;
+ DictTrie::DictTrie() {
+ spl_trie_ = SpellingTrie::get_cpinstance();
+ root_ = NULL;
+ splid_le0_index_ = NULL;
+ lma_node_num_le0_ = 0;
+ nodes_ge1_ = NULL;
+ lma_node_num_ge1_ = 0;
+ lma_idx_buf_ = NULL;
+ lma_idx_buf_len_ = 0;
+ total_lma_num_ = 0;
+ top_lmas_num_ = 0;
+ dict_list_ = NULL;
+ parsing_marks_ = NULL;
+ mile_stones_ = NULL;
+ reset_milestones ( 0, kFirstValidMileStoneHandle );
}
- dict_list_ = NULL;
- }
-
- if (parsing_marks_)
- delete [] parsing_marks_;
- parsing_marks_ = NULL;
- if (mile_stones_)
- delete [] mile_stones_;
- mile_stones_ = NULL;
+ DictTrie::~DictTrie() {
+ free_resource ( true );
+ }
- reset_milestones(0, kFirstValidMileStoneHandle);
-}
+ void DictTrie::free_resource ( bool free_dict_list ) {
+ if ( NULL != root_ )
+ { free ( root_ ); }
+ root_ = NULL;
+ if ( NULL != splid_le0_index_ )
+ { free ( splid_le0_index_ ); }
+ splid_le0_index_ = NULL;
+ if ( NULL != nodes_ge1_ )
+ { free ( nodes_ge1_ ); }
+ nodes_ge1_ = NULL;
+ if ( NULL != nodes_ge1_ )
+ { free ( nodes_ge1_ ); }
+ nodes_ge1_ = NULL;
+ if ( free_dict_list ) {
+ if ( NULL != dict_list_ ) {
+ delete dict_list_;
+ }
+ dict_list_ = NULL;
+ }
+ if ( parsing_marks_ )
+ { delete [] parsing_marks_; }
+ parsing_marks_ = NULL;
+ if ( mile_stones_ )
+ { delete [] mile_stones_; }
+ mile_stones_ = NULL;
+ reset_milestones ( 0, kFirstValidMileStoneHandle );
+ }
-inline size_t DictTrie::get_son_offset(const LmaNodeGE1 *node) {
- return ((size_t)node->son_1st_off_l + ((size_t)node->son_1st_off_h << 16));
-}
+ inline size_t DictTrie::get_son_offset ( const LmaNodeGE1 *node ) {
+ return ( ( size_t ) node->son_1st_off_l + ( ( size_t ) node->son_1st_off_h << 16 ) );
+ }
-inline size_t DictTrie::get_homo_idx_buf_offset(const LmaNodeGE1 *node) {
- return ((size_t)node->homo_idx_buf_off_l +
- ((size_t)node->homo_idx_buf_off_h << 16));
-}
+ inline size_t DictTrie::get_homo_idx_buf_offset ( const LmaNodeGE1 *node ) {
+ return ( ( size_t ) node->homo_idx_buf_off_l +
+ ( ( size_t ) node->homo_idx_buf_off_h << 16 ) );
+ }
-inline LemmaIdType DictTrie::get_lemma_id(size_t id_offset) {
- LemmaIdType id = 0;
- for (uint16 pos = kLemmaIdSize - 1; pos > 0; pos--)
- id = (id << 8) + lma_idx_buf_[id_offset * kLemmaIdSize + pos];
- id = (id << 8) + lma_idx_buf_[id_offset * kLemmaIdSize];
- return id;
-}
+ inline LemmaIdType DictTrie::get_lemma_id ( size_t id_offset ) {
+ LemmaIdType id = 0;
+ for ( uint16 pos = kLemmaIdSize - 1; pos > 0; pos-- )
+ { id = ( id << 8 ) + lma_idx_buf_[id_offset * kLemmaIdSize + pos]; }
+ id = ( id << 8 ) + lma_idx_buf_[id_offset * kLemmaIdSize];
+ return id;
+ }
#ifdef ___BUILD_MODEL___
-bool DictTrie::build_dict(const char* fn_raw, const char* fn_validhzs) {
- DictBuilder* dict_builder = new DictBuilder();
-
- free_resource(true);
-
- return dict_builder->build_dict(fn_raw, fn_validhzs, this);
-}
-
-bool DictTrie::save_dict(FILE *fp) {
- if (NULL == fp)
- return false;
-
- if (fwrite(&lma_node_num_le0_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(&lma_node_num_ge1_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(&lma_idx_buf_len_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(&top_lmas_num_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(root_, sizeof(LmaNodeLE0), lma_node_num_le0_, fp)
- != lma_node_num_le0_)
- return false;
-
- if (fwrite(nodes_ge1_, sizeof(LmaNodeGE1), lma_node_num_ge1_, fp)
- != lma_node_num_ge1_)
- return false;
-
- if (fwrite(lma_idx_buf_, sizeof(unsigned char), lma_idx_buf_len_, fp) !=
- lma_idx_buf_len_)
- return false;
-
- return true;
-}
-
-bool DictTrie::save_dict(const char *filename) {
- if (NULL == filename)
- return false;
-
- if (NULL == root_ || NULL == dict_list_)
- return false;
-
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- NGram &ngram = NGram::get_instance();
-
- FILE *fp = fopen(filename, "wb");
- if (NULL == fp)
- return false;
-
- if (!spl_trie.save_spl_trie(fp) || !dict_list_->save_list(fp) ||
- !save_dict(fp) || !ngram.save_ngram(fp)) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
- return true;
-}
-#endif // ___BUILD_MODEL___
-
-bool DictTrie::load_dict(FILE *fp) {
- if (NULL == fp)
- return false;
-
- if (fread(&lma_node_num_le0_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fread(&lma_node_num_ge1_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fread(&lma_idx_buf_len_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fread(&top_lmas_num_, sizeof(size_t), 1, fp) != 1 ||
- top_lmas_num_ >= lma_idx_buf_len_)
- return false;
-
- free_resource(false);
-
- root_ = static_cast<LmaNodeLE0*>
- (malloc(lma_node_num_le0_ * sizeof(LmaNodeLE0)));
- nodes_ge1_ = static_cast<LmaNodeGE1*>
- (malloc(lma_node_num_ge1_ * sizeof(LmaNodeGE1)));
- lma_idx_buf_ = (unsigned char*)malloc(lma_idx_buf_len_);
- total_lma_num_ = lma_idx_buf_len_ / kLemmaIdSize;
-
- size_t buf_size = SpellingTrie::get_instance().get_spelling_num() + 1;
- assert(lma_node_num_le0_ <= buf_size);
- splid_le0_index_ = static_cast<uint16*>(malloc(buf_size * sizeof(uint16)));
-
- // Init the space for parsing.
- parsing_marks_ = new ParsingMark[kMaxParsingMark];
- mile_stones_ = new MileStone[kMaxMileStone];
- reset_milestones(0, kFirstValidMileStoneHandle);
-
- if (NULL == root_ || NULL == nodes_ge1_ || NULL == lma_idx_buf_ ||
- NULL == splid_le0_index_ || NULL == parsing_marks_ ||
- NULL == mile_stones_) {
- free_resource(false);
- return false;
- }
-
- if (fread(root_, sizeof(LmaNodeLE0), lma_node_num_le0_, fp)
- != lma_node_num_le0_)
- return false;
-
- if (fread(nodes_ge1_, sizeof(LmaNodeGE1), lma_node_num_ge1_, fp)
- != lma_node_num_ge1_)
- return false;
-
- if (fread(lma_idx_buf_, sizeof(unsigned char), lma_idx_buf_len_, fp) !=
- lma_idx_buf_len_)
- return false;
-
- // The quick index for the first level sons
- uint16 last_splid = kFullSplIdStart;
- size_t last_pos = 0;
- for (size_t i = 1; i < lma_node_num_le0_; i++) {
- for (uint16 splid = last_splid; splid < root_[i].spl_idx; splid++)
- splid_le0_index_[splid - kFullSplIdStart] = last_pos;
-
- splid_le0_index_[root_[i].spl_idx - kFullSplIdStart] =
- static_cast<uint16>(i);
- last_splid = root_[i].spl_idx;
- last_pos = i;
- }
-
- for (uint16 splid = last_splid + 1;
- splid < buf_size + kFullSplIdStart; splid++) {
- assert(static_cast<size_t>(splid - kFullSplIdStart) < buf_size);
- splid_le0_index_[splid - kFullSplIdStart] = last_pos + 1;
- }
-
- return true;
-}
-
-bool DictTrie::load_dict(const char *filename, LemmaIdType start_id,
- LemmaIdType end_id) {
- if (NULL == filename || end_id <= start_id)
- return false;
-
- FILE *fp = fopen(filename, "rb");
- if (NULL == fp)
- return false;
-
- free_resource(true);
-
- dict_list_ = new DictList();
- if (NULL == dict_list_) {
- fclose(fp);
- return false;
- }
-
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- NGram &ngram = NGram::get_instance();
-
- if (!spl_trie.load_spl_trie(fp) || !dict_list_->load_list(fp) ||
- !load_dict(fp) || !ngram.load_ngram(fp) ||
- total_lma_num_ > end_id - start_id + 1) {
- free_resource(true);
- fclose(fp);
- return false;
- }
-
- fclose(fp);
- return true;
-}
-
-bool DictTrie::load_dict_fd(int sys_fd, long start_offset,
- long length, LemmaIdType start_id,
- LemmaIdType end_id) {
- if (start_offset < 0 || length <= 0 || end_id <= start_id)
- return false;
-
- FILE *fp = fdopen(sys_fd, "rb");
- if (NULL == fp)
- return false;
-
- if (-1 == fseek(fp, start_offset, SEEK_SET)) {
- fclose(fp);
- return false;
- }
-
- free_resource(true);
-
- dict_list_ = new DictList();
- if (NULL == dict_list_) {
- fclose(fp);
- return false;
- }
-
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- NGram &ngram = NGram::get_instance();
-
- if (!spl_trie.load_spl_trie(fp) || !dict_list_->load_list(fp) ||
- !load_dict(fp) || !ngram.load_ngram(fp) ||
- ftell(fp) < start_offset + length ||
- total_lma_num_ > end_id - start_id + 1) {
- free_resource(true);
- fclose(fp);
- return false;
- }
-
- fclose(fp);
- return true;
-}
-
-size_t DictTrie::fill_lpi_buffer(LmaPsbItem lpi_items[], size_t lpi_max,
- LmaNodeLE0 *node) {
- size_t lpi_num = 0;
- NGram& ngram = NGram::get_instance();
- for (size_t homo = 0; homo < (size_t)node->num_of_homo; homo++) {
- lpi_items[lpi_num].id = get_lemma_id(node->homo_idx_buf_off +
- homo);
- lpi_items[lpi_num].lma_len = 1;
- lpi_items[lpi_num].psb =
- static_cast<LmaScoreType>(ngram.get_uni_psb(lpi_items[lpi_num].id));
- lpi_num++;
- if (lpi_num >= lpi_max)
- break;
- }
-
- return lpi_num;
-}
-
-size_t DictTrie::fill_lpi_buffer(LmaPsbItem lpi_items[], size_t lpi_max,
- size_t homo_buf_off, LmaNodeGE1 *node,
- uint16 lma_len) {
- size_t lpi_num = 0;
- NGram& ngram = NGram::get_instance();
- for (size_t homo = 0; homo < (size_t)node->num_of_homo; homo++) {
- lpi_items[lpi_num].id = get_lemma_id(homo_buf_off + homo);
- lpi_items[lpi_num].lma_len = lma_len;
- lpi_items[lpi_num].psb =
- static_cast<LmaScoreType>(ngram.get_uni_psb(lpi_items[lpi_num].id));
- lpi_num++;
- if (lpi_num >= lpi_max)
- break;
- }
-
- return lpi_num;
-}
-
-void DictTrie::reset_milestones(uint16 from_step, MileStoneHandle from_handle) {
- if (0 == from_step) {
- parsing_marks_pos_ = 0;
- mile_stones_pos_ = kFirstValidMileStoneHandle;
- } else {
- if (from_handle > 0 && from_handle < mile_stones_pos_) {
- mile_stones_pos_ = from_handle;
-
- MileStone *mile_stone = mile_stones_ + from_handle;
- parsing_marks_pos_ = mile_stone->mark_start;
+ bool DictTrie::build_dict ( const char *fn_raw, const char *fn_validhzs ) {
+ DictBuilder *dict_builder = new DictBuilder();
+ free_resource ( true );
+ return dict_builder->build_dict ( fn_raw, fn_validhzs, this );
}
- }
-}
-
-MileStoneHandle DictTrie::extend_dict(MileStoneHandle from_handle,
- const DictExtPara *dep,
- LmaPsbItem *lpi_items, size_t lpi_max,
- size_t *lpi_num) {
- if (NULL == dep)
- return 0;
-
- // from LmaNodeLE0 (root) to LmaNodeLE0
- if (0 == from_handle) {
- assert(0 == dep->splids_extended);
- return extend_dict0(from_handle, dep, lpi_items, lpi_max, lpi_num);
- }
-
- // from LmaNodeLE0 to LmaNodeGE1
- if (1 == dep->splids_extended)
- return extend_dict1(from_handle, dep, lpi_items, lpi_max, lpi_num);
-
- // From LmaNodeGE1 to LmaNodeGE1
- return extend_dict2(from_handle, dep, lpi_items, lpi_max, lpi_num);
-}
-
-MileStoneHandle DictTrie::extend_dict0(MileStoneHandle from_handle,
- const DictExtPara *dep,
- LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num) {
- assert(NULL != dep && 0 == from_handle);
- *lpi_num = 0;
- MileStoneHandle ret_handle = 0;
- uint16 splid = dep->splids[dep->splids_extended];
- uint16 id_start = dep->id_start;
- uint16 id_num = dep->id_num;
-
- LpiCache& lpi_cache = LpiCache::get_instance();
- bool cached = lpi_cache.is_cached(splid);
-
- // 2. Begin exgtending
- // 2.1 Get the LmaPsbItem list
- LmaNodeLE0 *node = root_;
- size_t son_start = splid_le0_index_[id_start - kFullSplIdStart];
- size_t son_end = splid_le0_index_[id_start + id_num - kFullSplIdStart];
- for (size_t son_pos = son_start; son_pos < son_end; son_pos++) {
- assert(1 == node->son_1st_off);
- LmaNodeLE0 *son = root_ + son_pos;
- assert(son->spl_idx >= id_start && son->spl_idx < id_start + id_num);
-
- if (!cached && *lpi_num < lpi_max) {
- bool need_lpi = true;
- if (spl_trie_->is_half_id_yunmu(splid) && son_pos != son_start)
- need_lpi = false;
-
- if (need_lpi)
- *lpi_num += fill_lpi_buffer(lpi_items + (*lpi_num),
- lpi_max - *lpi_num, son);
+ bool DictTrie::save_dict ( FILE *fp ) {
+ if ( NULL == fp )
+ { return false; }
+ if ( fwrite ( &lma_node_num_le0_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( &lma_node_num_ge1_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( &lma_idx_buf_len_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( &top_lmas_num_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( root_, sizeof ( LmaNodeLE0 ), lma_node_num_le0_, fp )
+ != lma_node_num_le0_ )
+ { return false; }
+ if ( fwrite ( nodes_ge1_, sizeof ( LmaNodeGE1 ), lma_node_num_ge1_, fp )
+ != lma_node_num_ge1_ )
+ { return false; }
+ if ( fwrite ( lma_idx_buf_, sizeof ( unsigned char ), lma_idx_buf_len_, fp ) !=
+ lma_idx_buf_len_ )
+ { return false; }
+ return true;
}
- // If necessary, fill in a new mile stone.
- if (son->spl_idx == id_start) {
- if (mile_stones_pos_ < kMaxMileStone &&
- parsing_marks_pos_ < kMaxParsingMark) {
- parsing_marks_[parsing_marks_pos_].node_offset = son_pos;
- parsing_marks_[parsing_marks_pos_].node_num = id_num;
- mile_stones_[mile_stones_pos_].mark_start = parsing_marks_pos_;
- mile_stones_[mile_stones_pos_].mark_num = 1;
- ret_handle = mile_stones_pos_;
- parsing_marks_pos_++;
- mile_stones_pos_++;
- }
+ bool DictTrie::save_dict ( const char *filename ) {
+ if ( NULL == filename )
+ { return false; }
+ if ( NULL == root_ || NULL == dict_list_ )
+ { return false; }
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ NGram &ngram = NGram::get_instance();
+ FILE *fp = fopen ( filename, "wb" );
+ if ( NULL == fp )
+ { return false; }
+ if ( !spl_trie.save_spl_trie ( fp ) || !dict_list_->save_list ( fp ) ||
+ !save_dict ( fp ) || !ngram.save_ngram ( fp ) ) {
+ fclose ( fp );
+ return false;
+ }
+ fclose ( fp );
+ return true;
}
+#endif // ___BUILD_MODEL___
- if (son->spl_idx >= id_start + id_num -1)
- break;
- }
-
- // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_,
- // mile_stones_pos_);
- return ret_handle;
-}
-
-MileStoneHandle DictTrie::extend_dict1(MileStoneHandle from_handle,
- const DictExtPara *dep,
- LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num) {
- assert(NULL != dep && from_handle > 0 && from_handle < mile_stones_pos_);
-
- MileStoneHandle ret_handle = 0;
-
- // 1. If this is a half Id, get its corresponding full starting Id and
- // number of full Id.
- size_t ret_val = 0;
-
- uint16 id_start = dep->id_start;
- uint16 id_num = dep->id_num;
-
- // 2. Begin extending.
- MileStone *mile_stone = mile_stones_ + from_handle;
-
- for (uint16 h_pos = 0; h_pos < mile_stone->mark_num; h_pos++) {
- ParsingMark p_mark = parsing_marks_[mile_stone->mark_start + h_pos];
- uint16 ext_num = p_mark.node_num;
- for (uint16 ext_pos = 0; ext_pos < ext_num; ext_pos++) {
- LmaNodeLE0 *node = root_ + p_mark.node_offset + ext_pos;
- size_t found_start = 0;
- size_t found_num = 0;
- for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son; son_pos++) {
- assert(node->son_1st_off <= lma_node_num_ge1_);
- LmaNodeGE1 *son = nodes_ge1_ + node->son_1st_off + son_pos;
- if (son->spl_idx >= id_start
- && son->spl_idx < id_start + id_num) {
- if (*lpi_num < lpi_max) {
- size_t homo_buf_off = get_homo_idx_buf_offset(son);
- *lpi_num += fill_lpi_buffer(lpi_items + (*lpi_num),
- lpi_max - *lpi_num, homo_buf_off, son,
- 2);
- }
-
- // If necessary, fill in the new DTMI
- if (0 == found_num) {
- found_start = son_pos;
- }
- found_num++;
+ bool DictTrie::load_dict ( FILE *fp ) {
+ if ( NULL == fp )
+ { return false; }
+ if ( fread ( &lma_node_num_le0_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fread ( &lma_node_num_ge1_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fread ( &lma_idx_buf_len_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fread ( &top_lmas_num_, sizeof ( size_t ), 1, fp ) != 1 ||
+ top_lmas_num_ >= lma_idx_buf_len_ )
+ { return false; }
+ free_resource ( false );
+ root_ = static_cast<LmaNodeLE0 *>
+ ( malloc ( lma_node_num_le0_ * sizeof ( LmaNodeLE0 ) ) );
+ nodes_ge1_ = static_cast<LmaNodeGE1 *>
+ ( malloc ( lma_node_num_ge1_ * sizeof ( LmaNodeGE1 ) ) );
+ lma_idx_buf_ = ( unsigned char * ) malloc ( lma_idx_buf_len_ );
+ total_lma_num_ = lma_idx_buf_len_ / kLemmaIdSize;
+ size_t buf_size = SpellingTrie::get_instance().get_spelling_num() + 1;
+ assert ( lma_node_num_le0_ <= buf_size );
+ splid_le0_index_ = static_cast<uint16 *> ( malloc ( buf_size * sizeof ( uint16 ) ) );
+ // Init the space for parsing.
+ parsing_marks_ = new ParsingMark[kMaxParsingMark];
+ mile_stones_ = new MileStone[kMaxMileStone];
+ reset_milestones ( 0, kFirstValidMileStoneHandle );
+ if ( NULL == root_ || NULL == nodes_ge1_ || NULL == lma_idx_buf_ ||
+ NULL == splid_le0_index_ || NULL == parsing_marks_ ||
+ NULL == mile_stones_ ) {
+ free_resource ( false );
+ return false;
}
- if (son->spl_idx >= id_start + id_num - 1 || son_pos ==
- (size_t)node->num_of_son - 1) {
- if (found_num > 0) {
- if (mile_stones_pos_ < kMaxMileStone &&
- parsing_marks_pos_ < kMaxParsingMark) {
- parsing_marks_[parsing_marks_pos_].node_offset =
- node->son_1st_off + found_start;
- parsing_marks_[parsing_marks_pos_].node_num = found_num;
- if (0 == ret_val)
- mile_stones_[mile_stones_pos_].mark_start =
- parsing_marks_pos_;
- parsing_marks_pos_++;
- }
-
- ret_val++;
- }
- break;
- } // for son_pos
- } // for ext_pos
- } // for h_pos
- }
-
- if (ret_val > 0) {
- mile_stones_[mile_stones_pos_].mark_num = ret_val;
- ret_handle = mile_stones_pos_;
- mile_stones_pos_++;
- ret_val = 1;
- }
-
- // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_,
- // mile_stones_pos_);
- return ret_handle;
-}
-
-MileStoneHandle DictTrie::extend_dict2(MileStoneHandle from_handle,
- const DictExtPara *dep,
- LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num) {
- assert(NULL != dep && from_handle > 0 && from_handle < mile_stones_pos_);
-
- MileStoneHandle ret_handle = 0;
-
- // 1. If this is a half Id, get its corresponding full starting Id and
- // number of full Id.
- size_t ret_val = 0;
-
- uint16 id_start = dep->id_start;
- uint16 id_num = dep->id_num;
-
- // 2. Begin extending.
- MileStone *mile_stone = mile_stones_ + from_handle;
-
- for (uint16 h_pos = 0; h_pos < mile_stone->mark_num; h_pos++) {
- ParsingMark p_mark = parsing_marks_[mile_stone->mark_start + h_pos];
- uint16 ext_num = p_mark.node_num;
- for (uint16 ext_pos = 0; ext_pos < ext_num; ext_pos++) {
- LmaNodeGE1 *node = nodes_ge1_ + p_mark.node_offset + ext_pos;
- size_t found_start = 0;
- size_t found_num = 0;
-
- for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son; son_pos++) {
- assert(node->son_1st_off_l > 0 || node->son_1st_off_h > 0);
- LmaNodeGE1 *son = nodes_ge1_ + get_son_offset(node) + son_pos;
- if (son->spl_idx >= id_start
- && son->spl_idx < id_start + id_num) {
- if (*lpi_num < lpi_max) {
- size_t homo_buf_off = get_homo_idx_buf_offset(son);
- *lpi_num += fill_lpi_buffer(lpi_items + (*lpi_num),
- lpi_max - *lpi_num, homo_buf_off, son,
- dep->splids_extended + 1);
- }
-
- // If necessary, fill in the new DTMI
- if (0 == found_num) {
- found_start = son_pos;
- }
- found_num++;
+ if ( fread ( root_, sizeof ( LmaNodeLE0 ), lma_node_num_le0_, fp )
+ != lma_node_num_le0_ )
+ { return false; }
+ if ( fread ( nodes_ge1_, sizeof ( LmaNodeGE1 ), lma_node_num_ge1_, fp )
+ != lma_node_num_ge1_ )
+ { return false; }
+ if ( fread ( lma_idx_buf_, sizeof ( unsigned char ), lma_idx_buf_len_, fp ) !=
+ lma_idx_buf_len_ )
+ { return false; }
+ // The quick index for the first level sons
+ uint16 last_splid = kFullSplIdStart;
+ size_t last_pos = 0;
+ for ( size_t i = 1; i < lma_node_num_le0_; i++ ) {
+ for ( uint16 splid = last_splid; splid < root_[i].spl_idx; splid++ )
+ { splid_le0_index_[splid - kFullSplIdStart] = last_pos; }
+ splid_le0_index_[root_[i].spl_idx - kFullSplIdStart] =
+ static_cast<uint16> ( i );
+ last_splid = root_[i].spl_idx;
+ last_pos = i;
}
- if (son->spl_idx >= id_start + id_num - 1 || son_pos ==
- (size_t)node->num_of_son - 1) {
- if (found_num > 0) {
- if (mile_stones_pos_ < kMaxMileStone &&
- parsing_marks_pos_ < kMaxParsingMark) {
- parsing_marks_[parsing_marks_pos_].node_offset =
- get_son_offset(node) + found_start;
- parsing_marks_[parsing_marks_pos_].node_num = found_num;
- if (0 == ret_val)
- mile_stones_[mile_stones_pos_].mark_start =
- parsing_marks_pos_;
- parsing_marks_pos_++;
- }
-
- ret_val++;
- }
- break;
+ for ( uint16 splid = last_splid + 1;
+ splid < buf_size + kFullSplIdStart; splid++ ) {
+ assert ( static_cast<size_t> ( splid - kFullSplIdStart ) < buf_size );
+ splid_le0_index_[splid - kFullSplIdStart] = last_pos + 1;
}
- } // for son_pos
- } // for ext_pos
- } // for h_pos
-
- if (ret_val > 0) {
- mile_stones_[mile_stones_pos_].mark_num = ret_val;
- ret_handle = mile_stones_pos_;
- mile_stones_pos_++;
- }
-
- // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_,
- // mile_stones_pos_);
- return ret_handle;
-}
-
-bool DictTrie::try_extend(const uint16 *splids, uint16 splid_num,
- LemmaIdType id_lemma) {
- if (0 == splid_num || NULL == splids)
- return false;
-
- void *node = root_ + splid_le0_index_[splids[0] - kFullSplIdStart];
-
- for (uint16 pos = 1; pos < splid_num; pos++) {
- if (1 == pos) {
- LmaNodeLE0 *node_le0 = reinterpret_cast<LmaNodeLE0*>(node);
- LmaNodeGE1 *node_son;
- uint16 son_pos;
- for (son_pos = 0; son_pos < static_cast<uint16>(node_le0->num_of_son);
- son_pos++) {
- assert(node_le0->son_1st_off <= lma_node_num_ge1_);
- node_son = nodes_ge1_ + node_le0->son_1st_off
- + son_pos;
- if (node_son->spl_idx == splids[pos])
- break;
- }
- if (son_pos < node_le0->num_of_son)
- node = reinterpret_cast<void*>(node_son);
- else
- return false;
- } else {
- LmaNodeGE1 *node_ge1 = reinterpret_cast<LmaNodeGE1*>(node);
- LmaNodeGE1 *node_son;
- uint16 son_pos;
- for (son_pos = 0; son_pos < static_cast<uint16>(node_ge1->num_of_son);
- son_pos++) {
- assert(node_ge1->son_1st_off_l > 0 || node_ge1->son_1st_off_h > 0);
- node_son = nodes_ge1_ + get_son_offset(node_ge1) + son_pos;
- if (node_son->spl_idx == splids[pos])
- break;
- }
- if (son_pos < node_ge1->num_of_son)
- node = reinterpret_cast<void*>(node_son);
- else
- return false;
+ return true;
}
- }
- if (1 == splid_num) {
- LmaNodeLE0* node_le0 = reinterpret_cast<LmaNodeLE0*>(node);
- size_t num_of_homo = (size_t)node_le0->num_of_homo;
- for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) {
- LemmaIdType id_this = get_lemma_id(node_le0->homo_idx_buf_off + homo_pos);
- char16 str[2];
- get_lemma_str(id_this, str, 2);
- if (id_this == id_lemma)
+ bool DictTrie::load_dict ( const char *filename, LemmaIdType start_id,
+ LemmaIdType end_id ) {
+ if ( NULL == filename || end_id <= start_id )
+ { return false; }
+ FILE *fp = fopen ( filename, "rb" );
+ if ( NULL == fp )
+ { return false; }
+ free_resource ( true );
+ dict_list_ = new DictList();
+ if ( NULL == dict_list_ ) {
+ fclose ( fp );
+ return false;
+ }
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ NGram &ngram = NGram::get_instance();
+ if ( !spl_trie.load_spl_trie ( fp ) || !dict_list_->load_list ( fp ) ||
+ !load_dict ( fp ) || !ngram.load_ngram ( fp ) ||
+ total_lma_num_ > end_id - start_id + 1 ) {
+ free_resource ( true );
+ fclose ( fp );
+ return false;
+ }
+ fclose ( fp );
return true;
}
- } else {
- LmaNodeGE1* node_ge1 = reinterpret_cast<LmaNodeGE1*>(node);
- size_t num_of_homo = (size_t)node_ge1->num_of_homo;
- for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) {
- size_t node_homo_off = get_homo_idx_buf_offset(node_ge1);
- if (get_lemma_id(node_homo_off + homo_pos) == id_lemma)
+
+ bool DictTrie::load_dict_fd ( int sys_fd, long start_offset,
+ long length, LemmaIdType start_id,
+ LemmaIdType end_id ) {
+ if ( start_offset < 0 || length <= 0 || end_id <= start_id )
+ { return false; }
+ FILE *fp = fdopen ( sys_fd, "rb" );
+ if ( NULL == fp )
+ { return false; }
+ if ( -1 == fseek ( fp, start_offset, SEEK_SET ) ) {
+ fclose ( fp );
+ return false;
+ }
+ free_resource ( true );
+ dict_list_ = new DictList();
+ if ( NULL == dict_list_ ) {
+ fclose ( fp );
+ return false;
+ }
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ NGram &ngram = NGram::get_instance();
+ if ( !spl_trie.load_spl_trie ( fp ) || !dict_list_->load_list ( fp ) ||
+ !load_dict ( fp ) || !ngram.load_ngram ( fp ) ||
+ ftell ( fp ) < start_offset + length ||
+ total_lma_num_ > end_id - start_id + 1 ) {
+ free_resource ( true );
+ fclose ( fp );
+ return false;
+ }
+ fclose ( fp );
return true;
}
- }
- return false;
-}
+ size_t DictTrie::fill_lpi_buffer ( LmaPsbItem lpi_items[], size_t lpi_max,
+ LmaNodeLE0 *node ) {
+ size_t lpi_num = 0;
+ NGram &ngram = NGram::get_instance();
+ for ( size_t homo = 0; homo < ( size_t ) node->num_of_homo; homo++ ) {
+ lpi_items[lpi_num].id = get_lemma_id ( node->homo_idx_buf_off +
+ homo );
+ lpi_items[lpi_num].lma_len = 1;
+ lpi_items[lpi_num].psb =
+ static_cast<LmaScoreType> ( ngram.get_uni_psb ( lpi_items[lpi_num].id ) );
+ lpi_num++;
+ if ( lpi_num >= lpi_max )
+ { break; }
+ }
+ return lpi_num;
+ }
-size_t DictTrie::get_lpis(const uint16* splid_str, uint16 splid_str_len,
- LmaPsbItem* lma_buf, size_t max_lma_buf) {
- if (splid_str_len > kMaxLemmaSize)
- return 0;
+ size_t DictTrie::fill_lpi_buffer ( LmaPsbItem lpi_items[], size_t lpi_max,
+ size_t homo_buf_off, LmaNodeGE1 *node,
+ uint16 lma_len ) {
+ size_t lpi_num = 0;
+ NGram &ngram = NGram::get_instance();
+ for ( size_t homo = 0; homo < ( size_t ) node->num_of_homo; homo++ ) {
+ lpi_items[lpi_num].id = get_lemma_id ( homo_buf_off + homo );
+ lpi_items[lpi_num].lma_len = lma_len;
+ lpi_items[lpi_num].psb =
+ static_cast<LmaScoreType> ( ngram.get_uni_psb ( lpi_items[lpi_num].id ) );
+ lpi_num++;
+ if ( lpi_num >= lpi_max )
+ { break; }
+ }
+ return lpi_num;
+ }
-#define MAX_EXTENDBUF_LEN 200
+ void DictTrie::reset_milestones ( uint16 from_step, MileStoneHandle from_handle ) {
+ if ( 0 == from_step ) {
+ parsing_marks_pos_ = 0;
+ mile_stones_pos_ = kFirstValidMileStoneHandle;
+ } else {
+ if ( from_handle > 0 && from_handle < mile_stones_pos_ ) {
+ mile_stones_pos_ = from_handle;
+ MileStone *mile_stone = mile_stones_ + from_handle;
+ parsing_marks_pos_ = mile_stone->mark_start;
+ }
+ }
+ }
- size_t* node_buf1[MAX_EXTENDBUF_LEN]; // use size_t for data alignment
- size_t* node_buf2[MAX_EXTENDBUF_LEN];
- LmaNodeLE0** node_fr_le0 =
- reinterpret_cast<LmaNodeLE0**>(node_buf1); // Nodes from.
- LmaNodeLE0** node_to_le0 =
- reinterpret_cast<LmaNodeLE0**>(node_buf2); // Nodes to.
- LmaNodeGE1** node_fr_ge1 = NULL;
- LmaNodeGE1** node_to_ge1 = NULL;
- size_t node_fr_num = 1;
- size_t node_to_num = 0;
- node_fr_le0[0] = root_;
- if (NULL == node_fr_le0[0])
- return 0;
+ MileStoneHandle DictTrie::extend_dict ( MileStoneHandle from_handle,
+ const DictExtPara *dep,
+ LmaPsbItem *lpi_items, size_t lpi_max,
+ size_t *lpi_num ) {
+ if ( NULL == dep )
+ { return 0; }
+ // from LmaNodeLE0 (root) to LmaNodeLE0
+ if ( 0 == from_handle ) {
+ assert ( 0 == dep->splids_extended );
+ return extend_dict0 ( from_handle, dep, lpi_items, lpi_max, lpi_num );
+ }
+ // from LmaNodeLE0 to LmaNodeGE1
+ if ( 1 == dep->splids_extended )
+ { return extend_dict1 ( from_handle, dep, lpi_items, lpi_max, lpi_num ); }
+ // From LmaNodeGE1 to LmaNodeGE1
+ return extend_dict2 ( from_handle, dep, lpi_items, lpi_max, lpi_num );
+ }
- size_t spl_pos = 0;
+ MileStoneHandle DictTrie::extend_dict0 ( MileStoneHandle from_handle,
+ const DictExtPara *dep,
+ LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num ) {
+ assert ( NULL != dep && 0 == from_handle );
+ *lpi_num = 0;
+ MileStoneHandle ret_handle = 0;
+ uint16 splid = dep->splids[dep->splids_extended];
+ uint16 id_start = dep->id_start;
+ uint16 id_num = dep->id_num;
+ LpiCache &lpi_cache = LpiCache::get_instance();
+ bool cached = lpi_cache.is_cached ( splid );
+ // 2. Begin exgtending
+ // 2.1 Get the LmaPsbItem list
+ LmaNodeLE0 *node = root_;
+ size_t son_start = splid_le0_index_[id_start - kFullSplIdStart];
+ size_t son_end = splid_le0_index_[id_start + id_num - kFullSplIdStart];
+ for ( size_t son_pos = son_start; son_pos < son_end; son_pos++ ) {
+ assert ( 1 == node->son_1st_off );
+ LmaNodeLE0 *son = root_ + son_pos;
+ assert ( son->spl_idx >= id_start && son->spl_idx < id_start + id_num );
+ if ( !cached && *lpi_num < lpi_max ) {
+ bool need_lpi = true;
+ if ( spl_trie_->is_half_id_yunmu ( splid ) && son_pos != son_start )
+ { need_lpi = false; }
+ if ( need_lpi )
+ *lpi_num += fill_lpi_buffer ( lpi_items + ( *lpi_num ),
+ lpi_max - *lpi_num, son );
+ }
+ // If necessary, fill in a new mile stone.
+ if ( son->spl_idx == id_start ) {
+ if ( mile_stones_pos_ < kMaxMileStone &&
+ parsing_marks_pos_ < kMaxParsingMark ) {
+ parsing_marks_[parsing_marks_pos_].node_offset = son_pos;
+ parsing_marks_[parsing_marks_pos_].node_num = id_num;
+ mile_stones_[mile_stones_pos_].mark_start = parsing_marks_pos_;
+ mile_stones_[mile_stones_pos_].mark_num = 1;
+ ret_handle = mile_stones_pos_;
+ parsing_marks_pos_++;
+ mile_stones_pos_++;
+ }
+ }
+ if ( son->spl_idx >= id_start + id_num - 1 )
+ { break; }
+ }
+ // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_,
+ // mile_stones_pos_);
+ return ret_handle;
+ }
- while (spl_pos < splid_str_len) {
- uint16 id_num = 1;
- uint16 id_start = splid_str[spl_pos];
- // If it is a half id
- if (spl_trie_->is_half_id(splid_str[spl_pos])) {
- id_num = spl_trie_->half_to_full(splid_str[spl_pos], &id_start);
- assert(id_num > 0);
+ MileStoneHandle DictTrie::extend_dict1 ( MileStoneHandle from_handle,
+ const DictExtPara *dep,
+ LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num ) {
+ assert ( NULL != dep && from_handle > 0 && from_handle < mile_stones_pos_ );
+ MileStoneHandle ret_handle = 0;
+ // 1. If this is a half Id, get its corresponding full starting Id and
+ // number of full Id.
+ size_t ret_val = 0;
+ uint16 id_start = dep->id_start;
+ uint16 id_num = dep->id_num;
+ // 2. Begin extending.
+ MileStone *mile_stone = mile_stones_ + from_handle;
+ for ( uint16 h_pos = 0; h_pos < mile_stone->mark_num; h_pos++ ) {
+ ParsingMark p_mark = parsing_marks_[mile_stone->mark_start + h_pos];
+ uint16 ext_num = p_mark.node_num;
+ for ( uint16 ext_pos = 0; ext_pos < ext_num; ext_pos++ ) {
+ LmaNodeLE0 *node = root_ + p_mark.node_offset + ext_pos;
+ size_t found_start = 0;
+ size_t found_num = 0;
+ for ( size_t son_pos = 0; son_pos < ( size_t ) node->num_of_son; son_pos++ ) {
+ assert ( node->son_1st_off <= lma_node_num_ge1_ );
+ LmaNodeGE1 *son = nodes_ge1_ + node->son_1st_off + son_pos;
+ if ( son->spl_idx >= id_start
+ && son->spl_idx < id_start + id_num ) {
+ if ( *lpi_num < lpi_max ) {
+ size_t homo_buf_off = get_homo_idx_buf_offset ( son );
+ *lpi_num += fill_lpi_buffer ( lpi_items + ( *lpi_num ),
+ lpi_max - *lpi_num, homo_buf_off, son,
+ 2 );
+ }
+ // If necessary, fill in the new DTMI
+ if ( 0 == found_num ) {
+ found_start = son_pos;
+ }
+ found_num++;
+ }
+ if ( son->spl_idx >= id_start + id_num - 1 || son_pos ==
+ ( size_t ) node->num_of_son - 1 ) {
+ if ( found_num > 0 ) {
+ if ( mile_stones_pos_ < kMaxMileStone &&
+ parsing_marks_pos_ < kMaxParsingMark ) {
+ parsing_marks_[parsing_marks_pos_].node_offset =
+ node->son_1st_off + found_start;
+ parsing_marks_[parsing_marks_pos_].node_num = found_num;
+ if ( 0 == ret_val )
+ mile_stones_[mile_stones_pos_].mark_start =
+ parsing_marks_pos_;
+ parsing_marks_pos_++;
+ }
+ ret_val++;
+ }
+ break;
+ } // for son_pos
+ } // for ext_pos
+ } // for h_pos
+ }
+ if ( ret_val > 0 ) {
+ mile_stones_[mile_stones_pos_].mark_num = ret_val;
+ ret_handle = mile_stones_pos_;
+ mile_stones_pos_++;
+ ret_val = 1;
+ }
+ // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_,
+ // mile_stones_pos_);
+ return ret_handle;
}
- // Extend the nodes
- if (0 == spl_pos) { // From LmaNodeLE0 (root) to LmaNodeLE0 nodes
- for (size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++) {
- LmaNodeLE0 *node = node_fr_le0[node_fr_pos];
- assert(node == root_ && 1 == node_fr_num);
- size_t son_start = splid_le0_index_[id_start - kFullSplIdStart];
- size_t son_end =
- splid_le0_index_[id_start + id_num - kFullSplIdStart];
- for (size_t son_pos = son_start; son_pos < son_end; son_pos++) {
- assert(1 == node->son_1st_off);
- LmaNodeLE0 *node_son = root_ + son_pos;
- assert(node_son->spl_idx >= id_start
- && node_son->spl_idx < id_start + id_num);
- if (node_to_num < MAX_EXTENDBUF_LEN) {
- node_to_le0[node_to_num] = node_son;
- node_to_num++;
- }
- // id_start + id_num - 1 is the last one, which has just been
- // recorded.
- if (node_son->spl_idx >= id_start + id_num - 1)
- break;
+ MileStoneHandle DictTrie::extend_dict2 ( MileStoneHandle from_handle,
+ const DictExtPara *dep,
+ LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num ) {
+ assert ( NULL != dep && from_handle > 0 && from_handle < mile_stones_pos_ );
+ MileStoneHandle ret_handle = 0;
+ // 1. If this is a half Id, get its corresponding full starting Id and
+ // number of full Id.
+ size_t ret_val = 0;
+ uint16 id_start = dep->id_start;
+ uint16 id_num = dep->id_num;
+ // 2. Begin extending.
+ MileStone *mile_stone = mile_stones_ + from_handle;
+ for ( uint16 h_pos = 0; h_pos < mile_stone->mark_num; h_pos++ ) {
+ ParsingMark p_mark = parsing_marks_[mile_stone->mark_start + h_pos];
+ uint16 ext_num = p_mark.node_num;
+ for ( uint16 ext_pos = 0; ext_pos < ext_num; ext_pos++ ) {
+ LmaNodeGE1 *node = nodes_ge1_ + p_mark.node_offset + ext_pos;
+ size_t found_start = 0;
+ size_t found_num = 0;
+ for ( size_t son_pos = 0; son_pos < ( size_t ) node->num_of_son; son_pos++ ) {
+ assert ( node->son_1st_off_l > 0 || node->son_1st_off_h > 0 );
+ LmaNodeGE1 *son = nodes_ge1_ + get_son_offset ( node ) + son_pos;
+ if ( son->spl_idx >= id_start
+ && son->spl_idx < id_start + id_num ) {
+ if ( *lpi_num < lpi_max ) {
+ size_t homo_buf_off = get_homo_idx_buf_offset ( son );
+ *lpi_num += fill_lpi_buffer ( lpi_items + ( *lpi_num ),
+ lpi_max - *lpi_num, homo_buf_off, son,
+ dep->splids_extended + 1 );
+ }
+ // If necessary, fill in the new DTMI
+ if ( 0 == found_num ) {
+ found_start = son_pos;
+ }
+ found_num++;
+ }
+ if ( son->spl_idx >= id_start + id_num - 1 || son_pos ==
+ ( size_t ) node->num_of_son - 1 ) {
+ if ( found_num > 0 ) {
+ if ( mile_stones_pos_ < kMaxMileStone &&
+ parsing_marks_pos_ < kMaxParsingMark ) {
+ parsing_marks_[parsing_marks_pos_].node_offset =
+ get_son_offset ( node ) + found_start;
+ parsing_marks_[parsing_marks_pos_].node_num = found_num;
+ if ( 0 == ret_val )
+ mile_stones_[mile_stones_pos_].mark_start =
+ parsing_marks_pos_;
+ parsing_marks_pos_++;
+ }
+ ret_val++;
+ }
+ break;
+ }
+ } // for son_pos
+ } // for ext_pos
+ } // for h_pos
+ if ( ret_val > 0 ) {
+ mile_stones_[mile_stones_pos_].mark_num = ret_val;
+ ret_handle = mile_stones_pos_;
+ mile_stones_pos_++;
}
- }
+ // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_,
+ // mile_stones_pos_);
+ return ret_handle;
+ }
- spl_pos++;
- if (spl_pos >= splid_str_len || node_to_num == 0)
- break;
- // Prepare the nodes for next extending
- // next time, from LmaNodeLE0 to LmaNodeGE1
- LmaNodeLE0** node_tmp = node_fr_le0;
- node_fr_le0 = node_to_le0;
- node_to_le0 = NULL;
- node_to_ge1 = reinterpret_cast<LmaNodeGE1**>(node_tmp);
- } else if (1 == spl_pos) { // From LmaNodeLE0 to LmaNodeGE1 nodes
- for (size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++) {
- LmaNodeLE0 *node = node_fr_le0[node_fr_pos];
- for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son;
- son_pos++) {
- assert(node->son_1st_off <= lma_node_num_ge1_);
- LmaNodeGE1 *node_son = nodes_ge1_ + node->son_1st_off
- + son_pos;
- if (node_son->spl_idx >= id_start
- && node_son->spl_idx < id_start + id_num) {
- if (node_to_num < MAX_EXTENDBUF_LEN) {
- node_to_ge1[node_to_num] = node_son;
- node_to_num++;
+ bool DictTrie::try_extend ( const uint16 *splids, uint16 splid_num,
+ LemmaIdType id_lemma ) {
+ if ( 0 == splid_num || NULL == splids )
+ { return false; }
+ void *node = root_ + splid_le0_index_[splids[0] - kFullSplIdStart];
+ for ( uint16 pos = 1; pos < splid_num; pos++ ) {
+ if ( 1 == pos ) {
+ LmaNodeLE0 *node_le0 = reinterpret_cast<LmaNodeLE0 *> ( node );
+ LmaNodeGE1 *node_son;
+ uint16 son_pos;
+ for ( son_pos = 0; son_pos < static_cast<uint16> ( node_le0->num_of_son );
+ son_pos++ ) {
+ assert ( node_le0->son_1st_off <= lma_node_num_ge1_ );
+ node_son = nodes_ge1_ + node_le0->son_1st_off
+ + son_pos;
+ if ( node_son->spl_idx == splids[pos] )
+ { break; }
+ }
+ if ( son_pos < node_le0->num_of_son )
+ { node = reinterpret_cast<void *> ( node_son ); }
+ else
+ { return false; }
+ } else {
+ LmaNodeGE1 *node_ge1 = reinterpret_cast<LmaNodeGE1 *> ( node );
+ LmaNodeGE1 *node_son;
+ uint16 son_pos;
+ for ( son_pos = 0; son_pos < static_cast<uint16> ( node_ge1->num_of_son );
+ son_pos++ ) {
+ assert ( node_ge1->son_1st_off_l > 0 || node_ge1->son_1st_off_h > 0 );
+ node_son = nodes_ge1_ + get_son_offset ( node_ge1 ) + son_pos;
+ if ( node_son->spl_idx == splids[pos] )
+ { break; }
+ }
+ if ( son_pos < node_ge1->num_of_son )
+ { node = reinterpret_cast<void *> ( node_son ); }
+ else
+ { return false; }
}
- }
- // id_start + id_num - 1 is the last one, which has just been
- // recorded.
- if (node_son->spl_idx >= id_start + id_num - 1)
- break;
}
- }
-
- spl_pos++;
- if (spl_pos >= splid_str_len || node_to_num == 0)
- break;
- // Prepare the nodes for next extending
- // next time, from LmaNodeGE1 to LmaNodeGE1
- node_fr_ge1 = node_to_ge1;
- node_to_ge1 = reinterpret_cast<LmaNodeGE1**>(node_fr_le0);
- node_fr_le0 = NULL;
- node_to_le0 = NULL;
- } else { // From LmaNodeGE1 to LmaNodeGE1 nodes
- for (size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++) {
- LmaNodeGE1 *node = node_fr_ge1[node_fr_pos];
- for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son;
- son_pos++) {
- assert(node->son_1st_off_l > 0 || node->son_1st_off_h > 0);
- LmaNodeGE1 *node_son = nodes_ge1_
- + get_son_offset(node) + son_pos;
- if (node_son->spl_idx >= id_start
- && node_son->spl_idx < id_start + id_num) {
- if (node_to_num < MAX_EXTENDBUF_LEN) {
- node_to_ge1[node_to_num] = node_son;
- node_to_num++;
+ if ( 1 == splid_num ) {
+ LmaNodeLE0 *node_le0 = reinterpret_cast<LmaNodeLE0 *> ( node );
+ size_t num_of_homo = ( size_t ) node_le0->num_of_homo;
+ for ( size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++ ) {
+ LemmaIdType id_this = get_lemma_id ( node_le0->homo_idx_buf_off + homo_pos );
+ char16 str[2];
+ get_lemma_str ( id_this, str, 2 );
+ if ( id_this == id_lemma )
+ { return true; }
+ }
+ } else {
+ LmaNodeGE1 *node_ge1 = reinterpret_cast<LmaNodeGE1 *> ( node );
+ size_t num_of_homo = ( size_t ) node_ge1->num_of_homo;
+ for ( size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++ ) {
+ size_t node_homo_off = get_homo_idx_buf_offset ( node_ge1 );
+ if ( get_lemma_id ( node_homo_off + homo_pos ) == id_lemma )
+ { return true; }
}
- }
- // id_start + id_num - 1 is the last one, which has just been
- // recorded.
- if (node_son->spl_idx >= id_start + id_num - 1)
- break;
}
- }
-
- spl_pos++;
- if (spl_pos >= splid_str_len || node_to_num == 0)
- break;
- // Prepare the nodes for next extending
- // next time, from LmaNodeGE1 to LmaNodeGE1
- LmaNodeGE1 **node_tmp = node_fr_ge1;
- node_fr_ge1 = node_to_ge1;
- node_to_ge1 = node_tmp;
+ return false;
}
- // The number of node for next extending
- node_fr_num = node_to_num;
- node_to_num = 0;
- } // while
-
- if (0 == node_to_num)
- return 0;
-
- NGram &ngram = NGram::get_instance();
- size_t lma_num = 0;
-
- // If the length is 1, and the splid is a one-char Yunmu like 'a', 'o', 'e',
- // only those candidates for the full matched one-char id will be returned.
- if (1 == splid_str_len && spl_trie_->is_half_id_yunmu(splid_str[0]))
- node_to_num = node_to_num > 0 ? 1 : 0;
-
- for (size_t node_pos = 0; node_pos < node_to_num; node_pos++) {
- size_t num_of_homo = 0;
- if (spl_pos <= 1) { // Get from LmaNodeLE0 nodes
- LmaNodeLE0* node_le0 = node_to_le0[node_pos];
- num_of_homo = (size_t)node_le0->num_of_homo;
- for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) {
- size_t ch_pos = lma_num + homo_pos;
- lma_buf[ch_pos].id =
- get_lemma_id(node_le0->homo_idx_buf_off + homo_pos);
- lma_buf[ch_pos].lma_len = 1;
- lma_buf[ch_pos].psb =
- static_cast<LmaScoreType>(ngram.get_uni_psb(lma_buf[ch_pos].id));
-
- if (lma_num + homo_pos >= max_lma_buf - 1)
- break;
- }
- } else { // Get from LmaNodeGE1 nodes
- LmaNodeGE1* node_ge1 = node_to_ge1[node_pos];
- num_of_homo = (size_t)node_ge1->num_of_homo;
- for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) {
- size_t ch_pos = lma_num + homo_pos;
- size_t node_homo_off = get_homo_idx_buf_offset(node_ge1);
- lma_buf[ch_pos].id = get_lemma_id(node_homo_off + homo_pos);
- lma_buf[ch_pos].lma_len = splid_str_len;
- lma_buf[ch_pos].psb =
- static_cast<LmaScoreType>(ngram.get_uni_psb(lma_buf[ch_pos].id));
-
- if (lma_num + homo_pos >= max_lma_buf - 1)
- break;
- }
+ size_t DictTrie::get_lpis ( const uint16 *splid_str, uint16 splid_str_len,
+ LmaPsbItem *lma_buf, size_t max_lma_buf ) {
+ if ( splid_str_len > kMaxLemmaSize )
+ { return 0; }
+#define MAX_EXTENDBUF_LEN 200
+ size_t *node_buf1[MAX_EXTENDBUF_LEN]; // use size_t for data alignment
+ size_t *node_buf2[MAX_EXTENDBUF_LEN];
+ LmaNodeLE0 **node_fr_le0 =
+ reinterpret_cast<LmaNodeLE0 **> ( node_buf1 ); // Nodes from.
+ LmaNodeLE0 **node_to_le0 =
+ reinterpret_cast<LmaNodeLE0 **> ( node_buf2 ); // Nodes to.
+ LmaNodeGE1 **node_fr_ge1 = NULL;
+ LmaNodeGE1 **node_to_ge1 = NULL;
+ size_t node_fr_num = 1;
+ size_t node_to_num = 0;
+ node_fr_le0[0] = root_;
+ if ( NULL == node_fr_le0[0] )
+ { return 0; }
+ size_t spl_pos = 0;
+ while ( spl_pos < splid_str_len ) {
+ uint16 id_num = 1;
+ uint16 id_start = splid_str[spl_pos];
+ // If it is a half id
+ if ( spl_trie_->is_half_id ( splid_str[spl_pos] ) ) {
+ id_num = spl_trie_->half_to_full ( splid_str[spl_pos], &id_start );
+ assert ( id_num > 0 );
+ }
+ // Extend the nodes
+ if ( 0 == spl_pos ) { // From LmaNodeLE0 (root) to LmaNodeLE0 nodes
+ for ( size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++ ) {
+ LmaNodeLE0 *node = node_fr_le0[node_fr_pos];
+ assert ( node == root_ && 1 == node_fr_num );
+ size_t son_start = splid_le0_index_[id_start - kFullSplIdStart];
+ size_t son_end =
+ splid_le0_index_[id_start + id_num - kFullSplIdStart];
+ for ( size_t son_pos = son_start; son_pos < son_end; son_pos++ ) {
+ assert ( 1 == node->son_1st_off );
+ LmaNodeLE0 *node_son = root_ + son_pos;
+ assert ( node_son->spl_idx >= id_start
+ && node_son->spl_idx < id_start + id_num );
+ if ( node_to_num < MAX_EXTENDBUF_LEN ) {
+ node_to_le0[node_to_num] = node_son;
+ node_to_num++;
+ }
+ // id_start + id_num - 1 is the last one, which has just been
+ // recorded.
+ if ( node_son->spl_idx >= id_start + id_num - 1 )
+ { break; }
+ }
+ }
+ spl_pos++;
+ if ( spl_pos >= splid_str_len || node_to_num == 0 )
+ { break; }
+ // Prepare the nodes for next extending
+ // next time, from LmaNodeLE0 to LmaNodeGE1
+ LmaNodeLE0 **node_tmp = node_fr_le0;
+ node_fr_le0 = node_to_le0;
+ node_to_le0 = NULL;
+ node_to_ge1 = reinterpret_cast<LmaNodeGE1 **> ( node_tmp );
+ } else if ( 1 == spl_pos ) { // From LmaNodeLE0 to LmaNodeGE1 nodes
+ for ( size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++ ) {
+ LmaNodeLE0 *node = node_fr_le0[node_fr_pos];
+ for ( size_t son_pos = 0; son_pos < ( size_t ) node->num_of_son;
+ son_pos++ ) {
+ assert ( node->son_1st_off <= lma_node_num_ge1_ );
+ LmaNodeGE1 *node_son = nodes_ge1_ + node->son_1st_off
+ + son_pos;
+ if ( node_son->spl_idx >= id_start
+ && node_son->spl_idx < id_start + id_num ) {
+ if ( node_to_num < MAX_EXTENDBUF_LEN ) {
+ node_to_ge1[node_to_num] = node_son;
+ node_to_num++;
+ }
+ }
+ // id_start + id_num - 1 is the last one, which has just been
+ // recorded.
+ if ( node_son->spl_idx >= id_start + id_num - 1 )
+ { break; }
+ }
+ }
+ spl_pos++;
+ if ( spl_pos >= splid_str_len || node_to_num == 0 )
+ { break; }
+ // Prepare the nodes for next extending
+ // next time, from LmaNodeGE1 to LmaNodeGE1
+ node_fr_ge1 = node_to_ge1;
+ node_to_ge1 = reinterpret_cast<LmaNodeGE1 **> ( node_fr_le0 );
+ node_fr_le0 = NULL;
+ node_to_le0 = NULL;
+ } else { // From LmaNodeGE1 to LmaNodeGE1 nodes
+ for ( size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++ ) {
+ LmaNodeGE1 *node = node_fr_ge1[node_fr_pos];
+ for ( size_t son_pos = 0; son_pos < ( size_t ) node->num_of_son;
+ son_pos++ ) {
+ assert ( node->son_1st_off_l > 0 || node->son_1st_off_h > 0 );
+ LmaNodeGE1 *node_son = nodes_ge1_
+ + get_son_offset ( node ) + son_pos;
+ if ( node_son->spl_idx >= id_start
+ && node_son->spl_idx < id_start + id_num ) {
+ if ( node_to_num < MAX_EXTENDBUF_LEN ) {
+ node_to_ge1[node_to_num] = node_son;
+ node_to_num++;
+ }
+ }
+ // id_start + id_num - 1 is the last one, which has just been
+ // recorded.
+ if ( node_son->spl_idx >= id_start + id_num - 1 )
+ { break; }
+ }
+ }
+ spl_pos++;
+ if ( spl_pos >= splid_str_len || node_to_num == 0 )
+ { break; }
+ // Prepare the nodes for next extending
+ // next time, from LmaNodeGE1 to LmaNodeGE1
+ LmaNodeGE1 **node_tmp = node_fr_ge1;
+ node_fr_ge1 = node_to_ge1;
+ node_to_ge1 = node_tmp;
+ }
+ // The number of node for next extending
+ node_fr_num = node_to_num;
+ node_to_num = 0;
+ } // while
+ if ( 0 == node_to_num )
+ { return 0; }
+ NGram &ngram = NGram::get_instance();
+ size_t lma_num = 0;
+ // If the length is 1, and the splid is a one-char Yunmu like 'a', 'o', 'e',
+ // only those candidates for the full matched one-char id will be returned.
+ if ( 1 == splid_str_len && spl_trie_->is_half_id_yunmu ( splid_str[0] ) )
+ { node_to_num = node_to_num > 0 ? 1 : 0; }
+ for ( size_t node_pos = 0; node_pos < node_to_num; node_pos++ ) {
+ size_t num_of_homo = 0;
+ if ( spl_pos <= 1 ) { // Get from LmaNodeLE0 nodes
+ LmaNodeLE0 *node_le0 = node_to_le0[node_pos];
+ num_of_homo = ( size_t ) node_le0->num_of_homo;
+ for ( size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++ ) {
+ size_t ch_pos = lma_num + homo_pos;
+ lma_buf[ch_pos].id =
+ get_lemma_id ( node_le0->homo_idx_buf_off + homo_pos );
+ lma_buf[ch_pos].lma_len = 1;
+ lma_buf[ch_pos].psb =
+ static_cast<LmaScoreType> ( ngram.get_uni_psb ( lma_buf[ch_pos].id ) );
+ if ( lma_num + homo_pos >= max_lma_buf - 1 )
+ { break; }
+ }
+ } else { // Get from LmaNodeGE1 nodes
+ LmaNodeGE1 *node_ge1 = node_to_ge1[node_pos];
+ num_of_homo = ( size_t ) node_ge1->num_of_homo;
+ for ( size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++ ) {
+ size_t ch_pos = lma_num + homo_pos;
+ size_t node_homo_off = get_homo_idx_buf_offset ( node_ge1 );
+ lma_buf[ch_pos].id = get_lemma_id ( node_homo_off + homo_pos );
+ lma_buf[ch_pos].lma_len = splid_str_len;
+ lma_buf[ch_pos].psb =
+ static_cast<LmaScoreType> ( ngram.get_uni_psb ( lma_buf[ch_pos].id ) );
+ if ( lma_num + homo_pos >= max_lma_buf - 1 )
+ { break; }
+ }
+ }
+ lma_num += num_of_homo;
+ if ( lma_num >= max_lma_buf ) {
+ lma_num = max_lma_buf;
+ break;
+ }
+ }
+ return lma_num;
}
- lma_num += num_of_homo;
- if (lma_num >= max_lma_buf) {
- lma_num = max_lma_buf;
- break;
+ uint16 DictTrie::get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf,
+ uint16 str_max ) {
+ return dict_list_->get_lemma_str ( id_lemma, str_buf, str_max );
}
- }
- return lma_num;
-}
-
-uint16 DictTrie::get_lemma_str(LemmaIdType id_lemma, char16 *str_buf,
- uint16 str_max) {
- return dict_list_->get_lemma_str(id_lemma, str_buf, str_max);
-}
-
-uint16 DictTrie::get_lemma_splids(LemmaIdType id_lemma, uint16 *splids,
- uint16 splids_max, bool arg_valid) {
- char16 lma_str[kMaxLemmaSize + 1];
- uint16 lma_len = get_lemma_str(id_lemma, lma_str, kMaxLemmaSize + 1);
- assert((!arg_valid && splids_max >= lma_len) || lma_len == splids_max);
-
- uint16 spl_mtrx[kMaxLemmaSize * 5];
- uint16 spl_start[kMaxLemmaSize + 1];
- spl_start[0] = 0;
- uint16 try_num = 1;
- for (uint16 pos = 0; pos < lma_len; pos++) {
- uint16 cand_splids_this = 0;
- if (arg_valid && spl_trie_->is_full_id(splids[pos])) {
- spl_mtrx[spl_start[pos]] = splids[pos];
- cand_splids_this = 1;
- } else {
- cand_splids_this = dict_list_->get_splids_for_hanzi(lma_str[pos],
- arg_valid ? splids[pos] : 0, spl_mtrx + spl_start[pos],
- kMaxLemmaSize * 5 - spl_start[pos]);
- assert(cand_splids_this > 0);
+ uint16 DictTrie::get_lemma_splids ( LemmaIdType id_lemma, uint16 *splids,
+ uint16 splids_max, bool arg_valid ) {
+ char16 lma_str[kMaxLemmaSize + 1];
+ uint16 lma_len = get_lemma_str ( id_lemma, lma_str, kMaxLemmaSize + 1 );
+ assert ( ( !arg_valid && splids_max >= lma_len ) || lma_len == splids_max );
+ uint16 spl_mtrx[kMaxLemmaSize * 5];
+ uint16 spl_start[kMaxLemmaSize + 1];
+ spl_start[0] = 0;
+ uint16 try_num = 1;
+ for ( uint16 pos = 0; pos < lma_len; pos++ ) {
+ uint16 cand_splids_this = 0;
+ if ( arg_valid && spl_trie_->is_full_id ( splids[pos] ) ) {
+ spl_mtrx[spl_start[pos]] = splids[pos];
+ cand_splids_this = 1;
+ } else {
+ cand_splids_this = dict_list_->get_splids_for_hanzi ( lma_str[pos],
+ arg_valid ? splids[pos] : 0, spl_mtrx + spl_start[pos],
+ kMaxLemmaSize * 5 - spl_start[pos] );
+ assert ( cand_splids_this > 0 );
+ }
+ spl_start[pos + 1] = spl_start[pos] + cand_splids_this;
+ try_num *= cand_splids_this;
+ }
+ for ( uint16 try_pos = 0; try_pos < try_num; try_pos++ ) {
+ uint16 mod = 1;
+ for ( uint16 pos = 0; pos < lma_len; pos++ ) {
+ uint16 radix = spl_start[pos + 1] - spl_start[pos];
+ splids[pos] = spl_mtrx[ spl_start[pos] + try_pos / mod % radix];
+ mod *= radix;
+ }
+ if ( try_extend ( splids, lma_len, id_lemma ) )
+ { return lma_len; }
+ }
+ return 0;
}
- spl_start[pos + 1] = spl_start[pos] + cand_splids_this;
- try_num *= cand_splids_this;
- }
- for (uint16 try_pos = 0; try_pos < try_num; try_pos++) {
- uint16 mod = 1;
- for (uint16 pos = 0; pos < lma_len; pos++) {
- uint16 radix = spl_start[pos + 1] - spl_start[pos];
- splids[pos] = spl_mtrx[ spl_start[pos] + try_pos / mod % radix];
- mod *= radix;
+ void DictTrie::set_total_lemma_count_of_others ( size_t count ) {
+ NGram &ngram = NGram::get_instance();
+ ngram.set_total_freq_none_sys ( count );
}
- if (try_extend(splids, lma_len, id_lemma))
- return lma_len;
- }
-
- return 0;
-}
-
-void DictTrie::set_total_lemma_count_of_others(size_t count) {
- NGram& ngram = NGram::get_instance();
- ngram.set_total_freq_none_sys(count);
-}
-
-void DictTrie::convert_to_hanzis(char16 *str, uint16 str_len) {
- return dict_list_->convert_to_hanzis(str, str_len);
-}
-
-void DictTrie::convert_to_scis_ids(char16 *str, uint16 str_len) {
- return dict_list_->convert_to_scis_ids(str, str_len);
-}
-
-LemmaIdType DictTrie::get_lemma_id(const char16 lemma_str[], uint16 lemma_len) {
- if (NULL == lemma_str || lemma_len > kMaxLemmaSize)
- return 0;
+ void DictTrie::convert_to_hanzis ( char16 *str, uint16 str_len ) {
+ return dict_list_->convert_to_hanzis ( str, str_len );
+ }
- return dict_list_->get_lemma_id(lemma_str, lemma_len);
-}
+ void DictTrie::convert_to_scis_ids ( char16 *str, uint16 str_len ) {
+ return dict_list_->convert_to_scis_ids ( str, str_len );
+ }
-size_t DictTrie::predict_top_lmas(size_t his_len, NPredictItem *npre_items,
- size_t npre_max, size_t b4_used) {
- NGram &ngram = NGram::get_instance();
+ LemmaIdType DictTrie::get_lemma_id ( const char16 lemma_str[], uint16 lemma_len ) {
+ if ( NULL == lemma_str || lemma_len > kMaxLemmaSize )
+ { return 0; }
+ return dict_list_->get_lemma_id ( lemma_str, lemma_len );
+ }
- size_t item_num = 0;
- size_t top_lmas_id_offset = lma_idx_buf_len_ / kLemmaIdSize - top_lmas_num_;
- size_t top_lmas_pos = 0;
- while (item_num < npre_max && top_lmas_pos < top_lmas_num_) {
- memset(npre_items + item_num, 0, sizeof(NPredictItem));
- LemmaIdType top_lma_id = get_lemma_id(top_lmas_id_offset + top_lmas_pos);
- top_lmas_pos += 1;
- if (dict_list_->get_lemma_str(top_lma_id,
- npre_items[item_num].pre_hzs,
- kMaxLemmaSize - 1) == 0) {
- continue;
+ size_t DictTrie::predict_top_lmas ( size_t his_len, NPredictItem *npre_items,
+ size_t npre_max, size_t b4_used ) {
+ NGram &ngram = NGram::get_instance();
+ size_t item_num = 0;
+ size_t top_lmas_id_offset = lma_idx_buf_len_ / kLemmaIdSize - top_lmas_num_;
+ size_t top_lmas_pos = 0;
+ while ( item_num < npre_max && top_lmas_pos < top_lmas_num_ ) {
+ memset ( npre_items + item_num, 0, sizeof ( NPredictItem ) );
+ LemmaIdType top_lma_id = get_lemma_id ( top_lmas_id_offset + top_lmas_pos );
+ top_lmas_pos += 1;
+ if ( dict_list_->get_lemma_str ( top_lma_id,
+ npre_items[item_num].pre_hzs,
+ kMaxLemmaSize - 1 ) == 0 ) {
+ continue;
+ }
+ npre_items[item_num].psb = ngram.get_uni_psb ( top_lma_id );
+ npre_items[item_num].his_len = his_len;
+ item_num++;
+ }
+ return item_num;
}
- npre_items[item_num].psb = ngram.get_uni_psb(top_lma_id);
- npre_items[item_num].his_len = his_len;
- item_num++;
- }
- return item_num;
-}
-size_t DictTrie::predict(const char16 *last_hzs, uint16 hzs_len,
- NPredictItem *npre_items, size_t npre_max,
- size_t b4_used) {
- return dict_list_->predict(last_hzs, hzs_len, npre_items, npre_max, b4_used);
-}
+ size_t DictTrie::predict ( const char16 *last_hzs, uint16 hzs_len,
+ NPredictItem *npre_items, size_t npre_max,
+ size_t b4_used ) {
+ return dict_list_->predict ( last_hzs, hzs_len, npre_items, npre_max, b4_used );
+ }
} // namespace ime_pinyin
diff --git a/jni/share/lpicache.cpp b/jni/share/lpicache.cpp
index 4bb4ca2..d95879c 100755
--- a/jni/share/lpicache.cpp
+++ b/jni/share/lpicache.cpp
@@ -19,63 +19,59 @@
namespace ime_pinyin {
-LpiCache* LpiCache::instance_ = NULL;
+ LpiCache *LpiCache::instance_ = NULL;
-LpiCache::LpiCache() {
- lpi_cache_ = new LmaPsbItem[kFullSplIdStart * kMaxLpiCachePerId];
- lpi_cache_len_ = new uint16[kFullSplIdStart];
- assert(NULL != lpi_cache_);
- assert(NULL != lpi_cache_len_);
- for (uint16 id = 0; id < kFullSplIdStart; id++)
- lpi_cache_len_[id] = 0;
-}
+ LpiCache::LpiCache() {
+ lpi_cache_ = new LmaPsbItem[kFullSplIdStart * kMaxLpiCachePerId];
+ lpi_cache_len_ = new uint16[kFullSplIdStart];
+ assert ( NULL != lpi_cache_ );
+ assert ( NULL != lpi_cache_len_ );
+ for ( uint16 id = 0; id < kFullSplIdStart; id++ )
+ { lpi_cache_len_[id] = 0; }
+ }
-LpiCache::~LpiCache() {
- if (NULL != lpi_cache_)
- delete [] lpi_cache_;
+ LpiCache::~LpiCache() {
+ if ( NULL != lpi_cache_ )
+ { delete [] lpi_cache_; }
+ if ( NULL != lpi_cache_len_ )
+ { delete [] lpi_cache_len_; }
+ }
- if (NULL != lpi_cache_len_)
- delete [] lpi_cache_len_;
-}
+ LpiCache &LpiCache::get_instance() {
+ if ( NULL == instance_ ) {
+ instance_ = new LpiCache();
+ assert ( NULL != instance_ );
+ }
+ return *instance_;
+ }
-LpiCache& LpiCache::get_instance() {
- if (NULL == instance_) {
- instance_ = new LpiCache();
- assert(NULL != instance_);
- }
- return *instance_;
-}
+ bool LpiCache::is_cached ( uint16 splid ) {
+ if ( splid >= kFullSplIdStart )
+ { return false; }
+ return lpi_cache_len_[splid] != 0;
+ }
-bool LpiCache::is_cached(uint16 splid) {
- if (splid >= kFullSplIdStart)
- return false;
- return lpi_cache_len_[splid] != 0;
-}
+ size_t LpiCache::put_cache ( uint16 splid, LmaPsbItem lpi_items[],
+ size_t lpi_num ) {
+ uint16 num = kMaxLpiCachePerId;
+ if ( num > lpi_num )
+ { num = static_cast<uint16> ( lpi_num ); }
+ LmaPsbItem *lpi_cache_this = lpi_cache_ + splid * kMaxLpiCachePerId;
+ for ( uint16 pos = 0; pos < num; pos++ )
+ { lpi_cache_this[pos] = lpi_items[pos]; }
+ lpi_cache_len_[splid] = num;
+ return num;
+ }
-size_t LpiCache::put_cache(uint16 splid, LmaPsbItem lpi_items[],
- size_t lpi_num) {
- uint16 num = kMaxLpiCachePerId;
- if (num > lpi_num)
- num = static_cast<uint16>(lpi_num);
-
- LmaPsbItem *lpi_cache_this = lpi_cache_ + splid * kMaxLpiCachePerId;
- for (uint16 pos = 0; pos < num; pos++)
- lpi_cache_this[pos] = lpi_items[pos];
-
- lpi_cache_len_[splid] = num;
- return num;
-}
-
-size_t LpiCache::get_cache(uint16 splid, LmaPsbItem lpi_items[],
- size_t lpi_max) {
- if (lpi_max > lpi_cache_len_[splid])
- lpi_max = lpi_cache_len_[splid];
-
- LmaPsbItem *lpi_cache_this = lpi_cache_ + splid * kMaxLpiCachePerId;
- for (uint16 pos = 0; pos < lpi_max; pos++) {
- lpi_items[pos] = lpi_cache_this[pos];
- }
- return lpi_max;
-}
+ size_t LpiCache::get_cache ( uint16 splid, LmaPsbItem lpi_items[],
+ size_t lpi_max ) {
+ if ( lpi_max > lpi_cache_len_[splid] )
+ { lpi_max = lpi_cache_len_[splid]; }
+ LmaPsbItem *lpi_cache_this = lpi_cache_ + splid * kMaxLpiCachePerId;
+ for ( uint16 pos = 0; pos < lpi_max; pos++ ) {
+ lpi_items[pos] = lpi_cache_this[pos];
+ }
+ return lpi_max;
+ }
} // namespace ime_pinyin
diff --git a/jni/share/matrixsearch.cpp b/jni/share/matrixsearch.cpp
index dd19f59..5df8527 100755
--- a/jni/share/matrixsearch.cpp
+++ b/jni/share/matrixsearch.cpp
@@ -28,1931 +28,1675 @@ namespace ime_pinyin {
#define PRUMING_SCORE 8000.0
-MatrixSearch::MatrixSearch() {
- inited_ = false;
- spl_trie_ = SpellingTrie::get_cpinstance();
-
- reset_pointers_to_null();
-
- pys_decoded_len_ = 0;
- mtrx_nd_pool_used_ = 0;
- dmi_pool_used_ = 0;
- xi_an_enabled_ = false;
- dmi_c_phrase_ = false;
-
- assert(kMaxSearchSteps > 0);
- max_sps_len_ = kMaxSearchSteps - 1;
- max_hzs_len_ = kMaxSearchSteps;
-}
-
-MatrixSearch::~MatrixSearch() {
- free_resource();
-}
-
-void MatrixSearch::reset_pointers_to_null() {
- dict_trie_ = NULL;
- user_dict_ = NULL;
- spl_parser_ = NULL;
-
- share_buf_ = NULL;
-
- // The following four buffers are used for decoding, and they are based on
- // share_buf_, no need to delete them.
- mtrx_nd_pool_ = NULL;
- dmi_pool_ = NULL;
- matrix_ = NULL;
- dep_ = NULL;
-
- // Based on share_buf_, no need to delete them.
- npre_items_ = NULL;
-}
-
-bool MatrixSearch::alloc_resource() {
- free_resource();
-
- dict_trie_ = new DictTrie();
- user_dict_ = static_cast<AtomDictBase*>(new UserDict());
- spl_parser_ = new SpellingParser();
-
- size_t mtrx_nd_size = sizeof(MatrixNode) * kMtrxNdPoolSize;
- mtrx_nd_size = align_to_size_t(mtrx_nd_size) / sizeof(size_t);
- size_t dmi_size = sizeof(DictMatchInfo) * kDmiPoolSize;
- dmi_size = align_to_size_t(dmi_size) / sizeof(size_t);
- size_t matrix_size = sizeof(MatrixRow) * kMaxRowNum;
- matrix_size = align_to_size_t(matrix_size) / sizeof(size_t);
- size_t dep_size = sizeof(DictExtPara);
- dep_size = align_to_size_t(dep_size) / sizeof(size_t);
-
- // share_buf's size is determined by the buffers for search.
- share_buf_ = new size_t[mtrx_nd_size + dmi_size + matrix_size + dep_size];
-
- if (NULL == dict_trie_ || NULL == user_dict_ || NULL == spl_parser_ ||
- NULL == share_buf_)
- return false;
-
- // The buffers for search are based on the share buffer
- mtrx_nd_pool_ = reinterpret_cast<MatrixNode*>(share_buf_);
- dmi_pool_ = reinterpret_cast<DictMatchInfo*>(share_buf_ + mtrx_nd_size);
- matrix_ = reinterpret_cast<MatrixRow*>(share_buf_ + mtrx_nd_size + dmi_size);
- dep_ = reinterpret_cast<DictExtPara*>
- (share_buf_ + mtrx_nd_size + dmi_size + matrix_size);
-
- // The prediction buffer is also based on the share buffer.
- npre_items_ = reinterpret_cast<NPredictItem*>(share_buf_);
- npre_items_len_ = (mtrx_nd_size + dmi_size + matrix_size + dep_size) *
- sizeof(size_t) / sizeof(NPredictItem);
- return true;
-}
-
-void MatrixSearch::free_resource() {
- if (NULL != dict_trie_)
- delete dict_trie_;
-
- if (NULL != user_dict_)
- delete user_dict_;
-
- if (NULL != spl_parser_)
- delete spl_parser_;
-
- if (NULL != share_buf_)
- delete [] share_buf_;
-
- reset_pointers_to_null();
-}
-
-bool MatrixSearch::init(const char *fn_sys_dict, const char *fn_usr_dict) {
- if (NULL == fn_sys_dict || NULL == fn_usr_dict)
- return false;
-
- if (!alloc_resource())
- return false;
-
- if (!dict_trie_->load_dict(fn_sys_dict, 1, kSysDictIdEnd))
- return false;
-
- // If engine fails to load the user dictionary, reset the user dictionary
- // to NULL.
- if (!user_dict_->load_dict(fn_usr_dict, kUserDictIdStart, kUserDictIdEnd)) {
- delete user_dict_;
- user_dict_ = NULL;
- } else{
- user_dict_->set_total_lemma_count_of_others(NGram::kSysDictTotalFreq);
- }
-
- reset_search0();
-
- inited_ = true;
- return true;
-}
-
-bool MatrixSearch::init_fd(int sys_fd, long start_offset, long length,
- const char *fn_usr_dict) {
- if (NULL == fn_usr_dict)
- return false;
-
- if (!alloc_resource())
- return false;
-
- if (!dict_trie_->load_dict_fd(sys_fd, start_offset, length, 1, kSysDictIdEnd))
- return false;
-
- if (!user_dict_->load_dict(fn_usr_dict, kUserDictIdStart, kUserDictIdEnd)) {
- delete user_dict_;
- user_dict_ = NULL;
- } else {
- user_dict_->set_total_lemma_count_of_others(NGram::kSysDictTotalFreq);
- }
-
- reset_search0();
-
- inited_ = true;
- return true;
-}
-
-void MatrixSearch::set_max_lens(size_t max_sps_len, size_t max_hzs_len) {
- if (0 != max_sps_len)
- max_sps_len_ = max_sps_len;
- if (0 != max_hzs_len)
- max_hzs_len_ = max_hzs_len;
-}
-
-void MatrixSearch::close() {
- flush_cache();
- free_resource();
- inited_ = false;
-}
-
-void MatrixSearch::flush_cache() {
- if (NULL != user_dict_)
- user_dict_->flush_cache();
-}
-
-void MatrixSearch::set_xi_an_switch(bool xi_an_enabled) {
- xi_an_enabled_ = xi_an_enabled;
-}
-
-bool MatrixSearch::get_xi_an_switch() {
- return xi_an_enabled_;
-}
-
-bool MatrixSearch::reset_search() {
- if (!inited_)
- return false;
- return reset_search0();
-}
-
-bool MatrixSearch::reset_search0() {
- if (!inited_)
- return false;
-
- pys_decoded_len_ = 0;
- mtrx_nd_pool_used_ = 0;
- dmi_pool_used_ = 0;
-
- // Get a MatrixNode from the pool
- matrix_[0].mtrx_nd_pos = mtrx_nd_pool_used_;
- matrix_[0].mtrx_nd_num = 1;
- mtrx_nd_pool_used_ += 1;
-
- // Update the node, and make it to be a starting node
- MatrixNode *node = mtrx_nd_pool_ + matrix_[0].mtrx_nd_pos;
- node->id = 0;
- node->score = 0;
- node->from = NULL;
- node->step = 0;
- node->dmi_fr = (PoolPosType)-1;
-
- matrix_[0].dmi_pos = 0;
- matrix_[0].dmi_num = 0;
- matrix_[0].dmi_has_full_id = 1;
- matrix_[0].mtrx_nd_fixed = node;
-
- lma_start_[0] = 0;
- fixed_lmas_ = 0;
- spl_start_[0] = 0;
- fixed_hzs_ = 0;
-
- dict_trie_->reset_milestones(0, 0);
- if (NULL != user_dict_)
- user_dict_->reset_milestones(0, 0);
-
- return true;
-}
-
-bool MatrixSearch::reset_search(size_t ch_pos, bool clear_fixed_this_step,
- bool clear_dmi_this_step,
- bool clear_mtrx_this_step) {
- if (!inited_ || ch_pos > pys_decoded_len_ || ch_pos >= kMaxRowNum)
- return false;
-
- if (0 == ch_pos) {
- reset_search0();
- } else {
- // Prepare mile stones of this step to clear.
- MileStoneHandle *dict_handles_to_clear = NULL;
- if (clear_dmi_this_step && matrix_[ch_pos].dmi_num > 0) {
- dict_handles_to_clear = dmi_pool_[matrix_[ch_pos].dmi_pos].dict_handles;
+ MatrixSearch::MatrixSearch() {
+ inited_ = false;
+ spl_trie_ = SpellingTrie::get_cpinstance();
+ reset_pointers_to_null();
+ pys_decoded_len_ = 0;
+ mtrx_nd_pool_used_ = 0;
+ dmi_pool_used_ = 0;
+ xi_an_enabled_ = false;
+ dmi_c_phrase_ = false;
+ assert ( kMaxSearchSteps > 0 );
+ max_sps_len_ = kMaxSearchSteps - 1;
+ max_hzs_len_ = kMaxSearchSteps;
}
- // If there are more steps, and this step is not allowed to clear, find
- // milestones of next step.
- if (pys_decoded_len_ > ch_pos && !clear_dmi_this_step) {
- dict_handles_to_clear = NULL;
- if (matrix_[ch_pos + 1].dmi_num > 0) {
- dict_handles_to_clear =
- dmi_pool_[matrix_[ch_pos + 1].dmi_pos].dict_handles;
- }
+ MatrixSearch::~MatrixSearch() {
+ free_resource();
}
- if (NULL != dict_handles_to_clear) {
- dict_trie_->reset_milestones(ch_pos, dict_handles_to_clear[0]);
- if (NULL != user_dict_)
- user_dict_->reset_milestones(ch_pos, dict_handles_to_clear[1]);
+ void MatrixSearch::reset_pointers_to_null() {
+ dict_trie_ = NULL;
+ user_dict_ = NULL;
+ spl_parser_ = NULL;
+ share_buf_ = NULL;
+ // The following four buffers are used for decoding, and they are based on
+ // share_buf_, no need to delete them.
+ mtrx_nd_pool_ = NULL;
+ dmi_pool_ = NULL;
+ matrix_ = NULL;
+ dep_ = NULL;
+ // Based on share_buf_, no need to delete them.
+ npre_items_ = NULL;
}
- pys_decoded_len_ = ch_pos;
-
- if (clear_dmi_this_step) {
- dmi_pool_used_ = matrix_[ch_pos - 1].dmi_pos
- + matrix_[ch_pos - 1].dmi_num;
- matrix_[ch_pos].dmi_num = 0;
- } else {
- dmi_pool_used_ = matrix_[ch_pos].dmi_pos + matrix_[ch_pos].dmi_num;
+ bool MatrixSearch::alloc_resource() {
+ free_resource();
+ dict_trie_ = new DictTrie();
+ user_dict_ = static_cast<AtomDictBase *> ( new UserDict() );
+ spl_parser_ = new SpellingParser();
+ size_t mtrx_nd_size = sizeof ( MatrixNode ) * kMtrxNdPoolSize;
+ mtrx_nd_size = align_to_size_t ( mtrx_nd_size ) / sizeof ( size_t );
+ size_t dmi_size = sizeof ( DictMatchInfo ) * kDmiPoolSize;
+ dmi_size = align_to_size_t ( dmi_size ) / sizeof ( size_t );
+ size_t matrix_size = sizeof ( MatrixRow ) * kMaxRowNum;
+ matrix_size = align_to_size_t ( matrix_size ) / sizeof ( size_t );
+ size_t dep_size = sizeof ( DictExtPara );
+ dep_size = align_to_size_t ( dep_size ) / sizeof ( size_t );
+ // share_buf's size is determined by the buffers for search.
+ share_buf_ = new size_t[mtrx_nd_size + dmi_size + matrix_size + dep_size];
+ if ( NULL == dict_trie_ || NULL == user_dict_ || NULL == spl_parser_ ||
+ NULL == share_buf_ )
+ { return false; }
+ // The buffers for search are based on the share buffer
+ mtrx_nd_pool_ = reinterpret_cast<MatrixNode *> ( share_buf_ );
+ dmi_pool_ = reinterpret_cast<DictMatchInfo *> ( share_buf_ + mtrx_nd_size );
+ matrix_ = reinterpret_cast<MatrixRow *> ( share_buf_ + mtrx_nd_size + dmi_size );
+ dep_ = reinterpret_cast<DictExtPara *>
+ ( share_buf_ + mtrx_nd_size + dmi_size + matrix_size );
+ // The prediction buffer is also based on the share buffer.
+ npre_items_ = reinterpret_cast<NPredictItem *> ( share_buf_ );
+ npre_items_len_ = ( mtrx_nd_size + dmi_size + matrix_size + dep_size ) *
+ sizeof ( size_t ) / sizeof ( NPredictItem );
+ return true;
}
- if (clear_mtrx_this_step) {
- mtrx_nd_pool_used_ = matrix_[ch_pos - 1].mtrx_nd_pos
- + matrix_[ch_pos - 1].mtrx_nd_num;
- matrix_[ch_pos].mtrx_nd_num = 0;
- } else {
- mtrx_nd_pool_used_ = matrix_[ch_pos].mtrx_nd_pos
- + matrix_[ch_pos].mtrx_nd_num;
+ void MatrixSearch::free_resource() {
+ if ( NULL != dict_trie_ )
+ { delete dict_trie_; }
+ if ( NULL != user_dict_ )
+ { delete user_dict_; }
+ if ( NULL != spl_parser_ )
+ { delete spl_parser_; }
+ if ( NULL != share_buf_ )
+ { delete [] share_buf_; }
+ reset_pointers_to_null();
}
- // Modify fixed_hzs_
- if (fixed_hzs_ > 0 &&
- ((kLemmaIdComposing != lma_id_[0]) ||
- (kLemmaIdComposing == lma_id_[0] &&
- spl_start_[c_phrase_.length] <= ch_pos))) {
- size_t fixed_ch_pos = ch_pos;
- if (clear_fixed_this_step)
- fixed_ch_pos = fixed_ch_pos > 0 ? fixed_ch_pos - 1 : 0;
- while (NULL == matrix_[fixed_ch_pos].mtrx_nd_fixed && fixed_ch_pos > 0)
- fixed_ch_pos--;
-
- fixed_lmas_ = 0;
- fixed_hzs_ = 0;
- if (fixed_ch_pos > 0) {
- while (spl_start_[fixed_hzs_] < fixed_ch_pos)
- fixed_hzs_++;
- assert(spl_start_[fixed_hzs_] == fixed_ch_pos);
-
- while (lma_start_[fixed_lmas_] < fixed_hzs_)
- fixed_lmas_++;
- assert(lma_start_[fixed_lmas_] == fixed_hzs_);
- }
-
- // Re-search the Pinyin string for the unlocked lemma
- // which was previously fixed.
- //
- // Prepare mile stones of this step to clear.
- MileStoneHandle *dict_handles_to_clear = NULL;
- if (clear_dmi_this_step && ch_pos == fixed_ch_pos &&
- matrix_[fixed_ch_pos].dmi_num > 0) {
- dict_handles_to_clear = dmi_pool_[matrix_[fixed_ch_pos].dmi_pos].dict_handles;
- }
-
- // If there are more steps, and this step is not allowed to clear, find
- // milestones of next step.
- if (pys_decoded_len_ > fixed_ch_pos && !clear_dmi_this_step) {
- dict_handles_to_clear = NULL;
- if (matrix_[fixed_ch_pos + 1].dmi_num > 0) {
- dict_handles_to_clear =
- dmi_pool_[matrix_[fixed_ch_pos + 1].dmi_pos].dict_handles;
- }
- }
-
- if (NULL != dict_handles_to_clear) {
- dict_trie_->reset_milestones(fixed_ch_pos, dict_handles_to_clear[0]);
- if (NULL != user_dict_)
- user_dict_->reset_milestones(fixed_ch_pos, dict_handles_to_clear[1]);
- }
-
-
- pys_decoded_len_ = fixed_ch_pos;
-
- if (clear_dmi_this_step && ch_pos == fixed_ch_pos) {
- dmi_pool_used_ = matrix_[fixed_ch_pos - 1].dmi_pos
- + matrix_[fixed_ch_pos - 1].dmi_num;
- matrix_[fixed_ch_pos].dmi_num = 0;
- } else {
- dmi_pool_used_ = matrix_[fixed_ch_pos].dmi_pos +
- matrix_[fixed_ch_pos].dmi_num;
- }
-
- if (clear_mtrx_this_step && ch_pos == fixed_ch_pos) {
- mtrx_nd_pool_used_ = matrix_[fixed_ch_pos - 1].mtrx_nd_pos
- + matrix_[fixed_ch_pos - 1].mtrx_nd_num;
- matrix_[fixed_ch_pos].mtrx_nd_num = 0;
- } else {
- mtrx_nd_pool_used_ = matrix_[fixed_ch_pos].mtrx_nd_pos
- + matrix_[fixed_ch_pos].mtrx_nd_num;
- }
-
- for (uint16 re_pos = fixed_ch_pos; re_pos < ch_pos; re_pos++) {
- add_char(pys_[re_pos]);
- }
- } else if (fixed_hzs_ > 0 && kLemmaIdComposing == lma_id_[0]) {
- for (uint16 subpos = 0; subpos < c_phrase_.sublma_num; subpos++) {
- uint16 splpos_begin = c_phrase_.sublma_start[subpos];
- uint16 splpos_end = c_phrase_.sublma_start[subpos + 1];
- for (uint16 splpos = splpos_begin; splpos < splpos_end; splpos++) {
- // If ch_pos is in this spelling
- uint16 spl_start = c_phrase_.spl_start[splpos];
- uint16 spl_end = c_phrase_.spl_start[splpos + 1];
- if (ch_pos >= spl_start && ch_pos < spl_end) {
- // Clear everything after this position
- c_phrase_.chn_str[splpos] = static_cast<char16>('\0');
- c_phrase_.sublma_start[subpos + 1] = splpos;
- c_phrase_.sublma_num = subpos + 1;
- c_phrase_.length = splpos;
-
- if (splpos == splpos_begin) {
- c_phrase_.sublma_num = subpos;
- }
- }
+ bool MatrixSearch::init ( const char *fn_sys_dict, const char *fn_usr_dict ) {
+ if ( NULL == fn_sys_dict || NULL == fn_usr_dict )
+ { return false; }
+ if ( !alloc_resource() )
+ { return false; }
+ if ( !dict_trie_->load_dict ( fn_sys_dict, 1, kSysDictIdEnd ) )
+ { return false; }
+ // If engine fails to load the user dictionary, reset the user dictionary
+ // to NULL.
+ if ( !user_dict_->load_dict ( fn_usr_dict, kUserDictIdStart, kUserDictIdEnd ) ) {
+ delete user_dict_;
+ user_dict_ = NULL;
+ } else {
+ user_dict_->set_total_lemma_count_of_others ( NGram::kSysDictTotalFreq );
}
- }
-
- // Extend the composing phrase.
- reset_search0();
- dmi_c_phrase_ = true;
- uint16 c_py_pos = 0;
- while (c_py_pos < spl_start_[c_phrase_.length]) {
- bool b_ac_tmp = add_char(pys_[c_py_pos]);
- assert(b_ac_tmp);
- c_py_pos++;
- }
- dmi_c_phrase_ = false;
-
- lma_id_num_ = 1;
- fixed_lmas_ = 1;
- fixed_lmas_no1_[0] = 0; // A composing string is always modified.
- fixed_hzs_ = c_phrase_.length;
- lma_start_[1] = fixed_hzs_;
- lma_id_[0] = kLemmaIdComposing;
- matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ +
- matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos;
- }
- }
-
- return true;
-}
-
-void MatrixSearch::del_in_pys(size_t start, size_t len) {
- while (start < kMaxRowNum - len && '\0' != pys_[start]) {
- pys_[start] = pys_[start + len];
- start++;
- }
-}
-
-size_t MatrixSearch::search(const char *py, size_t py_len) {
- if (!inited_ || NULL == py)
- return 0;
-
- // If the search Pinyin string is too long, it will be truncated.
- if (py_len > kMaxRowNum - 1)
- py_len = kMaxRowNum - 1;
-
- // Compare the new string with the previous one. Find their prefix to
- // increase search efficiency.
- size_t ch_pos = 0;
- for (ch_pos = 0; ch_pos < pys_decoded_len_; ch_pos++) {
- if ('\0' == py[ch_pos] || py[ch_pos] != pys_[ch_pos])
- break;
- }
-
- bool clear_fix = true;
- if (ch_pos == pys_decoded_len_)
- clear_fix = false;
-
- reset_search(ch_pos, clear_fix, false, false);
-
- memcpy(pys_ + ch_pos, py + ch_pos, py_len - ch_pos);
- pys_[py_len] = '\0';
-
- while ('\0' != pys_[ch_pos]) {
- if (!add_char(py[ch_pos])) {
- pys_decoded_len_ = ch_pos;
- break;
- }
- ch_pos++;
- }
-
- // Get spelling ids and starting positions.
- get_spl_start_id();
-
- // If there are too many spellings, remove the last letter until the spelling
- // number is acceptable.
- while (spl_id_num_ > 9) {
- py_len--;
- reset_search(py_len, false, false, false);
- pys_[py_len] = '\0';
- get_spl_start_id();
- }
-
- prepare_candidates();
-
- if (kPrintDebug0) {
- printf("--Matrix Node Pool Used: %d\n", mtrx_nd_pool_used_);
- printf("--DMI Pool Used: %d\n", dmi_pool_used_);
-
- if (kPrintDebug1) {
- for (PoolPosType pos = 0; pos < dmi_pool_used_; pos++) {
- debug_print_dmi(pos, 1);
- }
- }
- }
-
- return ch_pos;
-}
-
-size_t MatrixSearch::delsearch(size_t pos, bool is_pos_in_splid,
- bool clear_fixed_this_step) {
- if (!inited_)
- return 0;
-
- size_t reset_pos = pos;
-
- // Out of range for both Pinyin mode and Spelling id mode.
- if (pys_decoded_len_ <= pos) {
- del_in_pys(pos, 1);
-
- reset_pos = pys_decoded_len_;
- // Decode the string after the un-decoded position
- while ('\0' != pys_[reset_pos]) {
- if (!add_char(pys_[reset_pos])) {
- pys_decoded_len_ = reset_pos;
- break;
- }
- reset_pos++;
- }
- get_spl_start_id();
- prepare_candidates();
- return pys_decoded_len_;
- }
-
- // Spelling id mode, but out of range.
- if (is_pos_in_splid && spl_id_num_ <= pos)
- return pys_decoded_len_;
-
- // Begin to handle two modes respectively.
- // Pinyin mode by default
- size_t c_py_len = 0; // The length of composing phrase's Pinyin
- size_t del_py_len = 1;
- if (!is_pos_in_splid) {
- // Pinyin mode is only allowed to delete beyond the fixed lemmas.
- if (fixed_lmas_ > 0 && pos < spl_start_[lma_start_[fixed_lmas_]])
- return pys_decoded_len_;
-
- del_in_pys(pos, 1);
-
- // If the deleted character is just the one after the last fixed lemma
- if (pos == spl_start_[lma_start_[fixed_lmas_]]) {
- // If all fixed lemmas have been merged, and the caller of the function
- // request to unlock the last fixed lemma.
- if (kLemmaIdComposing == lma_id_[0] && clear_fixed_this_step) {
- // Unlock the last sub lemma in the composing phrase. Because it is not
- // easy to unlock it directly. Instead, we re-decode the modified
- // composing phrase.
- c_phrase_.sublma_num--;
- c_phrase_.length = c_phrase_.sublma_start[c_phrase_.sublma_num];
- reset_pos = spl_start_[c_phrase_.length];
- c_py_len = reset_pos;
- }
- }
- } else {
- del_py_len = spl_start_[pos + 1] - spl_start_[pos];
-
- del_in_pys(spl_start_[pos], del_py_len);
-
- if (pos >= lma_start_[fixed_lmas_]) {
- c_py_len = 0;
- reset_pos = spl_start_[pos + 1] - del_py_len;
- } else {
- c_py_len = spl_start_[lma_start_[fixed_lmas_]] - del_py_len;
- reset_pos = c_py_len;
- if (c_py_len > 0)
- merge_fixed_lmas(pos);
- }
- }
-
- if (c_py_len > 0) {
- assert(c_phrase_.length > 0 && c_py_len ==
- c_phrase_.spl_start[c_phrase_.sublma_start[c_phrase_.sublma_num]]);
- // The composing phrase is valid, reset all search space,
- // and begin a new search which will only extend the composing
- // phrase.
- reset_search0();
-
- dmi_c_phrase_ = true;
- // Extend the composing phrase.
- uint16 c_py_pos = 0;
- while (c_py_pos < c_py_len) {
- bool b_ac_tmp = add_char(pys_[c_py_pos]);
- assert(b_ac_tmp);
- c_py_pos++;
- }
- dmi_c_phrase_ = false;
-
- // Fixd the composing phrase as the first choice.
- lma_id_num_ = 1;
- fixed_lmas_ = 1;
- fixed_lmas_no1_[0] = 0; // A composing string is always modified.
- fixed_hzs_ = c_phrase_.length;
- lma_start_[1] = fixed_hzs_;
- lma_id_[0] = kLemmaIdComposing;
- matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ +
- matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos;
- } else {
- // Reseting search only clear pys_decoded_len_, but the string is kept.
- reset_search(reset_pos, clear_fixed_this_step, false, false);
- }
-
- // Decode the string after the delete position.
- while ('\0' != pys_[reset_pos]) {
- if (!add_char(pys_[reset_pos])) {
- pys_decoded_len_ = reset_pos;
- break;
- }
- reset_pos++;
- }
-
- get_spl_start_id();
- prepare_candidates();
- return pys_decoded_len_;
-}
-
-size_t MatrixSearch::get_candidate_num() {
- if (!inited_ || 0 == pys_decoded_len_ ||
- 0 == matrix_[pys_decoded_len_].mtrx_nd_num)
- return 0;
-
- return 1 + lpi_total_;
-}
-
-char16* MatrixSearch::get_candidate(size_t cand_id, char16 *cand_str,
- size_t max_len) {
- if (!inited_ || 0 == pys_decoded_len_ || NULL == cand_str)
- return NULL;
-
- if (0 == cand_id) {
- return get_candidate0(cand_str, max_len, NULL, false);
- } else {
- cand_id--;
- }
-
- // For this case: the current sentence is a word only, and the user fixed it,
- // so the result will be fixed to the sentence space, and
- // lpi_total_ will be set to 0.
- if (0 == lpi_total_) {
- return get_candidate0(cand_str, max_len, NULL, false);
- }
-
- LemmaIdType id = lpi_items_[cand_id].id;
- char16 s[kMaxLemmaSize + 1];
-
- uint16 s_len = lpi_items_[cand_id].lma_len;
- if (s_len > 1) {
- s_len = get_lemma_str(id, s, kMaxLemmaSize + 1);
- } else {
- // For a single character, Hanzi is ready.
- s[0] = lpi_items_[cand_id].hanzi;
- s[1] = static_cast<char16>(0);
- }
-
- if (s_len > 0 && max_len > s_len) {
- utf16_strncpy(cand_str, s, s_len);
- cand_str[s_len] = (char16)'\0';
- return cand_str;
- }
-
- return NULL;
-}
-
-void MatrixSearch::update_dict_freq() {
- if (NULL != user_dict_) {
- // Update the total frequency of all lemmas, including system lemmas and
- // user dictionary lemmas.
- size_t total_freq = user_dict_->get_total_lemma_count();
- dict_trie_->set_total_lemma_count_of_others(total_freq);
- }
-}
-
-bool MatrixSearch::add_lma_to_userdict(uint16 lma_fr, uint16 lma_to,
- float score) {
- if (lma_to - lma_fr <= 1 || NULL == user_dict_)
- return false;
-
- char16 word_str[kMaxLemmaSize + 1];
- uint16 spl_ids[kMaxLemmaSize];
-
- uint16 spl_id_fr = 0;
-
- for (uint16 pos = lma_fr; pos < lma_to; pos++) {
- LemmaIdType lma_id = lma_id_[pos];
- if (is_user_lemma(lma_id)) {
- user_dict_->update_lemma(lma_id, 1, true);
+ reset_search0();
+ inited_ = true;
+ return true;
}
- uint16 lma_len = lma_start_[pos + 1] - lma_start_[pos];
- utf16_strncpy(spl_ids + spl_id_fr, spl_id_ + lma_start_[pos], lma_len);
- uint16 tmp = get_lemma_str(lma_id, word_str + spl_id_fr,
- kMaxLemmaSize + 1 - spl_id_fr);
- assert(tmp == lma_len);
-
- tmp = get_lemma_splids(lma_id, spl_ids + spl_id_fr, lma_len, true);
- if (tmp != lma_len) {
- return false;
+ bool MatrixSearch::init_fd ( int sys_fd, long start_offset, long length,
+ const char *fn_usr_dict ) {
+ if ( NULL == fn_usr_dict )
+ { return false; }
+ if ( !alloc_resource() )
+ { return false; }
+ if ( !dict_trie_->load_dict_fd ( sys_fd, start_offset, length, 1, kSysDictIdEnd ) )
+ { return false; }
+ if ( !user_dict_->load_dict ( fn_usr_dict, kUserDictIdStart, kUserDictIdEnd ) ) {
+ delete user_dict_;
+ user_dict_ = NULL;
+ } else {
+ user_dict_->set_total_lemma_count_of_others ( NGram::kSysDictTotalFreq );
+ }
+ reset_search0();
+ inited_ = true;
+ return true;
}
- spl_id_fr += lma_len;
- }
-
- assert(spl_id_fr <= kMaxLemmaSize);
-
- return user_dict_->put_lemma(static_cast<char16*>(word_str), spl_ids,
- spl_id_fr, 1);
-}
-
-void MatrixSearch::debug_print_dmi(PoolPosType dmi_pos, uint16 nest_level) {
- if (dmi_pos >= dmi_pool_used_) return;
-
- DictMatchInfo *dmi = dmi_pool_ + dmi_pos;
-
- if (1 == nest_level) {
- printf("-----------------%d\'th DMI node begin----------->\n", dmi_pos);
- }
- if (dmi->dict_level > 1) {
- debug_print_dmi(dmi->dmi_fr, nest_level + 1);
- }
- printf("---%d\n", dmi->dict_level);
- printf(" MileStone: %x, %x\n", dmi->dict_handles[0], dmi->dict_handles[1]);
- printf(" Spelling : %s, %d\n", SpellingTrie::get_instance().
- get_spelling_str(dmi->spl_id), dmi->spl_id);
- printf(" Total Pinyin Len: %d\n", dmi->splstr_len);
- if (1 == nest_level) {
- printf("<----------------%d\'th DMI node end--------------\n\n", dmi_pos);
- }
-}
-
-bool MatrixSearch::try_add_cand0_to_userdict() {
- size_t new_cand_num = get_candidate_num();
- if (fixed_hzs_ > 0 && 1 == new_cand_num) {
- float score_from = 0;
- uint16 lma_id_from = 0;
- uint16 pos = 0;
- bool modified = false;
- while (pos < fixed_lmas_) {
- if (lma_start_[pos + 1] - lma_start_[lma_id_from] >
- static_cast<uint16>(kMaxLemmaSize)) {
- float score_to_add =
- mtrx_nd_pool_[matrix_[spl_start_[lma_start_[pos]]]
- .mtrx_nd_pos].score - score_from;
- if (modified) {
- score_to_add += 1.0;
- if (score_to_add > NGram::kMaxScore) {
- score_to_add = NGram::kMaxScore;
- }
- add_lma_to_userdict(lma_id_from, pos, score_to_add);
- }
- lma_id_from = pos;
- score_from += score_to_add;
-
- // Clear the flag for next user lemma.
- modified = false;
- }
-
- if (0 == fixed_lmas_no1_[pos]) {
- modified = true;
- }
- pos++;
+ void MatrixSearch::set_max_lens ( size_t max_sps_len, size_t max_hzs_len ) {
+ if ( 0 != max_sps_len )
+ { max_sps_len_ = max_sps_len; }
+ if ( 0 != max_hzs_len )
+ { max_hzs_len_ = max_hzs_len; }
}
- // Single-char word is not allowed to add to userdict.
- if (lma_start_[pos] - lma_start_[lma_id_from] > 1) {
- float score_to_add =
- mtrx_nd_pool_[matrix_[spl_start_[lma_start_[pos]]]
- .mtrx_nd_pos].score - score_from;
- if (modified) {
- score_to_add += 1.0;
- if (score_to_add > NGram::kMaxScore) {
- score_to_add = NGram::kMaxScore;
- }
- add_lma_to_userdict(lma_id_from, pos, score_to_add);
- }
+ void MatrixSearch::close() {
+ flush_cache();
+ free_resource();
+ inited_ = false;
}
- }
- return true;
-}
-
-// Choose a candidate, and give new candidates for next step.
-// If user finishes selection, we will try to communicate with user dictionary
-// to add new items or update score of some existing items.
-//
-// Basic rule:
-// 1. If user selects the first choice:
-// 1.1. If the first choice is not a sentence, instead, it is a lemma:
-// 1.1.1. If the first choice is a user lemma, notify the user
-// dictionary that a user lemma is hit, and add occuring count
-// by 1.
-// 1.1.2. If the first choice is a system lemma, do nothing.
-// 1.2. If the first choice is a sentence containing more than one lemma:
-// 1.2.1. The whole sentence will be added as a user lemma. If the
-// sentence contains user lemmas, -> hit, and add occuring count
-// by 1.
-size_t MatrixSearch::choose(size_t cand_id) {
- if (!inited_ || 0 == pys_decoded_len_)
- return 0;
- if (0 == cand_id) {
- fixed_hzs_ = spl_id_num_;
- matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ +
- matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos;
- for (size_t pos = fixed_lmas_; pos < lma_id_num_; pos++) {
- fixed_lmas_no1_[pos] = 1;
+ void MatrixSearch::flush_cache() {
+ if ( NULL != user_dict_ )
+ { user_dict_->flush_cache(); }
}
- fixed_lmas_ = lma_id_num_;
- lpi_total_ = 0; // Clean all other candidates.
- // 1. It is the first choice
- if (1 == lma_id_num_) {
- // 1.1. The first choice is not a sentence but a lemma
- if (is_user_lemma(lma_id_[0])) {
- // 1.1.1. The first choice is a user lemma, notify the user dictionary
- // that it is hit.
- if (NULL != user_dict_)
- user_dict_->update_lemma(lma_id_[0], 1, true);
- } else {
- // 1.1.2. do thing for a system lemma.
- }
- } else {
- // 1.2. The first choice is a sentence.
- // 1.2.1 Try to add the whole sentence to user dictionary, the whole
- // sentence may be splitted into many items.
- if (NULL != user_dict_) {
- try_add_cand0_to_userdict();
- }
+ void MatrixSearch::set_xi_an_switch ( bool xi_an_enabled ) {
+ xi_an_enabled_ = xi_an_enabled;
}
- update_dict_freq();
- return 1;
- } else {
- cand_id--;
- }
-
- // 2. It is not the full sentence candidate.
- // Find the length of the candidate.
- LemmaIdType id_chosen = lpi_items_[cand_id].id;
- LmaScoreType score_chosen = lpi_items_[cand_id].psb;
- size_t cand_len = lpi_items_[cand_id].lma_len;
- assert(cand_len > 0);
-
- // Notify the atom dictionary that this item is hit.
- if (is_user_lemma(id_chosen)) {
- if (NULL != user_dict_) {
- user_dict_->update_lemma(id_chosen, 1, true);
+ bool MatrixSearch::get_xi_an_switch() {
+ return xi_an_enabled_;
}
- update_dict_freq();
- }
-
- // 3. Fixed the chosen item.
- // 3.1 Get the steps number.
- size_t step_fr = spl_start_[fixed_hzs_];
- size_t step_to = spl_start_[fixed_hzs_ + cand_len];
-
- // 3.2 Save the length of the original string.
- size_t pys_decoded_len = pys_decoded_len_;
-
- // 3.2 Reset the space of the fixed part.
- reset_search(step_to, false, false, true);
-
- // 3.3 For the last character of the fixed part, the previous DMI
- // information will be kept, while the MTRX information will be re-extended,
- // and only one node will be extended.
- matrix_[step_to].mtrx_nd_num = 0;
-
- LmaPsbItem lpi_item;
- lpi_item.psb = score_chosen;
- lpi_item.id = id_chosen;
-
- PoolPosType step_to_dmi_fr = match_dmi(step_to,
- spl_id_ + fixed_hzs_, cand_len);
- assert(step_to_dmi_fr != static_cast<PoolPosType>(-1));
- extend_mtrx_nd(matrix_[step_fr].mtrx_nd_fixed, &lpi_item, 1,
- step_to_dmi_fr, step_to);
-
- matrix_[step_to].mtrx_nd_fixed = mtrx_nd_pool_ + matrix_[step_to].mtrx_nd_pos;
- mtrx_nd_pool_used_ = matrix_[step_to].mtrx_nd_pos +
- matrix_[step_to].mtrx_nd_num;
-
- if (id_chosen == lma_id_[fixed_lmas_])
- fixed_lmas_no1_[fixed_lmas_] = 1;
- else
- fixed_lmas_no1_[fixed_lmas_] = 0;
- lma_id_[fixed_lmas_] = id_chosen;
- lma_start_[fixed_lmas_ + 1] = lma_start_[fixed_lmas_] + cand_len;
- fixed_lmas_++;
- fixed_hzs_ = fixed_hzs_ + cand_len;
-
- while (step_to != pys_decoded_len) {
- bool b = add_char(pys_[step_to]);
- assert(b);
- step_to++;
- }
-
- if (fixed_hzs_ < spl_id_num_) {
- prepare_candidates();
- } else {
- lpi_total_ = 0;
- if (NULL != user_dict_) {
- try_add_cand0_to_userdict();
+ bool MatrixSearch::reset_search() {
+ if ( !inited_ )
+ { return false; }
+ return reset_search0();
}
- }
-
- return get_candidate_num();
-}
-
-size_t MatrixSearch::cancel_last_choice() {
- if (!inited_ || 0 == pys_decoded_len_)
- return 0;
- size_t step_start = 0;
- if (fixed_hzs_ > 0) {
- size_t step_end = spl_start_[fixed_hzs_];
- MatrixNode *end_node = matrix_[step_end].mtrx_nd_fixed;
- assert(NULL != end_node);
-
- step_start = end_node->from->step;
-
- if (step_start > 0) {
- DictMatchInfo *dmi = dmi_pool_ + end_node->dmi_fr;
- fixed_hzs_ -= dmi->dict_level;
- } else {
- fixed_hzs_ = 0;
+ bool MatrixSearch::reset_search0() {
+ if ( !inited_ )
+ { return false; }
+ pys_decoded_len_ = 0;
+ mtrx_nd_pool_used_ = 0;
+ dmi_pool_used_ = 0;
+ // Get a MatrixNode from the pool
+ matrix_[0].mtrx_nd_pos = mtrx_nd_pool_used_;
+ matrix_[0].mtrx_nd_num = 1;
+ mtrx_nd_pool_used_ += 1;
+ // Update the node, and make it to be a starting node
+ MatrixNode *node = mtrx_nd_pool_ + matrix_[0].mtrx_nd_pos;
+ node->id = 0;
+ node->score = 0;
+ node->from = NULL;
+ node->step = 0;
+ node->dmi_fr = ( PoolPosType ) - 1;
+ matrix_[0].dmi_pos = 0;
+ matrix_[0].dmi_num = 0;
+ matrix_[0].dmi_has_full_id = 1;
+ matrix_[0].mtrx_nd_fixed = node;
+ lma_start_[0] = 0;
+ fixed_lmas_ = 0;
+ spl_start_[0] = 0;
+ fixed_hzs_ = 0;
+ dict_trie_->reset_milestones ( 0, 0 );
+ if ( NULL != user_dict_ )
+ { user_dict_->reset_milestones ( 0, 0 ); }
+ return true;
}
- reset_search(step_start, false, false, false);
-
- while (pys_[step_start] != '\0') {
- bool b = add_char(pys_[step_start]);
- assert(b);
- step_start++;
+ bool MatrixSearch::reset_search ( size_t ch_pos, bool clear_fixed_this_step,
+ bool clear_dmi_this_step,
+ bool clear_mtrx_this_step ) {
+ if ( !inited_ || ch_pos > pys_decoded_len_ || ch_pos >= kMaxRowNum )
+ { return false; }
+ if ( 0 == ch_pos ) {
+ reset_search0();
+ } else {
+ // Prepare mile stones of this step to clear.
+ MileStoneHandle *dict_handles_to_clear = NULL;
+ if ( clear_dmi_this_step && matrix_[ch_pos].dmi_num > 0 ) {
+ dict_handles_to_clear = dmi_pool_[matrix_[ch_pos].dmi_pos].dict_handles;
+ }
+ // If there are more steps, and this step is not allowed to clear, find
+ // milestones of next step.
+ if ( pys_decoded_len_ > ch_pos && !clear_dmi_this_step ) {
+ dict_handles_to_clear = NULL;
+ if ( matrix_[ch_pos + 1].dmi_num > 0 ) {
+ dict_handles_to_clear =
+ dmi_pool_[matrix_[ch_pos + 1].dmi_pos].dict_handles;
+ }
+ }
+ if ( NULL != dict_handles_to_clear ) {
+ dict_trie_->reset_milestones ( ch_pos, dict_handles_to_clear[0] );
+ if ( NULL != user_dict_ )
+ { user_dict_->reset_milestones ( ch_pos, dict_handles_to_clear[1] ); }
+ }
+ pys_decoded_len_ = ch_pos;
+ if ( clear_dmi_this_step ) {
+ dmi_pool_used_ = matrix_[ch_pos - 1].dmi_pos
+ + matrix_[ch_pos - 1].dmi_num;
+ matrix_[ch_pos].dmi_num = 0;
+ } else {
+ dmi_pool_used_ = matrix_[ch_pos].dmi_pos + matrix_[ch_pos].dmi_num;
+ }
+ if ( clear_mtrx_this_step ) {
+ mtrx_nd_pool_used_ = matrix_[ch_pos - 1].mtrx_nd_pos
+ + matrix_[ch_pos - 1].mtrx_nd_num;
+ matrix_[ch_pos].mtrx_nd_num = 0;
+ } else {
+ mtrx_nd_pool_used_ = matrix_[ch_pos].mtrx_nd_pos
+ + matrix_[ch_pos].mtrx_nd_num;
+ }
+ // Modify fixed_hzs_
+ if ( fixed_hzs_ > 0 &&
+ ( ( kLemmaIdComposing != lma_id_[0] ) ||
+ ( kLemmaIdComposing == lma_id_[0] &&
+ spl_start_[c_phrase_.length] <= ch_pos ) ) ) {
+ size_t fixed_ch_pos = ch_pos;
+ if ( clear_fixed_this_step )
+ { fixed_ch_pos = fixed_ch_pos > 0 ? fixed_ch_pos - 1 : 0; }
+ while ( NULL == matrix_[fixed_ch_pos].mtrx_nd_fixed && fixed_ch_pos > 0 )
+ { fixed_ch_pos--; }
+ fixed_lmas_ = 0;
+ fixed_hzs_ = 0;
+ if ( fixed_ch_pos > 0 ) {
+ while ( spl_start_[fixed_hzs_] < fixed_ch_pos )
+ { fixed_hzs_++; }
+ assert ( spl_start_[fixed_hzs_] == fixed_ch_pos );
+ while ( lma_start_[fixed_lmas_] < fixed_hzs_ )
+ { fixed_lmas_++; }
+ assert ( lma_start_[fixed_lmas_] == fixed_hzs_ );
+ }
+ // Re-search the Pinyin string for the unlocked lemma
+ // which was previously fixed.
+ //
+ // Prepare mile stones of this step to clear.
+ MileStoneHandle *dict_handles_to_clear = NULL;
+ if ( clear_dmi_this_step && ch_pos == fixed_ch_pos &&
+ matrix_[fixed_ch_pos].dmi_num > 0 ) {
+ dict_handles_to_clear = dmi_pool_[matrix_[fixed_ch_pos].dmi_pos].dict_handles;
+ }
+ // If there are more steps, and this step is not allowed to clear, find
+ // milestones of next step.
+ if ( pys_decoded_len_ > fixed_ch_pos && !clear_dmi_this_step ) {
+ dict_handles_to_clear = NULL;
+ if ( matrix_[fixed_ch_pos + 1].dmi_num > 0 ) {
+ dict_handles_to_clear =
+ dmi_pool_[matrix_[fixed_ch_pos + 1].dmi_pos].dict_handles;
+ }
+ }
+ if ( NULL != dict_handles_to_clear ) {
+ dict_trie_->reset_milestones ( fixed_ch_pos, dict_handles_to_clear[0] );
+ if ( NULL != user_dict_ )
+ { user_dict_->reset_milestones ( fixed_ch_pos, dict_handles_to_clear[1] ); }
+ }
+ pys_decoded_len_ = fixed_ch_pos;
+ if ( clear_dmi_this_step && ch_pos == fixed_ch_pos ) {
+ dmi_pool_used_ = matrix_[fixed_ch_pos - 1].dmi_pos
+ + matrix_[fixed_ch_pos - 1].dmi_num;
+ matrix_[fixed_ch_pos].dmi_num = 0;
+ } else {
+ dmi_pool_used_ = matrix_[fixed_ch_pos].dmi_pos +
+ matrix_[fixed_ch_pos].dmi_num;
+ }
+ if ( clear_mtrx_this_step && ch_pos == fixed_ch_pos ) {
+ mtrx_nd_pool_used_ = matrix_[fixed_ch_pos - 1].mtrx_nd_pos
+ + matrix_[fixed_ch_pos - 1].mtrx_nd_num;
+ matrix_[fixed_ch_pos].mtrx_nd_num = 0;
+ } else {
+ mtrx_nd_pool_used_ = matrix_[fixed_ch_pos].mtrx_nd_pos
+ + matrix_[fixed_ch_pos].mtrx_nd_num;
+ }
+ for ( uint16 re_pos = fixed_ch_pos; re_pos < ch_pos; re_pos++ ) {
+ add_char ( pys_[re_pos] );
+ }
+ } else if ( fixed_hzs_ > 0 && kLemmaIdComposing == lma_id_[0] ) {
+ for ( uint16 subpos = 0; subpos < c_phrase_.sublma_num; subpos++ ) {
+ uint16 splpos_begin = c_phrase_.sublma_start[subpos];
+ uint16 splpos_end = c_phrase_.sublma_start[subpos + 1];
+ for ( uint16 splpos = splpos_begin; splpos < splpos_end; splpos++ ) {
+ // If ch_pos is in this spelling
+ uint16 spl_start = c_phrase_.spl_start[splpos];
+ uint16 spl_end = c_phrase_.spl_start[splpos + 1];
+ if ( ch_pos >= spl_start && ch_pos < spl_end ) {
+ // Clear everything after this position
+ c_phrase_.chn_str[splpos] = static_cast<char16> ( '\0' );
+ c_phrase_.sublma_start[subpos + 1] = splpos;
+ c_phrase_.sublma_num = subpos + 1;
+ c_phrase_.length = splpos;
+ if ( splpos == splpos_begin ) {
+ c_phrase_.sublma_num = subpos;
+ }
+ }
+ }
+ }
+ // Extend the composing phrase.
+ reset_search0();
+ dmi_c_phrase_ = true;
+ uint16 c_py_pos = 0;
+ while ( c_py_pos < spl_start_[c_phrase_.length] ) {
+ bool b_ac_tmp = add_char ( pys_[c_py_pos] );
+ assert ( b_ac_tmp );
+ c_py_pos++;
+ }
+ dmi_c_phrase_ = false;
+ lma_id_num_ = 1;
+ fixed_lmas_ = 1;
+ fixed_lmas_no1_[0] = 0; // A composing string is always modified.
+ fixed_hzs_ = c_phrase_.length;
+ lma_start_[1] = fixed_hzs_;
+ lma_id_[0] = kLemmaIdComposing;
+ matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ +
+ matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos;
+ }
+ }
+ return true;
}
- prepare_candidates();
- }
- return get_candidate_num();
-}
-
-size_t MatrixSearch::get_fixedlen() {
- if (!inited_ || 0 == pys_decoded_len_)
- return 0;
- return fixed_hzs_;
-}
-
-bool MatrixSearch::prepare_add_char(char ch) {
- if (pys_decoded_len_ >= kMaxRowNum - 1 ||
- (!spl_parser_->is_valid_to_parse(ch) && ch != '\''))
- return false;
-
- if (dmi_pool_used_ >= kDmiPoolSize) return false;
-
- pys_[pys_decoded_len_] = ch;
- pys_decoded_len_++;
-
- MatrixRow *mtrx_this_row = matrix_ + pys_decoded_len_;
- mtrx_this_row->mtrx_nd_pos = mtrx_nd_pool_used_;
- mtrx_this_row->mtrx_nd_num = 0;
- mtrx_this_row->dmi_pos = dmi_pool_used_;
- mtrx_this_row->dmi_num = 0;
- mtrx_this_row->dmi_has_full_id = 0;
-
- return true;
-}
-
-bool MatrixSearch::is_split_at(uint16 pos) {
- return !spl_parser_->is_valid_to_parse(pys_[pos - 1]);
-}
-
-void MatrixSearch::fill_dmi(DictMatchInfo *dmi, MileStoneHandle *handles,
- PoolPosType dmi_fr, uint16 spl_id,
- uint16 node_num, unsigned char dict_level,
- bool splid_end_split, unsigned char splstr_len,
- unsigned char all_full_id) {
- dmi->dict_handles[0] = handles[0];
- dmi->dict_handles[1] = handles[1];
- dmi->dmi_fr = dmi_fr;
- dmi->spl_id = spl_id;
- dmi->dict_level = dict_level;
- dmi->splid_end_split = splid_end_split ? 1 : 0;
- dmi->splstr_len = splstr_len;
- dmi->all_full_id = all_full_id;
- dmi->c_phrase = 0;
-}
-
-bool MatrixSearch::add_char(char ch) {
- if (!prepare_add_char(ch))
- return false;
- return add_char_qwerty();
-}
-
-bool MatrixSearch::add_char_qwerty() {
- matrix_[pys_decoded_len_].mtrx_nd_num = 0;
-
- bool spl_matched = false;
- uint16 longest_ext = 0;
- // Extend the search matrix, from the oldest unfixed row. ext_len means
- // extending length.
- for (uint16 ext_len = kMaxPinyinSize + 1; ext_len > 0; ext_len--) {
- if (ext_len > pys_decoded_len_ - spl_start_[fixed_hzs_])
- continue;
-
- // Refer to the declaration of the variable dmi_has_full_id for the
- // explanation of this piece of code. In one word, it is used to prevent
- // from the unwise extending of "shoud ou" but allow the reasonable
- // extending of "heng ao", "lang a", etc.
- if (ext_len > 1 && 0 != longest_ext &&
- 0 == matrix_[pys_decoded_len_ - ext_len].dmi_has_full_id) {
- if (xi_an_enabled_)
- continue;
- else
- break;
+ void MatrixSearch::del_in_pys ( size_t start, size_t len ) {
+ while ( start < kMaxRowNum - len && '\0' != pys_[start] ) {
+ pys_[start] = pys_[start + len];
+ start++;
+ }
}
- uint16 oldrow = pys_decoded_len_ - ext_len;
-
- // 0. If that row is before the last fixed step, ignore.
- if (spl_start_[fixed_hzs_] > oldrow)
- continue;
-
- // 1. Check if that old row has valid MatrixNode. If no, means that row is
- // not a boundary, either a word boundary or a spelling boundary.
- // If it is for extending composing phrase, it's OK to ignore the 0.
- if (0 == matrix_[oldrow].mtrx_nd_num && !dmi_c_phrase_)
- continue;
-
- // 2. Get spelling id(s) for the last ext_len chars.
- uint16 spl_idx;
- bool is_pre = false;
- spl_idx = spl_parser_->get_splid_by_str(pys_ + oldrow,
- ext_len, &is_pre);
- if (is_pre)
- spl_matched = true;
-
- if (0 == spl_idx)
- continue;
-
- bool splid_end_split = is_split_at(oldrow + ext_len);
-
- // 3. Extend the DMI nodes of that old row
- // + 1 is to extend an extra node from the root
- for (PoolPosType dmi_pos = matrix_[oldrow].dmi_pos;
- dmi_pos < matrix_[oldrow].dmi_pos + matrix_[oldrow].dmi_num + 1;
- dmi_pos++) {
- DictMatchInfo *dmi = dmi_pool_ + dmi_pos;
- if (dmi_pos == matrix_[oldrow].dmi_pos + matrix_[oldrow].dmi_num) {
- dmi = NULL; // The last one, NULL means extending from the root.
- } else {
- // If the dmi is covered by the fixed arrange, ignore it.
- if (fixed_hzs_ > 0 &&
- pys_decoded_len_ - ext_len - dmi->splstr_len <
- spl_start_[fixed_hzs_]) {
- continue;
- }
- // If it is not in mode for composing phrase, and the source DMI node
- // is marked for composing phrase, ignore this node.
- if (dmi->c_phrase != 0 && !dmi_c_phrase_) {
- continue;
- }
- }
-
- // For example, if "gao" is extended, "g ao" is not allowed.
- // or "zh" has been passed, "z h" is not allowed.
- // Both word and word-connection will be prevented.
- if (longest_ext > ext_len) {
- if (NULL == dmi && 0 == matrix_[oldrow].dmi_has_full_id) {
- continue;
+ size_t MatrixSearch::search ( const char *py, size_t py_len ) {
+ if ( !inited_ || NULL == py )
+ { return 0; }
+ // If the search Pinyin string is too long, it will be truncated.
+ if ( py_len > kMaxRowNum - 1 )
+ { py_len = kMaxRowNum - 1; }
+ // Compare the new string with the previous one. Find their prefix to
+ // increase search efficiency.
+ size_t ch_pos = 0;
+ for ( ch_pos = 0; ch_pos < pys_decoded_len_; ch_pos++ ) {
+ if ( '\0' == py[ch_pos] || py[ch_pos] != pys_[ch_pos] )
+ { break; }
}
-
- // "z h" is not allowed.
- if (NULL != dmi && spl_trie_->is_half_id(dmi->spl_id)) {
- continue;
+ bool clear_fix = true;
+ if ( ch_pos == pys_decoded_len_ )
+ { clear_fix = false; }
+ reset_search ( ch_pos, clear_fix, false, false );
+ memcpy ( pys_ + ch_pos, py + ch_pos, py_len - ch_pos );
+ pys_[py_len] = '\0';
+ while ( '\0' != pys_[ch_pos] ) {
+ if ( !add_char ( py[ch_pos] ) ) {
+ pys_decoded_len_ = ch_pos;
+ break;
+ }
+ ch_pos++;
}
- }
-
- dep_->splids_extended = 0;
- if (NULL != dmi) {
- uint16 prev_ids_num = dmi->dict_level;
- if ((!dmi_c_phrase_ && prev_ids_num >= kMaxLemmaSize) ||
- (dmi_c_phrase_ && prev_ids_num >= kMaxRowNum)) {
- continue;
+ // Get spelling ids and starting positions.
+ get_spl_start_id();
+ // If there are too many spellings, remove the last letter until the spelling
+ // number is acceptable.
+ while ( spl_id_num_ > 9 ) {
+ py_len--;
+ reset_search ( py_len, false, false, false );
+ pys_[py_len] = '\0';
+ get_spl_start_id();
}
-
- DictMatchInfo *d = dmi;
- while (d) {
- dep_->splids[--prev_ids_num] = d->spl_id;
- if ((PoolPosType)-1 == d->dmi_fr)
- break;
- d = dmi_pool_ + d->dmi_fr;
- }
- assert(0 == prev_ids_num);
- dep_->splids_extended = dmi->dict_level;
- }
- dep_->splids[dep_->splids_extended] = spl_idx;
- dep_->ext_len = ext_len;
- dep_->splid_end_split = splid_end_split;
-
- dep_->id_num = 1;
- dep_->id_start = spl_idx;
- if (spl_trie_->is_half_id(spl_idx)) {
- // Get the full id list
- dep_->id_num = spl_trie_->half_to_full(spl_idx, &(dep_->id_start));
- assert(dep_->id_num > 0);
- }
-
- uint16 new_dmi_num;
-
- new_dmi_num = extend_dmi(dep_, dmi);
-
- if (new_dmi_num > 0) {
- if (dmi_c_phrase_) {
- dmi_pool_[dmi_pool_used_].c_phrase = 1;
+ prepare_candidates();
+ if ( kPrintDebug0 ) {
+ printf ( "--Matrix Node Pool Used: %d\n", mtrx_nd_pool_used_ );
+ printf ( "--DMI Pool Used: %d\n", dmi_pool_used_ );
+ if ( kPrintDebug1 ) {
+ for ( PoolPosType pos = 0; pos < dmi_pool_used_; pos++ ) {
+ debug_print_dmi ( pos, 1 );
+ }
+ }
}
- matrix_[pys_decoded_len_].dmi_num += new_dmi_num;
- dmi_pool_used_ += new_dmi_num;
-
- if (!spl_trie_->is_half_id(spl_idx))
- matrix_[pys_decoded_len_].dmi_has_full_id = 1;
- }
+ return ch_pos;
+ }
- // If get candiate lemmas, try to extend the path
- if (lpi_total_ > 0) {
- uint16 fr_row;
- if (NULL == dmi) {
- fr_row = oldrow;
+ size_t MatrixSearch::delsearch ( size_t pos, bool is_pos_in_splid,
+ bool clear_fixed_this_step ) {
+ if ( !inited_ )
+ { return 0; }
+ size_t reset_pos = pos;
+ // Out of range for both Pinyin mode and Spelling id mode.
+ if ( pys_decoded_len_ <= pos ) {
+ del_in_pys ( pos, 1 );
+ reset_pos = pys_decoded_len_;
+ // Decode the string after the un-decoded position
+ while ( '\0' != pys_[reset_pos] ) {
+ if ( !add_char ( pys_[reset_pos] ) ) {
+ pys_decoded_len_ = reset_pos;
+ break;
+ }
+ reset_pos++;
+ }
+ get_spl_start_id();
+ prepare_candidates();
+ return pys_decoded_len_;
+ }
+ // Spelling id mode, but out of range.
+ if ( is_pos_in_splid && spl_id_num_ <= pos )
+ { return pys_decoded_len_; }
+ // Begin to handle two modes respectively.
+ // Pinyin mode by default
+ size_t c_py_len = 0; // The length of composing phrase's Pinyin
+ size_t del_py_len = 1;
+ if ( !is_pos_in_splid ) {
+ // Pinyin mode is only allowed to delete beyond the fixed lemmas.
+ if ( fixed_lmas_ > 0 && pos < spl_start_[lma_start_[fixed_lmas_]] )
+ { return pys_decoded_len_; }
+ del_in_pys ( pos, 1 );
+ // If the deleted character is just the one after the last fixed lemma
+ if ( pos == spl_start_[lma_start_[fixed_lmas_]] ) {
+ // If all fixed lemmas have been merged, and the caller of the function
+ // request to unlock the last fixed lemma.
+ if ( kLemmaIdComposing == lma_id_[0] && clear_fixed_this_step ) {
+ // Unlock the last sub lemma in the composing phrase. Because it is not
+ // easy to unlock it directly. Instead, we re-decode the modified
+ // composing phrase.
+ c_phrase_.sublma_num--;
+ c_phrase_.length = c_phrase_.sublma_start[c_phrase_.sublma_num];
+ reset_pos = spl_start_[c_phrase_.length];
+ c_py_len = reset_pos;
+ }
+ }
} else {
- assert(oldrow >= dmi->splstr_len);
- fr_row = oldrow - dmi->splstr_len;
- }
- for (PoolPosType mtrx_nd_pos = matrix_[fr_row].mtrx_nd_pos;
- mtrx_nd_pos < matrix_[fr_row].mtrx_nd_pos +
- matrix_[fr_row].mtrx_nd_num;
- mtrx_nd_pos++) {
- MatrixNode *mtrx_nd = mtrx_nd_pool_ + mtrx_nd_pos;
-
- extend_mtrx_nd(mtrx_nd, lpi_items_, lpi_total_,
- dmi_pool_used_ - new_dmi_num, pys_decoded_len_);
- if (longest_ext == 0)
- longest_ext = ext_len;
- }
- }
- } // for dmi_pos
- } // for ext_len
- mtrx_nd_pool_used_ += matrix_[pys_decoded_len_].mtrx_nd_num;
-
- if (dmi_c_phrase_)
- return true;
-
- return (matrix_[pys_decoded_len_].mtrx_nd_num != 0 || spl_matched);
-}
-
-void MatrixSearch::prepare_candidates() {
- // Get candiates from the first un-fixed step.
- uint16 lma_size_max = kMaxLemmaSize;
- if (lma_size_max > spl_id_num_ - fixed_hzs_)
- lma_size_max = spl_id_num_ - fixed_hzs_;
-
- uint16 lma_size = lma_size_max;
-
- // If the full sentense candidate's unfixed part may be the same with a normal
- // lemma. Remove the lemma candidate in this case.
- char16 fullsent[kMaxLemmaSize + 1];
- char16 *pfullsent = NULL;
- uint16 sent_len;
- pfullsent = get_candidate0(fullsent, kMaxLemmaSize + 1, &sent_len, true);
-
- // If the unfixed part contains more than one ids, it is not necessary to
- // check whether a lemma's string is the same to the unfixed part of the full
- // sentence candidate, so, set it to NULL;
- if (sent_len > kMaxLemmaSize)
- pfullsent = NULL;
-
- lpi_total_ = 0;
- size_t lpi_num_full_match = 0; // Number of items which are fully-matched.
- while (lma_size > 0) {
- size_t lma_num;
- lma_num = get_lpis(spl_id_ + fixed_hzs_, lma_size,
- lpi_items_ + lpi_total_,
- size_t(kMaxLmaPsbItems - lpi_total_),
- pfullsent, lma_size == lma_size_max);
-
- if (lma_num > 0) {
- lpi_total_ += lma_num;
- // For next lemma candidates which are not the longest, it is not
- // necessary to compare with the full sentence candiate.
- pfullsent = NULL;
- }
- if (lma_size == lma_size_max) {
- lpi_num_full_match = lpi_total_;
+ del_py_len = spl_start_[pos + 1] - spl_start_[pos];
+ del_in_pys ( spl_start_[pos], del_py_len );
+ if ( pos >= lma_start_[fixed_lmas_] ) {
+ c_py_len = 0;
+ reset_pos = spl_start_[pos + 1] - del_py_len;
+ } else {
+ c_py_len = spl_start_[lma_start_[fixed_lmas_]] - del_py_len;
+ reset_pos = c_py_len;
+ if ( c_py_len > 0 )
+ { merge_fixed_lmas ( pos ); }
+ }
+ }
+ if ( c_py_len > 0 ) {
+ assert ( c_phrase_.length > 0 && c_py_len ==
+ c_phrase_.spl_start[c_phrase_.sublma_start[c_phrase_.sublma_num]] );
+ // The composing phrase is valid, reset all search space,
+ // and begin a new search which will only extend the composing
+ // phrase.
+ reset_search0();
+ dmi_c_phrase_ = true;
+ // Extend the composing phrase.
+ uint16 c_py_pos = 0;
+ while ( c_py_pos < c_py_len ) {
+ bool b_ac_tmp = add_char ( pys_[c_py_pos] );
+ assert ( b_ac_tmp );
+ c_py_pos++;
+ }
+ dmi_c_phrase_ = false;
+ // Fixd the composing phrase as the first choice.
+ lma_id_num_ = 1;
+ fixed_lmas_ = 1;
+ fixed_lmas_no1_[0] = 0; // A composing string is always modified.
+ fixed_hzs_ = c_phrase_.length;
+ lma_start_[1] = fixed_hzs_;
+ lma_id_[0] = kLemmaIdComposing;
+ matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ +
+ matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos;
+ } else {
+ // Reseting search only clear pys_decoded_len_, but the string is kept.
+ reset_search ( reset_pos, clear_fixed_this_step, false, false );
+ }
+ // Decode the string after the delete position.
+ while ( '\0' != pys_[reset_pos] ) {
+ if ( !add_char ( pys_[reset_pos] ) ) {
+ pys_decoded_len_ = reset_pos;
+ break;
+ }
+ reset_pos++;
+ }
+ get_spl_start_id();
+ prepare_candidates();
+ return pys_decoded_len_;
}
- lma_size--;
- }
-
- // Sort those partially-matched items by their unified scores.
- myqsort(lpi_items_ + lpi_num_full_match, lpi_total_ - lpi_num_full_match,
- sizeof(LmaPsbItem), cmp_lpi_with_unified_psb);
- if (kPrintDebug0) {
- printf("-----Prepare candidates, score:\n");
- for (size_t a = 0; a < lpi_total_; a++) {
- printf("[%03d]%d ", a, lpi_items_[a].psb);
- if ((a + 1) % 6 == 0) printf("\n");
+ size_t MatrixSearch::get_candidate_num() {
+ if ( !inited_ || 0 == pys_decoded_len_ ||
+ 0 == matrix_[pys_decoded_len_].mtrx_nd_num )
+ { return 0; }
+ return 1 + lpi_total_;
}
- printf("\n");
- }
-
- if (kPrintDebug0) {
- printf("--- lpi_total_ = %d\n", lpi_total_);
- }
-}
-const char* MatrixSearch::get_pystr(size_t *decoded_len) {
- if (!inited_ || NULL == decoded_len)
- return NULL;
-
- *decoded_len = pys_decoded_len_;
- return pys_;
-}
-
-void MatrixSearch::merge_fixed_lmas(size_t del_spl_pos) {
- if (fixed_lmas_ == 0)
- return;
- // Update spelling segmentation information first.
- spl_id_num_ -= 1;
- uint16 del_py_len = spl_start_[del_spl_pos + 1] - spl_start_[del_spl_pos];
- for (size_t pos = del_spl_pos; pos <= spl_id_num_; pos++) {
- spl_start_[pos] = spl_start_[pos + 1] - del_py_len;
- if (pos == spl_id_num_)
- break;
- spl_id_[pos] = spl_id_[pos + 1];
- }
-
- // Begin to merge.
- uint16 phrase_len = 0;
-
- // Update the spelling ids to the composing phrase.
- // We need to convert these ids into full id in the future.
- memcpy(c_phrase_.spl_ids, spl_id_, spl_id_num_ * sizeof(uint16));
- memcpy(c_phrase_.spl_start, spl_start_, (spl_id_num_ + 1) * sizeof(uint16));
-
- // If composing phrase has not been created, first merge all fixed
- // lemmas into a composing phrase without deletion.
- if (fixed_lmas_ > 1 || kLemmaIdComposing != lma_id_[0]) {
- uint16 bp = 1; // Begin position of real fixed lemmas.
- // There is no existing composing phrase.
- if (kLemmaIdComposing != lma_id_[0]) {
- c_phrase_.sublma_num = 0;
- bp = 0;
+ char16 *MatrixSearch::get_candidate ( size_t cand_id, char16 *cand_str,
+ size_t max_len ) {
+ if ( !inited_ || 0 == pys_decoded_len_ || NULL == cand_str )
+ { return NULL; }
+ if ( 0 == cand_id ) {
+ return get_candidate0 ( cand_str, max_len, NULL, false );
+ } else {
+ cand_id--;
+ }
+ // For this case: the current sentence is a word only, and the user fixed it,
+ // so the result will be fixed to the sentence space, and
+ // lpi_total_ will be set to 0.
+ if ( 0 == lpi_total_ ) {
+ return get_candidate0 ( cand_str, max_len, NULL, false );
+ }
+ LemmaIdType id = lpi_items_[cand_id].id;
+ char16 s[kMaxLemmaSize + 1];
+ uint16 s_len = lpi_items_[cand_id].lma_len;
+ if ( s_len > 1 ) {
+ s_len = get_lemma_str ( id, s, kMaxLemmaSize + 1 );
+ } else {
+ // For a single character, Hanzi is ready.
+ s[0] = lpi_items_[cand_id].hanzi;
+ s[1] = static_cast<char16> ( 0 );
+ }
+ if ( s_len > 0 && max_len > s_len ) {
+ utf16_strncpy ( cand_str, s, s_len );
+ cand_str[s_len] = ( char16 ) '\0';
+ return cand_str;
+ }
+ return NULL;
}
- uint16 sub_num = c_phrase_.sublma_num;
- for (uint16 pos = bp; pos <= fixed_lmas_; pos++) {
- c_phrase_.sublma_start[sub_num + pos - bp] = lma_start_[pos];
- if (lma_start_[pos] > del_spl_pos) {
- c_phrase_.sublma_start[sub_num + pos - bp] -= 1;
- }
-
- if (pos == fixed_lmas_)
- break;
-
- uint16 lma_len;
- char16 *lma_str = c_phrase_.chn_str +
- c_phrase_.sublma_start[sub_num] + phrase_len;
-
- lma_len = get_lemma_str(lma_id_[pos], lma_str, kMaxRowNum - phrase_len);
- assert(lma_len == lma_start_[pos + 1] - lma_start_[pos]);
- phrase_len += lma_len;
- }
- assert(phrase_len == lma_start_[fixed_lmas_]);
- c_phrase_.length = phrase_len; // will be deleted by 1
- c_phrase_.sublma_num += fixed_lmas_ - bp;
- } else {
- for (uint16 pos = 0; pos <= c_phrase_.sublma_num; pos++) {
- if (c_phrase_.sublma_start[pos] > del_spl_pos) {
- c_phrase_.sublma_start[pos] -= 1;
- }
+ void MatrixSearch::update_dict_freq() {
+ if ( NULL != user_dict_ ) {
+ // Update the total frequency of all lemmas, including system lemmas and
+ // user dictionary lemmas.
+ size_t total_freq = user_dict_->get_total_lemma_count();
+ dict_trie_->set_total_lemma_count_of_others ( total_freq );
+ }
}
- phrase_len = c_phrase_.length;
- }
-
- assert(phrase_len > 0);
- if (1 == phrase_len) {
- // After the only one is deleted, nothing will be left.
- fixed_lmas_ = 0;
- return;
- }
- // Delete the Chinese character in the merged phrase.
- // The corresponding elements in spl_ids and spl_start of the
- // phrase have been deleted.
- char16 *chn_str = c_phrase_.chn_str + del_spl_pos;
- for (uint16 pos = 0;
- pos < c_phrase_.sublma_start[c_phrase_.sublma_num] - del_spl_pos;
- pos++) {
- chn_str[pos] = chn_str[pos + 1];
- }
- c_phrase_.length -= 1;
-
- // If the deleted spelling id is in a sub lemma which contains more than
- // one id, del_a_sub will be false; but if the deleted id is in a sub lemma
- // which only contains 1 id, the whole sub lemma needs to be deleted, so
- // del_a_sub will be true.
- bool del_a_sub = false;
- for (uint16 pos = 1; pos <= c_phrase_.sublma_num; pos++) {
- if (c_phrase_.sublma_start[pos - 1] ==
- c_phrase_.sublma_start[pos]) {
- del_a_sub = true;
- }
- if (del_a_sub) {
- c_phrase_.sublma_start[pos - 1] =
- c_phrase_.sublma_start[pos];
+ bool MatrixSearch::add_lma_to_userdict ( uint16 lma_fr, uint16 lma_to,
+ float score ) {
+ if ( lma_to - lma_fr <= 1 || NULL == user_dict_ )
+ { return false; }
+ char16 word_str[kMaxLemmaSize + 1];
+ uint16 spl_ids[kMaxLemmaSize];
+ uint16 spl_id_fr = 0;
+ for ( uint16 pos = lma_fr; pos < lma_to; pos++ ) {
+ LemmaIdType lma_id = lma_id_[pos];
+ if ( is_user_lemma ( lma_id ) ) {
+ user_dict_->update_lemma ( lma_id, 1, true );
+ }
+ uint16 lma_len = lma_start_[pos + 1] - lma_start_[pos];
+ utf16_strncpy ( spl_ids + spl_id_fr, spl_id_ + lma_start_[pos], lma_len );
+ uint16 tmp = get_lemma_str ( lma_id, word_str + spl_id_fr,
+ kMaxLemmaSize + 1 - spl_id_fr );
+ assert ( tmp == lma_len );
+ tmp = get_lemma_splids ( lma_id, spl_ids + spl_id_fr, lma_len, true );
+ if ( tmp != lma_len ) {
+ return false;
+ }
+ spl_id_fr += lma_len;
+ }
+ assert ( spl_id_fr <= kMaxLemmaSize );
+ return user_dict_->put_lemma ( static_cast<char16 *> ( word_str ), spl_ids,
+ spl_id_fr, 1 );
}
- }
- if (del_a_sub)
- c_phrase_.sublma_num -= 1;
-
- return;
-}
-
-void MatrixSearch::get_spl_start_id() {
- lma_id_num_ = 0;
- lma_start_[0] = 0;
-
- spl_id_num_ = 0;
- spl_start_[0] = 0;
- if (!inited_ || 0 == pys_decoded_len_ ||
- 0 == matrix_[pys_decoded_len_].mtrx_nd_num)
- return;
-
- // Calculate number of lemmas and spellings
- // Only scan those part which is not fixed.
- lma_id_num_ = fixed_lmas_;
- spl_id_num_ = fixed_hzs_;
- MatrixNode *mtrx_nd = mtrx_nd_pool_ + matrix_[pys_decoded_len_].mtrx_nd_pos;
- while (mtrx_nd != mtrx_nd_pool_) {
- if (fixed_hzs_ > 0) {
- if (mtrx_nd->step <= spl_start_[fixed_hzs_])
- break;
+ void MatrixSearch::debug_print_dmi ( PoolPosType dmi_pos, uint16 nest_level ) {
+ if ( dmi_pos >= dmi_pool_used_ ) { return; }
+ DictMatchInfo *dmi = dmi_pool_ + dmi_pos;
+ if ( 1 == nest_level ) {
+ printf ( "-----------------%d\'th DMI node begin----------->\n", dmi_pos );
+ }
+ if ( dmi->dict_level > 1 ) {
+ debug_print_dmi ( dmi->dmi_fr, nest_level + 1 );
+ }
+ printf ( "---%d\n", dmi->dict_level );
+ printf ( " MileStone: %x, %x\n", dmi->dict_handles[0], dmi->dict_handles[1] );
+ printf ( " Spelling : %s, %d\n", SpellingTrie::get_instance().
+ get_spelling_str ( dmi->spl_id ), dmi->spl_id );
+ printf ( " Total Pinyin Len: %d\n", dmi->splstr_len );
+ if ( 1 == nest_level ) {
+ printf ( "<----------------%d\'th DMI node end--------------\n\n", dmi_pos );
+ }
}
- // Update the spelling segamentation information
- unsigned char word_splstr_len = 0;
- PoolPosType dmi_fr = mtrx_nd->dmi_fr;
- if ((PoolPosType)-1 != dmi_fr)
- word_splstr_len = dmi_pool_[dmi_fr].splstr_len;
-
- while ((PoolPosType)-1 != dmi_fr) {
- spl_start_[spl_id_num_ + 1] = mtrx_nd->step -
- (word_splstr_len - dmi_pool_[dmi_fr].splstr_len);
- spl_id_[spl_id_num_] = dmi_pool_[dmi_fr].spl_id;
- spl_id_num_++;
- dmi_fr = dmi_pool_[dmi_fr].dmi_fr;
+ bool MatrixSearch::try_add_cand0_to_userdict() {
+ size_t new_cand_num = get_candidate_num();
+ if ( fixed_hzs_ > 0 && 1 == new_cand_num ) {
+ float score_from = 0;
+ uint16 lma_id_from = 0;
+ uint16 pos = 0;
+ bool modified = false;
+ while ( pos < fixed_lmas_ ) {
+ if ( lma_start_[pos + 1] - lma_start_[lma_id_from] >
+ static_cast<uint16> ( kMaxLemmaSize ) ) {
+ float score_to_add =
+ mtrx_nd_pool_[matrix_[spl_start_[lma_start_[pos]]]
+ .mtrx_nd_pos].score - score_from;
+ if ( modified ) {
+ score_to_add += 1.0;
+ if ( score_to_add > NGram::kMaxScore ) {
+ score_to_add = NGram::kMaxScore;
+ }
+ add_lma_to_userdict ( lma_id_from, pos, score_to_add );
+ }
+ lma_id_from = pos;
+ score_from += score_to_add;
+ // Clear the flag for next user lemma.
+ modified = false;
+ }
+ if ( 0 == fixed_lmas_no1_[pos] ) {
+ modified = true;
+ }
+ pos++;
+ }
+ // Single-char word is not allowed to add to userdict.
+ if ( lma_start_[pos] - lma_start_[lma_id_from] > 1 ) {
+ float score_to_add =
+ mtrx_nd_pool_[matrix_[spl_start_[lma_start_[pos]]]
+ .mtrx_nd_pos].score - score_from;
+ if ( modified ) {
+ score_to_add += 1.0;
+ if ( score_to_add > NGram::kMaxScore ) {
+ score_to_add = NGram::kMaxScore;
+ }
+ add_lma_to_userdict ( lma_id_from, pos, score_to_add );
+ }
+ }
+ }
+ return true;
}
- // Update the lemma segmentation information
- lma_start_[lma_id_num_ + 1] = spl_id_num_;
- lma_id_[lma_id_num_] = mtrx_nd->id;
- lma_id_num_++;
-
- mtrx_nd = mtrx_nd->from;
- }
-
- // Reverse the result of spelling info
- for (size_t pos = fixed_hzs_;
- pos < fixed_hzs_ + (spl_id_num_ - fixed_hzs_ + 1) / 2; pos++) {
- if (spl_id_num_ + fixed_hzs_ - pos != pos + 1) {
- spl_start_[pos + 1] ^= spl_start_[spl_id_num_ - pos + fixed_hzs_];
- spl_start_[spl_id_num_ - pos + fixed_hzs_] ^= spl_start_[pos + 1];
- spl_start_[pos + 1] ^= spl_start_[spl_id_num_ - pos + fixed_hzs_];
-
- spl_id_[pos] ^= spl_id_[spl_id_num_ + fixed_hzs_ - pos - 1];
- spl_id_[spl_id_num_ + fixed_hzs_- pos - 1] ^= spl_id_[pos];
- spl_id_[pos] ^= spl_id_[spl_id_num_ + fixed_hzs_- pos - 1];
+ // Choose a candidate, and give new candidates for next step.
+ // If user finishes selection, we will try to communicate with user dictionary
+ // to add new items or update score of some existing items.
+ //
+ // Basic rule:
+ // 1. If user selects the first choice:
+ // 1.1. If the first choice is not a sentence, instead, it is a lemma:
+ // 1.1.1. If the first choice is a user lemma, notify the user
+ // dictionary that a user lemma is hit, and add occuring count
+ // by 1.
+ // 1.1.2. If the first choice is a system lemma, do nothing.
+ // 1.2. If the first choice is a sentence containing more than one lemma:
+ // 1.2.1. The whole sentence will be added as a user lemma. If the
+ // sentence contains user lemmas, -> hit, and add occuring count
+ // by 1.
+ size_t MatrixSearch::choose ( size_t cand_id ) {
+ if ( !inited_ || 0 == pys_decoded_len_ )
+ { return 0; }
+ if ( 0 == cand_id ) {
+ fixed_hzs_ = spl_id_num_;
+ matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ +
+ matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos;
+ for ( size_t pos = fixed_lmas_; pos < lma_id_num_; pos++ ) {
+ fixed_lmas_no1_[pos] = 1;
+ }
+ fixed_lmas_ = lma_id_num_;
+ lpi_total_ = 0; // Clean all other candidates.
+ // 1. It is the first choice
+ if ( 1 == lma_id_num_ ) {
+ // 1.1. The first choice is not a sentence but a lemma
+ if ( is_user_lemma ( lma_id_[0] ) ) {
+ // 1.1.1. The first choice is a user lemma, notify the user dictionary
+ // that it is hit.
+ if ( NULL != user_dict_ )
+ { user_dict_->update_lemma ( lma_id_[0], 1, true ); }
+ } else {
+ // 1.1.2. do thing for a system lemma.
+ }
+ } else {
+ // 1.2. The first choice is a sentence.
+ // 1.2.1 Try to add the whole sentence to user dictionary, the whole
+ // sentence may be splitted into many items.
+ if ( NULL != user_dict_ ) {
+ try_add_cand0_to_userdict();
+ }
+ }
+ update_dict_freq();
+ return 1;
+ } else {
+ cand_id--;
+ }
+ // 2. It is not the full sentence candidate.
+ // Find the length of the candidate.
+ LemmaIdType id_chosen = lpi_items_[cand_id].id;
+ LmaScoreType score_chosen = lpi_items_[cand_id].psb;
+ size_t cand_len = lpi_items_[cand_id].lma_len;
+ assert ( cand_len > 0 );
+ // Notify the atom dictionary that this item is hit.
+ if ( is_user_lemma ( id_chosen ) ) {
+ if ( NULL != user_dict_ ) {
+ user_dict_->update_lemma ( id_chosen, 1, true );
+ }
+ update_dict_freq();
+ }
+ // 3. Fixed the chosen item.
+ // 3.1 Get the steps number.
+ size_t step_fr = spl_start_[fixed_hzs_];
+ size_t step_to = spl_start_[fixed_hzs_ + cand_len];
+ // 3.2 Save the length of the original string.
+ size_t pys_decoded_len = pys_decoded_len_;
+ // 3.2 Reset the space of the fixed part.
+ reset_search ( step_to, false, false, true );
+ // 3.3 For the last character of the fixed part, the previous DMI
+ // information will be kept, while the MTRX information will be re-extended,
+ // and only one node will be extended.
+ matrix_[step_to].mtrx_nd_num = 0;
+ LmaPsbItem lpi_item;
+ lpi_item.psb = score_chosen;
+ lpi_item.id = id_chosen;
+ PoolPosType step_to_dmi_fr = match_dmi ( step_to,
+ spl_id_ + fixed_hzs_, cand_len );
+ assert ( step_to_dmi_fr != static_cast<PoolPosType> ( -1 ) );
+ extend_mtrx_nd ( matrix_[step_fr].mtrx_nd_fixed, &lpi_item, 1,
+ step_to_dmi_fr, step_to );
+ matrix_[step_to].mtrx_nd_fixed = mtrx_nd_pool_ + matrix_[step_to].mtrx_nd_pos;
+ mtrx_nd_pool_used_ = matrix_[step_to].mtrx_nd_pos +
+ matrix_[step_to].mtrx_nd_num;
+ if ( id_chosen == lma_id_[fixed_lmas_] )
+ { fixed_lmas_no1_[fixed_lmas_] = 1; }
+ else
+ { fixed_lmas_no1_[fixed_lmas_] = 0; }
+ lma_id_[fixed_lmas_] = id_chosen;
+ lma_start_[fixed_lmas_ + 1] = lma_start_[fixed_lmas_] + cand_len;
+ fixed_lmas_++;
+ fixed_hzs_ = fixed_hzs_ + cand_len;
+ while ( step_to != pys_decoded_len ) {
+ bool b = add_char ( pys_[step_to] );
+ assert ( b );
+ step_to++;
+ }
+ if ( fixed_hzs_ < spl_id_num_ ) {
+ prepare_candidates();
+ } else {
+ lpi_total_ = 0;
+ if ( NULL != user_dict_ ) {
+ try_add_cand0_to_userdict();
+ }
+ }
+ return get_candidate_num();
}
- }
- // Reverse the result of lemma info
- for (size_t pos = fixed_lmas_;
- pos < fixed_lmas_ + (lma_id_num_ - fixed_lmas_ + 1) / 2; pos++) {
- assert(lma_id_num_ + fixed_lmas_ - pos - 1 >= pos);
-
- if (lma_id_num_ + fixed_lmas_ - pos > pos + 1) {
- lma_start_[pos + 1] ^= lma_start_[lma_id_num_ - pos + fixed_lmas_];
- lma_start_[lma_id_num_ - pos + fixed_lmas_] ^= lma_start_[pos + 1];
- lma_start_[pos + 1] ^= lma_start_[lma_id_num_ - pos + fixed_lmas_];
-
- lma_id_[pos] ^= lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_];
- lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_] ^= lma_id_[pos];
- lma_id_[pos] ^= lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_];
+ size_t MatrixSearch::cancel_last_choice() {
+ if ( !inited_ || 0 == pys_decoded_len_ )
+ { return 0; }
+ size_t step_start = 0;
+ if ( fixed_hzs_ > 0 ) {
+ size_t step_end = spl_start_[fixed_hzs_];
+ MatrixNode *end_node = matrix_[step_end].mtrx_nd_fixed;
+ assert ( NULL != end_node );
+ step_start = end_node->from->step;
+ if ( step_start > 0 ) {
+ DictMatchInfo *dmi = dmi_pool_ + end_node->dmi_fr;
+ fixed_hzs_ -= dmi->dict_level;
+ } else {
+ fixed_hzs_ = 0;
+ }
+ reset_search ( step_start, false, false, false );
+ while ( pys_[step_start] != '\0' ) {
+ bool b = add_char ( pys_[step_start] );
+ assert ( b );
+ step_start++;
+ }
+ prepare_candidates();
+ }
+ return get_candidate_num();
}
- }
-
- for (size_t pos = fixed_lmas_ + 1; pos <= lma_id_num_; pos++) {
- if (pos < lma_id_num_)
- lma_start_[pos] = lma_start_[pos - 1] +
- (lma_start_[pos] - lma_start_[pos + 1]);
- else
- lma_start_[pos] = lma_start_[pos - 1] + lma_start_[pos] -
- lma_start_[fixed_lmas_];
- }
- // Find the last fixed position
- fixed_hzs_ = 0;
- for (size_t pos = spl_id_num_; pos > 0; pos--) {
- if (NULL != matrix_[spl_start_[pos]].mtrx_nd_fixed) {
- fixed_hzs_ = pos;
- break;
+ size_t MatrixSearch::get_fixedlen() {
+ if ( !inited_ || 0 == pys_decoded_len_ )
+ { return 0; }
+ return fixed_hzs_;
}
- }
- return;
-}
-
-size_t MatrixSearch::get_spl_start(const uint16 *&spl_start) {
- get_spl_start_id();
- spl_start = spl_start_;
- return spl_id_num_;
-}
-
-size_t MatrixSearch::extend_dmi(DictExtPara *dep, DictMatchInfo *dmi_s) {
- if (dmi_pool_used_ >= kDmiPoolSize) return 0;
-
- if (dmi_c_phrase_)
- return extend_dmi_c(dep, dmi_s);
-
- LpiCache& lpi_cache = LpiCache::get_instance();
- uint16 splid = dep->splids[dep->splids_extended];
-
- bool cached = false;
- if (0 == dep->splids_extended)
- cached = lpi_cache.is_cached(splid);
-
- // 1. If this is a half Id, get its corresponding full starting Id and
- // number of full Id.
- size_t ret_val = 0;
- PoolPosType mtrx_dmi_fr = (PoolPosType)-1; // From which dmi node
-
- lpi_total_ = 0;
-
- MileStoneHandle from_h[3];
- from_h[0] = 0;
- from_h[1] = 0;
-
- if (0 != dep->splids_extended) {
- from_h[0] = dmi_s->dict_handles[0];
- from_h[1] = dmi_s->dict_handles[1];
- }
-
- // 2. Begin exgtending in the system dictionary
- size_t lpi_num = 0;
- MileStoneHandle handles[2];
- handles[0] = handles[1] = 0;
- if (from_h[0] > 0 || NULL == dmi_s) {
- handles[0] = dict_trie_->extend_dict(from_h[0], dep, lpi_items_,
- kMaxLmaPsbItems, &lpi_num);
- }
- if (handles[0] > 0)
- lpi_total_ = lpi_num;
-
- if (NULL == dmi_s) { // from root
- assert(0 != handles[0]);
- mtrx_dmi_fr = dmi_pool_used_;
- }
-
- // 3. Begin extending in the user dictionary
- if (NULL != user_dict_ && (from_h[1] > 0 || NULL == dmi_s)) {
- handles[1] = user_dict_->extend_dict(from_h[1], dep,
- lpi_items_ + lpi_total_,
- kMaxLmaPsbItems - lpi_total_,
- &lpi_num);
- if (handles[1] > 0) {
- if (kPrintDebug0) {
- for (size_t t = 0; t < lpi_num; t++) {
- printf("--Extend in user dict: uid:%d uscore:%d\n", lpi_items_[lpi_total_ + t].id,
- lpi_items_[lpi_total_ + t].psb);
- }
- }
- lpi_total_ += lpi_num;
+ bool MatrixSearch::prepare_add_char ( char ch ) {
+ if ( pys_decoded_len_ >= kMaxRowNum - 1 ||
+ ( !spl_parser_->is_valid_to_parse ( ch ) && ch != '\'' ) )
+ { return false; }
+ if ( dmi_pool_used_ >= kDmiPoolSize ) { return false; }
+ pys_[pys_decoded_len_] = ch;
+ pys_decoded_len_++;
+ MatrixRow *mtrx_this_row = matrix_ + pys_decoded_len_;
+ mtrx_this_row->mtrx_nd_pos = mtrx_nd_pool_used_;
+ mtrx_this_row->mtrx_nd_num = 0;
+ mtrx_this_row->dmi_pos = dmi_pool_used_;
+ mtrx_this_row->dmi_num = 0;
+ mtrx_this_row->dmi_has_full_id = 0;
+ return true;
}
- }
-
- if (0 != handles[0] || 0 != handles[1]) {
- if (dmi_pool_used_ >= kDmiPoolSize) return 0;
- DictMatchInfo *dmi_add = dmi_pool_ + dmi_pool_used_;
- if (NULL == dmi_s) {
- fill_dmi(dmi_add, handles,
- (PoolPosType)-1, splid,
- 1, 1, dep->splid_end_split, dep->ext_len,
- spl_trie_->is_half_id(splid) ? 0 : 1);
- } else {
- fill_dmi(dmi_add, handles,
- dmi_s - dmi_pool_, splid, 1,
- dmi_s->dict_level + 1, dep->splid_end_split,
- dmi_s->splstr_len + dep->ext_len,
- spl_trie_->is_half_id(splid) ? 0 : dmi_s->all_full_id);
+ bool MatrixSearch::is_split_at ( uint16 pos ) {
+ return !spl_parser_->is_valid_to_parse ( pys_[pos - 1] );
}
- ret_val = 1;
- }
-
- if (!cached) {
- if (0 == lpi_total_)
- return ret_val;
-
- if (kPrintDebug0) {
- printf("--- lpi_total_ = %d\n", lpi_total_);
+ void MatrixSearch::fill_dmi ( DictMatchInfo *dmi, MileStoneHandle *handles,
+ PoolPosType dmi_fr, uint16 spl_id,
+ uint16 node_num, unsigned char dict_level,
+ bool splid_end_split, unsigned char splstr_len,
+ unsigned char all_full_id ) {
+ dmi->dict_handles[0] = handles[0];
+ dmi->dict_handles[1] = handles[1];
+ dmi->dmi_fr = dmi_fr;
+ dmi->spl_id = spl_id;
+ dmi->dict_level = dict_level;
+ dmi->splid_end_split = splid_end_split ? 1 : 0;
+ dmi->splstr_len = splstr_len;
+ dmi->all_full_id = all_full_id;
+ dmi->c_phrase = 0;
}
- myqsort(lpi_items_, lpi_total_, sizeof(LmaPsbItem), cmp_lpi_with_psb);
- if (NULL == dmi_s && spl_trie_->is_half_id(splid))
- lpi_total_ = lpi_cache.put_cache(splid, lpi_items_, lpi_total_);
- } else {
- assert(spl_trie_->is_half_id(splid));
- lpi_total_ = lpi_cache.get_cache(splid, lpi_items_, kMaxLmaPsbItems);
- }
-
- return ret_val;
-}
-
-size_t MatrixSearch::extend_dmi_c(DictExtPara *dep, DictMatchInfo *dmi_s) {
- lpi_total_ = 0;
-
- uint16 pos = dep->splids_extended;
- assert(dmi_c_phrase_);
- if (pos >= c_phrase_.length)
- return 0;
-
- uint16 splid = dep->splids[pos];
- if (splid == c_phrase_.spl_ids[pos]) {
- DictMatchInfo *dmi_add = dmi_pool_ + dmi_pool_used_;
- MileStoneHandle handles[2]; // Actually never used.
- if (NULL == dmi_s)
- fill_dmi(dmi_add, handles,
- (PoolPosType)-1, splid,
- 1, 1, dep->splid_end_split, dep->ext_len,
- spl_trie_->is_half_id(splid) ? 0 : 1);
- else
- fill_dmi(dmi_add, handles,
- dmi_s - dmi_pool_, splid, 1,
- dmi_s->dict_level + 1, dep->splid_end_split,
- dmi_s->splstr_len + dep->ext_len,
- spl_trie_->is_half_id(splid) ? 0 : dmi_s->all_full_id);
-
- if (pos == c_phrase_.length - 1) {
- lpi_items_[0].id = kLemmaIdComposing;
- lpi_items_[0].psb = 0; // 0 is bigger than normal lemma score.
- lpi_total_ = 1;
+ bool MatrixSearch::add_char ( char ch ) {
+ if ( !prepare_add_char ( ch ) )
+ { return false; }
+ return add_char_qwerty();
}
- return 1;
- }
- return 0;
-}
-size_t MatrixSearch::extend_mtrx_nd(MatrixNode *mtrx_nd, LmaPsbItem lpi_items[],
- size_t lpi_num, PoolPosType dmi_fr,
- size_t res_row) {
- assert(NULL != mtrx_nd);
- matrix_[res_row].mtrx_nd_fixed = NULL;
-
- if (mtrx_nd_pool_used_ >= kMtrxNdPoolSize - kMaxNodeARow)
- return 0;
-
- if (0 == mtrx_nd->step) {
- // Because the list is sorted, if the source step is 0, it is only
- // necessary to pick up the first kMaxNodeARow items.
- if (lpi_num > kMaxNodeARow)
- lpi_num = kMaxNodeARow;
- }
-
- MatrixNode *mtrx_nd_res_min = mtrx_nd_pool_ + matrix_[res_row].mtrx_nd_pos;
- for (size_t pos = 0; pos < lpi_num; pos++) {
- float score = mtrx_nd->score + lpi_items[pos].psb;
- if (pos > 0 && score - PRUMING_SCORE > mtrx_nd_res_min->score)
- break;
-
- // Try to add a new node
- size_t mtrx_nd_num = matrix_[res_row].mtrx_nd_num;
- MatrixNode *mtrx_nd_res = mtrx_nd_res_min + mtrx_nd_num;
- bool replace = false;
- // Find its position
- while (mtrx_nd_res > mtrx_nd_res_min && score < (mtrx_nd_res - 1)->score) {
- if (static_cast<size_t>(mtrx_nd_res - mtrx_nd_res_min) < kMaxNodeARow)
- *mtrx_nd_res = *(mtrx_nd_res - 1);
- mtrx_nd_res--;
- replace = true;
- }
- if (replace || (mtrx_nd_num < kMaxNodeARow &&
- matrix_[res_row].mtrx_nd_pos + mtrx_nd_num < kMtrxNdPoolSize)) {
- mtrx_nd_res->id = lpi_items[pos].id;
- mtrx_nd_res->score = score;
- mtrx_nd_res->from = mtrx_nd;
- mtrx_nd_res->dmi_fr = dmi_fr;
- mtrx_nd_res->step = res_row;
- if (matrix_[res_row].mtrx_nd_num < kMaxNodeARow)
- matrix_[res_row].mtrx_nd_num++;
+ bool MatrixSearch::add_char_qwerty() {
+ matrix_[pys_decoded_len_].mtrx_nd_num = 0;
+ bool spl_matched = false;
+ uint16 longest_ext = 0;
+ // Extend the search matrix, from the oldest unfixed row. ext_len means
+ // extending length.
+ for ( uint16 ext_len = kMaxPinyinSize + 1; ext_len > 0; ext_len-- ) {
+ if ( ext_len > pys_decoded_len_ - spl_start_[fixed_hzs_] )
+ { continue; }
+ // Refer to the declaration of the variable dmi_has_full_id for the
+ // explanation of this piece of code. In one word, it is used to prevent
+ // from the unwise extending of "shoud ou" but allow the reasonable
+ // extending of "heng ao", "lang a", etc.
+ if ( ext_len > 1 && 0 != longest_ext &&
+ 0 == matrix_[pys_decoded_len_ - ext_len].dmi_has_full_id ) {
+ if ( xi_an_enabled_ )
+ { continue; }
+ else
+ { break; }
+ }
+ uint16 oldrow = pys_decoded_len_ - ext_len;
+ // 0. If that row is before the last fixed step, ignore.
+ if ( spl_start_[fixed_hzs_] > oldrow )
+ { continue; }
+ // 1. Check if that old row has valid MatrixNode. If no, means that row is
+ // not a boundary, either a word boundary or a spelling boundary.
+ // If it is for extending composing phrase, it's OK to ignore the 0.
+ if ( 0 == matrix_[oldrow].mtrx_nd_num && !dmi_c_phrase_ )
+ { continue; }
+ // 2. Get spelling id(s) for the last ext_len chars.
+ uint16 spl_idx;
+ bool is_pre = false;
+ spl_idx = spl_parser_->get_splid_by_str ( pys_ + oldrow,
+ ext_len, &is_pre );
+ if ( is_pre )
+ { spl_matched = true; }
+ if ( 0 == spl_idx )
+ { continue; }
+ bool splid_end_split = is_split_at ( oldrow + ext_len );
+ // 3. Extend the DMI nodes of that old row
+ // + 1 is to extend an extra node from the root
+ for ( PoolPosType dmi_pos = matrix_[oldrow].dmi_pos;
+ dmi_pos < matrix_[oldrow].dmi_pos + matrix_[oldrow].dmi_num + 1;
+ dmi_pos++ ) {
+ DictMatchInfo *dmi = dmi_pool_ + dmi_pos;
+ if ( dmi_pos == matrix_[oldrow].dmi_pos + matrix_[oldrow].dmi_num ) {
+ dmi = NULL; // The last one, NULL means extending from the root.
+ } else {
+ // If the dmi is covered by the fixed arrange, ignore it.
+ if ( fixed_hzs_ > 0 &&
+ pys_decoded_len_ - ext_len - dmi->splstr_len <
+ spl_start_[fixed_hzs_] ) {
+ continue;
+ }
+ // If it is not in mode for composing phrase, and the source DMI node
+ // is marked for composing phrase, ignore this node.
+ if ( dmi->c_phrase != 0 && !dmi_c_phrase_ ) {
+ continue;
+ }
+ }
+ // For example, if "gao" is extended, "g ao" is not allowed.
+ // or "zh" has been passed, "z h" is not allowed.
+ // Both word and word-connection will be prevented.
+ if ( longest_ext > ext_len ) {
+ if ( NULL == dmi && 0 == matrix_[oldrow].dmi_has_full_id ) {
+ continue;
+ }
+ // "z h" is not allowed.
+ if ( NULL != dmi && spl_trie_->is_half_id ( dmi->spl_id ) ) {
+ continue;
+ }
+ }
+ dep_->splids_extended = 0;
+ if ( NULL != dmi ) {
+ uint16 prev_ids_num = dmi->dict_level;
+ if ( ( !dmi_c_phrase_ && prev_ids_num >= kMaxLemmaSize ) ||
+ ( dmi_c_phrase_ && prev_ids_num >= kMaxRowNum ) ) {
+ continue;
+ }
+ DictMatchInfo *d = dmi;
+ while ( d ) {
+ dep_->splids[--prev_ids_num] = d->spl_id;
+ if ( ( PoolPosType ) - 1 == d->dmi_fr )
+ { break; }
+ d = dmi_pool_ + d->dmi_fr;
+ }
+ assert ( 0 == prev_ids_num );
+ dep_->splids_extended = dmi->dict_level;
+ }
+ dep_->splids[dep_->splids_extended] = spl_idx;
+ dep_->ext_len = ext_len;
+ dep_->splid_end_split = splid_end_split;
+ dep_->id_num = 1;
+ dep_->id_start = spl_idx;
+ if ( spl_trie_->is_half_id ( spl_idx ) ) {
+ // Get the full id list
+ dep_->id_num = spl_trie_->half_to_full ( spl_idx, & ( dep_->id_start ) );
+ assert ( dep_->id_num > 0 );
+ }
+ uint16 new_dmi_num;
+ new_dmi_num = extend_dmi ( dep_, dmi );
+ if ( new_dmi_num > 0 ) {
+ if ( dmi_c_phrase_ ) {
+ dmi_pool_[dmi_pool_used_].c_phrase = 1;
+ }
+ matrix_[pys_decoded_len_].dmi_num += new_dmi_num;
+ dmi_pool_used_ += new_dmi_num;
+ if ( !spl_trie_->is_half_id ( spl_idx ) )
+ { matrix_[pys_decoded_len_].dmi_has_full_id = 1; }
+ }
+ // If get candiate lemmas, try to extend the path
+ if ( lpi_total_ > 0 ) {
+ uint16 fr_row;
+ if ( NULL == dmi ) {
+ fr_row = oldrow;
+ } else {
+ assert ( oldrow >= dmi->splstr_len );
+ fr_row = oldrow - dmi->splstr_len;
+ }
+ for ( PoolPosType mtrx_nd_pos = matrix_[fr_row].mtrx_nd_pos;
+ mtrx_nd_pos < matrix_[fr_row].mtrx_nd_pos +
+ matrix_[fr_row].mtrx_nd_num;
+ mtrx_nd_pos++ ) {
+ MatrixNode *mtrx_nd = mtrx_nd_pool_ + mtrx_nd_pos;
+ extend_mtrx_nd ( mtrx_nd, lpi_items_, lpi_total_,
+ dmi_pool_used_ - new_dmi_num, pys_decoded_len_ );
+ if ( longest_ext == 0 )
+ { longest_ext = ext_len; }
+ }
+ }
+ } // for dmi_pos
+ } // for ext_len
+ mtrx_nd_pool_used_ += matrix_[pys_decoded_len_].mtrx_nd_num;
+ if ( dmi_c_phrase_ )
+ { return true; }
+ return ( matrix_[pys_decoded_len_].mtrx_nd_num != 0 || spl_matched );
}
- }
- return matrix_[res_row].mtrx_nd_num;
-}
-PoolPosType MatrixSearch::match_dmi(size_t step_to, uint16 spl_ids[],
- uint16 spl_id_num) {
- if (pys_decoded_len_ < step_to || 0 == matrix_[step_to].dmi_num) {
- return static_cast<PoolPosType>(-1);
- }
-
- for (PoolPosType dmi_pos = 0; dmi_pos < matrix_[step_to].dmi_num; dmi_pos++) {
- DictMatchInfo *dmi = dmi_pool_ + matrix_[step_to].dmi_pos + dmi_pos;
-
- if (dmi->dict_level != spl_id_num)
- continue;
-
- bool matched = true;
- for (uint16 spl_pos = 0; spl_pos < spl_id_num; spl_pos++) {
- if (spl_ids[spl_id_num - spl_pos - 1] != dmi->spl_id) {
- matched = false;
- break;
- }
-
- dmi = dmi_pool_ + dmi->dmi_fr;
- }
- if (matched) {
- return matrix_[step_to].dmi_pos + dmi_pos;
+ void MatrixSearch::prepare_candidates() {
+ // Get candiates from the first un-fixed step.
+ uint16 lma_size_max = kMaxLemmaSize;
+ if ( lma_size_max > spl_id_num_ - fixed_hzs_ )
+ { lma_size_max = spl_id_num_ - fixed_hzs_; }
+ uint16 lma_size = lma_size_max;
+ // If the full sentense candidate's unfixed part may be the same with a normal
+ // lemma. Remove the lemma candidate in this case.
+ char16 fullsent[kMaxLemmaSize + 1];
+ char16 *pfullsent = NULL;
+ uint16 sent_len;
+ pfullsent = get_candidate0 ( fullsent, kMaxLemmaSize + 1, &sent_len, true );
+ // If the unfixed part contains more than one ids, it is not necessary to
+ // check whether a lemma's string is the same to the unfixed part of the full
+ // sentence candidate, so, set it to NULL;
+ if ( sent_len > kMaxLemmaSize )
+ { pfullsent = NULL; }
+ lpi_total_ = 0;
+ size_t lpi_num_full_match = 0; // Number of items which are fully-matched.
+ while ( lma_size > 0 ) {
+ size_t lma_num;
+ lma_num = get_lpis ( spl_id_ + fixed_hzs_, lma_size,
+ lpi_items_ + lpi_total_,
+ size_t ( kMaxLmaPsbItems - lpi_total_ ),
+ pfullsent, lma_size == lma_size_max );
+ if ( lma_num > 0 ) {
+ lpi_total_ += lma_num;
+ // For next lemma candidates which are not the longest, it is not
+ // necessary to compare with the full sentence candiate.
+ pfullsent = NULL;
+ }
+ if ( lma_size == lma_size_max ) {
+ lpi_num_full_match = lpi_total_;
+ }
+ lma_size--;
+ }
+ // Sort those partially-matched items by their unified scores.
+ myqsort ( lpi_items_ + lpi_num_full_match, lpi_total_ - lpi_num_full_match,
+ sizeof ( LmaPsbItem ), cmp_lpi_with_unified_psb );
+ if ( kPrintDebug0 ) {
+ printf ( "-----Prepare candidates, score:\n" );
+ for ( size_t a = 0; a < lpi_total_; a++ ) {
+ printf ( "[%03d]%d ", a, lpi_items_[a].psb );
+ if ( ( a + 1 ) % 6 == 0 ) { printf ( "\n" ); }
+ }
+ printf ( "\n" );
+ }
+ if ( kPrintDebug0 ) {
+ printf ( "--- lpi_total_ = %d\n", lpi_total_ );
+ }
}
- }
-
- return static_cast<PoolPosType>(-1);
-}
-
-char16* MatrixSearch::get_candidate0(char16 *cand_str, size_t max_len,
- uint16 *retstr_len,
- bool only_unfixed) {
- if (pys_decoded_len_ == 0 ||
- matrix_[pys_decoded_len_].mtrx_nd_num == 0)
- return NULL;
- LemmaIdType idxs[kMaxRowNum];
- size_t id_num = 0;
-
- MatrixNode *mtrx_nd = mtrx_nd_pool_ + matrix_[pys_decoded_len_].mtrx_nd_pos;
-
- if (kPrintDebug0) {
- printf("--- sentence score: %f\n", mtrx_nd->score);
- }
-
- if (kPrintDebug1) {
- printf("==============Sentence DMI (reverse order) begin===========>>\n");
- }
-
- while (mtrx_nd != NULL) {
- idxs[id_num] = mtrx_nd->id;
- id_num++;
-
- if (kPrintDebug1) {
- printf("---MatrixNode [step: %d, lma_idx: %d, total score:%.5f]\n",
- mtrx_nd->step, mtrx_nd->id, mtrx_nd->score);
- debug_print_dmi(mtrx_nd->dmi_fr, 1);
+ const char *MatrixSearch::get_pystr ( size_t *decoded_len ) {
+ if ( !inited_ || NULL == decoded_len )
+ { return NULL; }
+ *decoded_len = pys_decoded_len_;
+ return pys_;
}
- mtrx_nd = mtrx_nd->from;
- }
-
- if (kPrintDebug1) {
- printf("<<==============Sentence DMI (reverse order) end=============\n");
- }
-
- size_t ret_pos = 0;
- do {
- id_num--;
- if (0 == idxs[id_num])
- continue;
-
- char16 str[kMaxLemmaSize + 1];
- uint16 str_len = get_lemma_str(idxs[id_num], str, kMaxLemmaSize + 1);
- if (str_len > 0 && ((!only_unfixed && max_len - ret_pos > str_len) ||
- (only_unfixed && max_len - ret_pos + fixed_hzs_ > str_len))) {
- if (!only_unfixed)
- utf16_strncpy(cand_str + ret_pos, str, str_len);
- else if (ret_pos >= fixed_hzs_)
- utf16_strncpy(cand_str + ret_pos - fixed_hzs_, str, str_len);
-
- ret_pos += str_len;
- } else {
- return NULL;
+ void MatrixSearch::merge_fixed_lmas ( size_t del_spl_pos ) {
+ if ( fixed_lmas_ == 0 )
+ { return; }
+ // Update spelling segmentation information first.
+ spl_id_num_ -= 1;
+ uint16 del_py_len = spl_start_[del_spl_pos + 1] - spl_start_[del_spl_pos];
+ for ( size_t pos = del_spl_pos; pos <= spl_id_num_; pos++ ) {
+ spl_start_[pos] = spl_start_[pos + 1] - del_py_len;
+ if ( pos == spl_id_num_ )
+ { break; }
+ spl_id_[pos] = spl_id_[pos + 1];
+ }
+ // Begin to merge.
+ uint16 phrase_len = 0;
+ // Update the spelling ids to the composing phrase.
+ // We need to convert these ids into full id in the future.
+ memcpy ( c_phrase_.spl_ids, spl_id_, spl_id_num_ * sizeof ( uint16 ) );
+ memcpy ( c_phrase_.spl_start, spl_start_, ( spl_id_num_ + 1 ) * sizeof ( uint16 ) );
+ // If composing phrase has not been created, first merge all fixed
+ // lemmas into a composing phrase without deletion.
+ if ( fixed_lmas_ > 1 || kLemmaIdComposing != lma_id_[0] ) {
+ uint16 bp = 1; // Begin position of real fixed lemmas.
+ // There is no existing composing phrase.
+ if ( kLemmaIdComposing != lma_id_[0] ) {
+ c_phrase_.sublma_num = 0;
+ bp = 0;
+ }
+ uint16 sub_num = c_phrase_.sublma_num;
+ for ( uint16 pos = bp; pos <= fixed_lmas_; pos++ ) {
+ c_phrase_.sublma_start[sub_num + pos - bp] = lma_start_[pos];
+ if ( lma_start_[pos] > del_spl_pos ) {
+ c_phrase_.sublma_start[sub_num + pos - bp] -= 1;
+ }
+ if ( pos == fixed_lmas_ )
+ { break; }
+ uint16 lma_len;
+ char16 *lma_str = c_phrase_.chn_str +
+ c_phrase_.sublma_start[sub_num] + phrase_len;
+ lma_len = get_lemma_str ( lma_id_[pos], lma_str, kMaxRowNum - phrase_len );
+ assert ( lma_len == lma_start_[pos + 1] - lma_start_[pos] );
+ phrase_len += lma_len;
+ }
+ assert ( phrase_len == lma_start_[fixed_lmas_] );
+ c_phrase_.length = phrase_len; // will be deleted by 1
+ c_phrase_.sublma_num += fixed_lmas_ - bp;
+ } else {
+ for ( uint16 pos = 0; pos <= c_phrase_.sublma_num; pos++ ) {
+ if ( c_phrase_.sublma_start[pos] > del_spl_pos ) {
+ c_phrase_.sublma_start[pos] -= 1;
+ }
+ }
+ phrase_len = c_phrase_.length;
+ }
+ assert ( phrase_len > 0 );
+ if ( 1 == phrase_len ) {
+ // After the only one is deleted, nothing will be left.
+ fixed_lmas_ = 0;
+ return;
+ }
+ // Delete the Chinese character in the merged phrase.
+ // The corresponding elements in spl_ids and spl_start of the
+ // phrase have been deleted.
+ char16 *chn_str = c_phrase_.chn_str + del_spl_pos;
+ for ( uint16 pos = 0;
+ pos < c_phrase_.sublma_start[c_phrase_.sublma_num] - del_spl_pos;
+ pos++ ) {
+ chn_str[pos] = chn_str[pos + 1];
+ }
+ c_phrase_.length -= 1;
+ // If the deleted spelling id is in a sub lemma which contains more than
+ // one id, del_a_sub will be false; but if the deleted id is in a sub lemma
+ // which only contains 1 id, the whole sub lemma needs to be deleted, so
+ // del_a_sub will be true.
+ bool del_a_sub = false;
+ for ( uint16 pos = 1; pos <= c_phrase_.sublma_num; pos++ ) {
+ if ( c_phrase_.sublma_start[pos - 1] ==
+ c_phrase_.sublma_start[pos] ) {
+ del_a_sub = true;
+ }
+ if ( del_a_sub ) {
+ c_phrase_.sublma_start[pos - 1] =
+ c_phrase_.sublma_start[pos];
+ }
+ }
+ if ( del_a_sub )
+ { c_phrase_.sublma_num -= 1; }
+ return;
}
- } while (id_num != 0);
-
- if (!only_unfixed) {
- if (NULL != retstr_len)
- *retstr_len = ret_pos;
- cand_str[ret_pos] = (char16)'\0';
- } else {
- if (NULL != retstr_len)
- *retstr_len = ret_pos - fixed_hzs_;
- cand_str[ret_pos - fixed_hzs_] = (char16)'\0';
- }
- return cand_str;
-}
-
-size_t MatrixSearch::get_lpis(const uint16* splid_str, size_t splid_str_len,
- LmaPsbItem* lma_buf, size_t max_lma_buf,
- const char16 *pfullsent, bool sort_by_psb) {
- if (splid_str_len > kMaxLemmaSize)
- return 0;
-
- size_t num1 = dict_trie_->get_lpis(splid_str, splid_str_len,
- lma_buf, max_lma_buf);
- size_t num2 = 0;
- if (NULL != user_dict_) {
- num2 = user_dict_->get_lpis(splid_str, splid_str_len,
- lma_buf + num1, max_lma_buf - num1);
- }
-
- size_t num = num1 + num2;
-
- if (0 == num)
- return 0;
- // Remove repeated items.
- if (splid_str_len > 1) {
- LmaPsbStrItem *lpsis = reinterpret_cast<LmaPsbStrItem*>(lma_buf + num);
- size_t lpsi_num = (max_lma_buf - num) * sizeof(LmaPsbItem) /
- sizeof(LmaPsbStrItem);
- assert(lpsi_num > num);
- if (num > lpsi_num) num = lpsi_num;
- lpsi_num = num;
-
- for (size_t pos = 0; pos < lpsi_num; pos++) {
- lpsis[pos].lpi = lma_buf[pos];
- get_lemma_str(lma_buf[pos].id, lpsis[pos].str, kMaxLemmaSize + 1);
+ void MatrixSearch::get_spl_start_id() {
+ lma_id_num_ = 0;
+ lma_start_[0] = 0;
+ spl_id_num_ = 0;
+ spl_start_[0] = 0;
+ if ( !inited_ || 0 == pys_decoded_len_ ||
+ 0 == matrix_[pys_decoded_len_].mtrx_nd_num )
+ { return; }
+ // Calculate number of lemmas and spellings
+ // Only scan those part which is not fixed.
+ lma_id_num_ = fixed_lmas_;
+ spl_id_num_ = fixed_hzs_;
+ MatrixNode *mtrx_nd = mtrx_nd_pool_ + matrix_[pys_decoded_len_].mtrx_nd_pos;
+ while ( mtrx_nd != mtrx_nd_pool_ ) {
+ if ( fixed_hzs_ > 0 ) {
+ if ( mtrx_nd->step <= spl_start_[fixed_hzs_] )
+ { break; }
+ }
+ // Update the spelling segamentation information
+ unsigned char word_splstr_len = 0;
+ PoolPosType dmi_fr = mtrx_nd->dmi_fr;
+ if ( ( PoolPosType ) - 1 != dmi_fr )
+ { word_splstr_len = dmi_pool_[dmi_fr].splstr_len; }
+ while ( ( PoolPosType ) - 1 != dmi_fr ) {
+ spl_start_[spl_id_num_ + 1] = mtrx_nd->step -
+ ( word_splstr_len - dmi_pool_[dmi_fr].splstr_len );
+ spl_id_[spl_id_num_] = dmi_pool_[dmi_fr].spl_id;
+ spl_id_num_++;
+ dmi_fr = dmi_pool_[dmi_fr].dmi_fr;
+ }
+ // Update the lemma segmentation information
+ lma_start_[lma_id_num_ + 1] = spl_id_num_;
+ lma_id_[lma_id_num_] = mtrx_nd->id;
+ lma_id_num_++;
+ mtrx_nd = mtrx_nd->from;
+ }
+ // Reverse the result of spelling info
+ for ( size_t pos = fixed_hzs_;
+ pos < fixed_hzs_ + ( spl_id_num_ - fixed_hzs_ + 1 ) / 2; pos++ ) {
+ if ( spl_id_num_ + fixed_hzs_ - pos != pos + 1 ) {
+ spl_start_[pos + 1] ^= spl_start_[spl_id_num_ - pos + fixed_hzs_];
+ spl_start_[spl_id_num_ - pos + fixed_hzs_] ^= spl_start_[pos + 1];
+ spl_start_[pos + 1] ^= spl_start_[spl_id_num_ - pos + fixed_hzs_];
+ spl_id_[pos] ^= spl_id_[spl_id_num_ + fixed_hzs_ - pos - 1];
+ spl_id_[spl_id_num_ + fixed_hzs_ - pos - 1] ^= spl_id_[pos];
+ spl_id_[pos] ^= spl_id_[spl_id_num_ + fixed_hzs_ - pos - 1];
+ }
+ }
+ // Reverse the result of lemma info
+ for ( size_t pos = fixed_lmas_;
+ pos < fixed_lmas_ + ( lma_id_num_ - fixed_lmas_ + 1 ) / 2; pos++ ) {
+ assert ( lma_id_num_ + fixed_lmas_ - pos - 1 >= pos );
+ if ( lma_id_num_ + fixed_lmas_ - pos > pos + 1 ) {
+ lma_start_[pos + 1] ^= lma_start_[lma_id_num_ - pos + fixed_lmas_];
+ lma_start_[lma_id_num_ - pos + fixed_lmas_] ^= lma_start_[pos + 1];
+ lma_start_[pos + 1] ^= lma_start_[lma_id_num_ - pos + fixed_lmas_];
+ lma_id_[pos] ^= lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_];
+ lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_] ^= lma_id_[pos];
+ lma_id_[pos] ^= lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_];
+ }
+ }
+ for ( size_t pos = fixed_lmas_ + 1; pos <= lma_id_num_; pos++ ) {
+ if ( pos < lma_id_num_ )
+ lma_start_[pos] = lma_start_[pos - 1] +
+ ( lma_start_[pos] - lma_start_[pos + 1] );
+ else
+ lma_start_[pos] = lma_start_[pos - 1] + lma_start_[pos] -
+ lma_start_[fixed_lmas_];
+ }
+ // Find the last fixed position
+ fixed_hzs_ = 0;
+ for ( size_t pos = spl_id_num_; pos > 0; pos-- ) {
+ if ( NULL != matrix_[spl_start_[pos]].mtrx_nd_fixed ) {
+ fixed_hzs_ = pos;
+ break;
+ }
+ }
+ return;
}
- myqsort(lpsis, lpsi_num, sizeof(LmaPsbStrItem), cmp_lpsi_with_str);
-
- size_t remain_num = 0;
- for (size_t pos = 0; pos < lpsi_num; pos++) {
- if (pos > 0 && utf16_strcmp(lpsis[pos].str, lpsis[pos - 1].str) == 0) {
- if (lpsis[pos].lpi.psb < lpsis[pos - 1].lpi.psb) {
- assert(remain_num > 0);
- lma_buf[remain_num - 1] = lpsis[pos].lpi;
- }
- continue;
- }
- if (NULL != pfullsent && utf16_strcmp(lpsis[pos].str, pfullsent) == 0)
- continue;
-
- lma_buf[remain_num] = lpsis[pos].lpi;
- remain_num++;
+ size_t MatrixSearch::get_spl_start ( const uint16 *&spl_start ) {
+ get_spl_start_id();
+ spl_start = spl_start_;
+ return spl_id_num_;
}
- // Update the result number
- num = remain_num;
- } else {
- // For single character, some characters have more than one spelling, for
- // example, "de" and "di" are all valid for a Chinese character, so when
- // the user input "d", repeated items are generated.
- // For single character lemmas, Hanzis will be gotten
- for (size_t pos = 0; pos < num; pos++) {
- char16 hanzis[2];
- get_lemma_str(lma_buf[pos].id, hanzis, 2);
- lma_buf[pos].hanzi = hanzis[0];
+ size_t MatrixSearch::extend_dmi ( DictExtPara *dep, DictMatchInfo *dmi_s ) {
+ if ( dmi_pool_used_ >= kDmiPoolSize ) { return 0; }
+ if ( dmi_c_phrase_ )
+ { return extend_dmi_c ( dep, dmi_s ); }
+ LpiCache &lpi_cache = LpiCache::get_instance();
+ uint16 splid = dep->splids[dep->splids_extended];
+ bool cached = false;
+ if ( 0 == dep->splids_extended )
+ { cached = lpi_cache.is_cached ( splid ); }
+ // 1. If this is a half Id, get its corresponding full starting Id and
+ // number of full Id.
+ size_t ret_val = 0;
+ PoolPosType mtrx_dmi_fr = ( PoolPosType ) - 1; // From which dmi node
+ lpi_total_ = 0;
+ MileStoneHandle from_h[3];
+ from_h[0] = 0;
+ from_h[1] = 0;
+ if ( 0 != dep->splids_extended ) {
+ from_h[0] = dmi_s->dict_handles[0];
+ from_h[1] = dmi_s->dict_handles[1];
+ }
+ // 2. Begin exgtending in the system dictionary
+ size_t lpi_num = 0;
+ MileStoneHandle handles[2];
+ handles[0] = handles[1] = 0;
+ if ( from_h[0] > 0 || NULL == dmi_s ) {
+ handles[0] = dict_trie_->extend_dict ( from_h[0], dep, lpi_items_,
+ kMaxLmaPsbItems, &lpi_num );
+ }
+ if ( handles[0] > 0 )
+ { lpi_total_ = lpi_num; }
+ if ( NULL == dmi_s ) { // from root
+ assert ( 0 != handles[0] );
+ mtrx_dmi_fr = dmi_pool_used_;
+ }
+ // 3. Begin extending in the user dictionary
+ if ( NULL != user_dict_ && ( from_h[1] > 0 || NULL == dmi_s ) ) {
+ handles[1] = user_dict_->extend_dict ( from_h[1], dep,
+ lpi_items_ + lpi_total_,
+ kMaxLmaPsbItems - lpi_total_,
+ &lpi_num );
+ if ( handles[1] > 0 ) {
+ if ( kPrintDebug0 ) {
+ for ( size_t t = 0; t < lpi_num; t++ ) {
+ printf ( "--Extend in user dict: uid:%d uscore:%d\n", lpi_items_[lpi_total_ + t].id,
+ lpi_items_[lpi_total_ + t].psb );
+ }
+ }
+ lpi_total_ += lpi_num;
+ }
+ }
+ if ( 0 != handles[0] || 0 != handles[1] ) {
+ if ( dmi_pool_used_ >= kDmiPoolSize ) { return 0; }
+ DictMatchInfo *dmi_add = dmi_pool_ + dmi_pool_used_;
+ if ( NULL == dmi_s ) {
+ fill_dmi ( dmi_add, handles,
+ ( PoolPosType ) - 1, splid,
+ 1, 1, dep->splid_end_split, dep->ext_len,
+ spl_trie_->is_half_id ( splid ) ? 0 : 1 );
+ } else {
+ fill_dmi ( dmi_add, handles,
+ dmi_s - dmi_pool_, splid, 1,
+ dmi_s->dict_level + 1, dep->splid_end_split,
+ dmi_s->splstr_len + dep->ext_len,
+ spl_trie_->is_half_id ( splid ) ? 0 : dmi_s->all_full_id );
+ }
+ ret_val = 1;
+ }
+ if ( !cached ) {
+ if ( 0 == lpi_total_ )
+ { return ret_val; }
+ if ( kPrintDebug0 ) {
+ printf ( "--- lpi_total_ = %d\n", lpi_total_ );
+ }
+ myqsort ( lpi_items_, lpi_total_, sizeof ( LmaPsbItem ), cmp_lpi_with_psb );
+ if ( NULL == dmi_s && spl_trie_->is_half_id ( splid ) )
+ { lpi_total_ = lpi_cache.put_cache ( splid, lpi_items_, lpi_total_ ); }
+ } else {
+ assert ( spl_trie_->is_half_id ( splid ) );
+ lpi_total_ = lpi_cache.get_cache ( splid, lpi_items_, kMaxLmaPsbItems );
+ }
+ return ret_val;
}
- myqsort(lma_buf, num, sizeof(LmaPsbItem), cmp_lpi_with_hanzi);
-
- size_t remain_num = 0;
- for (size_t pos = 0; pos < num; pos++) {
- if (pos > 0 && lma_buf[pos].hanzi == lma_buf[pos - 1].hanzi) {
- if (NULL != pfullsent &&
- static_cast<char16>(0) == pfullsent[1] &&
- lma_buf[pos].hanzi == pfullsent[0])
- continue;
-
- if (lma_buf[pos].psb < lma_buf[pos - 1].psb) {
- assert(remain_num > 0);
- assert(lma_buf[remain_num - 1].hanzi == lma_buf[pos].hanzi);
- lma_buf[remain_num - 1] = lma_buf[pos];
- }
- continue;
- }
- if (NULL != pfullsent &&
- static_cast<char16>(0) == pfullsent[1] &&
- lma_buf[pos].hanzi == pfullsent[0])
- continue;
-
- lma_buf[remain_num] = lma_buf[pos];
- remain_num++;
+ size_t MatrixSearch::extend_dmi_c ( DictExtPara *dep, DictMatchInfo *dmi_s ) {
+ lpi_total_ = 0;
+ uint16 pos = dep->splids_extended;
+ assert ( dmi_c_phrase_ );
+ if ( pos >= c_phrase_.length )
+ { return 0; }
+ uint16 splid = dep->splids[pos];
+ if ( splid == c_phrase_.spl_ids[pos] ) {
+ DictMatchInfo *dmi_add = dmi_pool_ + dmi_pool_used_;
+ MileStoneHandle handles[2]; // Actually never used.
+ if ( NULL == dmi_s )
+ fill_dmi ( dmi_add, handles,
+ ( PoolPosType ) - 1, splid,
+ 1, 1, dep->splid_end_split, dep->ext_len,
+ spl_trie_->is_half_id ( splid ) ? 0 : 1 );
+ else
+ fill_dmi ( dmi_add, handles,
+ dmi_s - dmi_pool_, splid, 1,
+ dmi_s->dict_level + 1, dep->splid_end_split,
+ dmi_s->splstr_len + dep->ext_len,
+ spl_trie_->is_half_id ( splid ) ? 0 : dmi_s->all_full_id );
+ if ( pos == c_phrase_.length - 1 ) {
+ lpi_items_[0].id = kLemmaIdComposing;
+ lpi_items_[0].psb = 0; // 0 is bigger than normal lemma score.
+ lpi_total_ = 1;
+ }
+ return 1;
+ }
+ return 0;
}
- num = remain_num;
- }
-
- if (sort_by_psb) {
- myqsort(lma_buf, num, sizeof(LmaPsbItem), cmp_lpi_with_psb);
- }
- return num;
-}
-
-uint16 MatrixSearch::get_lemma_str(LemmaIdType id_lemma, char16 *str_buf,
- uint16 str_max) {
- uint16 str_len = 0;
-
- if (is_system_lemma(id_lemma)) {
- str_len = dict_trie_->get_lemma_str(id_lemma, str_buf, str_max);
- } else if (is_user_lemma(id_lemma)) {
- if (NULL != user_dict_) {
- str_len = user_dict_->get_lemma_str(id_lemma, str_buf, str_max);
- } else {
- str_len = 0;
- str_buf[0] = static_cast<char16>('\0');
+ size_t MatrixSearch::extend_mtrx_nd ( MatrixNode *mtrx_nd, LmaPsbItem lpi_items[],
+ size_t lpi_num, PoolPosType dmi_fr,
+ size_t res_row ) {
+ assert ( NULL != mtrx_nd );
+ matrix_[res_row].mtrx_nd_fixed = NULL;
+ if ( mtrx_nd_pool_used_ >= kMtrxNdPoolSize - kMaxNodeARow )
+ { return 0; }
+ if ( 0 == mtrx_nd->step ) {
+ // Because the list is sorted, if the source step is 0, it is only
+ // necessary to pick up the first kMaxNodeARow items.
+ if ( lpi_num > kMaxNodeARow )
+ { lpi_num = kMaxNodeARow; }
+ }
+ MatrixNode *mtrx_nd_res_min = mtrx_nd_pool_ + matrix_[res_row].mtrx_nd_pos;
+ for ( size_t pos = 0; pos < lpi_num; pos++ ) {
+ float score = mtrx_nd->score + lpi_items[pos].psb;
+ if ( pos > 0 && score - PRUMING_SCORE > mtrx_nd_res_min->score )
+ { break; }
+ // Try to add a new node
+ size_t mtrx_nd_num = matrix_[res_row].mtrx_nd_num;
+ MatrixNode *mtrx_nd_res = mtrx_nd_res_min + mtrx_nd_num;
+ bool replace = false;
+ // Find its position
+ while ( mtrx_nd_res > mtrx_nd_res_min && score < ( mtrx_nd_res - 1 )->score ) {
+ if ( static_cast<size_t> ( mtrx_nd_res - mtrx_nd_res_min ) < kMaxNodeARow )
+ { *mtrx_nd_res = * ( mtrx_nd_res - 1 ); }
+ mtrx_nd_res--;
+ replace = true;
+ }
+ if ( replace || ( mtrx_nd_num < kMaxNodeARow &&
+ matrix_[res_row].mtrx_nd_pos + mtrx_nd_num < kMtrxNdPoolSize ) ) {
+ mtrx_nd_res->id = lpi_items[pos].id;
+ mtrx_nd_res->score = score;
+ mtrx_nd_res->from = mtrx_nd;
+ mtrx_nd_res->dmi_fr = dmi_fr;
+ mtrx_nd_res->step = res_row;
+ if ( matrix_[res_row].mtrx_nd_num < kMaxNodeARow )
+ { matrix_[res_row].mtrx_nd_num++; }
+ }
+ }
+ return matrix_[res_row].mtrx_nd_num;
}
- } else if (is_composing_lemma(id_lemma)) {
- if (str_max <= 1)
- return 0;
- str_len = c_phrase_.sublma_start[c_phrase_.sublma_num];
- if (str_len > str_max - 1)
- str_len = str_max - 1;
- utf16_strncpy(str_buf, c_phrase_.chn_str, str_len);
- str_buf[str_len] = (char16)'\0';
- return str_len;
- }
-
- return str_len;
-}
-
-uint16 MatrixSearch::get_lemma_splids(LemmaIdType id_lemma, uint16 *splids,
- uint16 splids_max, bool arg_valid) {
- uint16 splid_num = 0;
- if (arg_valid) {
- for (splid_num = 0; splid_num < splids_max; splid_num++) {
- if (spl_trie_->is_half_id(splids[splid_num]))
- break;
+ PoolPosType MatrixSearch::match_dmi ( size_t step_to, uint16 spl_ids[],
+ uint16 spl_id_num ) {
+ if ( pys_decoded_len_ < step_to || 0 == matrix_[step_to].dmi_num ) {
+ return static_cast<PoolPosType> ( -1 );
+ }
+ for ( PoolPosType dmi_pos = 0; dmi_pos < matrix_[step_to].dmi_num; dmi_pos++ ) {
+ DictMatchInfo *dmi = dmi_pool_ + matrix_[step_to].dmi_pos + dmi_pos;
+ if ( dmi->dict_level != spl_id_num )
+ { continue; }
+ bool matched = true;
+ for ( uint16 spl_pos = 0; spl_pos < spl_id_num; spl_pos++ ) {
+ if ( spl_ids[spl_id_num - spl_pos - 1] != dmi->spl_id ) {
+ matched = false;
+ break;
+ }
+ dmi = dmi_pool_ + dmi->dmi_fr;
+ }
+ if ( matched ) {
+ return matrix_[step_to].dmi_pos + dmi_pos;
+ }
+ }
+ return static_cast<PoolPosType> ( -1 );
}
- if (splid_num == splids_max)
- return splid_num;
- }
- if (is_system_lemma(id_lemma)) {
- splid_num = dict_trie_->get_lemma_splids(id_lemma, splids, splids_max,
- arg_valid);
- } else if (is_user_lemma(id_lemma)) {
- if (NULL != user_dict_) {
- splid_num = user_dict_->get_lemma_splids(id_lemma, splids, splids_max,
- arg_valid);
- } else {
- splid_num = 0;
- }
- } else if (is_composing_lemma(id_lemma)) {
- if (c_phrase_.length > splids_max) {
- return 0;
- }
- for (uint16 pos = 0; pos < c_phrase_.length; pos++) {
- splids[pos] = c_phrase_.spl_ids[pos];
- if (spl_trie_->is_half_id(splids[pos])) {
- return 0;
- }
+ char16 *MatrixSearch::get_candidate0 ( char16 *cand_str, size_t max_len,
+ uint16 *retstr_len,
+ bool only_unfixed ) {
+ if ( pys_decoded_len_ == 0 ||
+ matrix_[pys_decoded_len_].mtrx_nd_num == 0 )
+ { return NULL; }
+ LemmaIdType idxs[kMaxRowNum];
+ size_t id_num = 0;
+ MatrixNode *mtrx_nd = mtrx_nd_pool_ + matrix_[pys_decoded_len_].mtrx_nd_pos;
+ if ( kPrintDebug0 ) {
+ printf ( "--- sentence score: %f\n", mtrx_nd->score );
+ }
+ if ( kPrintDebug1 ) {
+ printf ( "==============Sentence DMI (reverse order) begin===========>>\n" );
+ }
+ while ( mtrx_nd != NULL ) {
+ idxs[id_num] = mtrx_nd->id;
+ id_num++;
+ if ( kPrintDebug1 ) {
+ printf ( "---MatrixNode [step: %d, lma_idx: %d, total score:%.5f]\n",
+ mtrx_nd->step, mtrx_nd->id, mtrx_nd->score );
+ debug_print_dmi ( mtrx_nd->dmi_fr, 1 );
+ }
+ mtrx_nd = mtrx_nd->from;
+ }
+ if ( kPrintDebug1 ) {
+ printf ( "<<==============Sentence DMI (reverse order) end=============\n" );
+ }
+ size_t ret_pos = 0;
+ do {
+ id_num--;
+ if ( 0 == idxs[id_num] )
+ { continue; }
+ char16 str[kMaxLemmaSize + 1];
+ uint16 str_len = get_lemma_str ( idxs[id_num], str, kMaxLemmaSize + 1 );
+ if ( str_len > 0 && ( ( !only_unfixed && max_len - ret_pos > str_len ) ||
+ ( only_unfixed && max_len - ret_pos + fixed_hzs_ > str_len ) ) ) {
+ if ( !only_unfixed )
+ { utf16_strncpy ( cand_str + ret_pos, str, str_len ); }
+ else if ( ret_pos >= fixed_hzs_ )
+ { utf16_strncpy ( cand_str + ret_pos - fixed_hzs_, str, str_len ); }
+ ret_pos += str_len;
+ } else {
+ return NULL;
+ }
+ } while ( id_num != 0 );
+ if ( !only_unfixed ) {
+ if ( NULL != retstr_len )
+ { *retstr_len = ret_pos; }
+ cand_str[ret_pos] = ( char16 ) '\0';
+ } else {
+ if ( NULL != retstr_len )
+ { *retstr_len = ret_pos - fixed_hzs_; }
+ cand_str[ret_pos - fixed_hzs_] = ( char16 ) '\0';
+ }
+ return cand_str;
}
- }
- return splid_num;
-}
-size_t MatrixSearch::inner_predict(const char16 *fixed_buf, uint16 fixed_len,
- char16 predict_buf[][kMaxPredictSize + 1],
- size_t buf_len) {
- size_t res_total = 0;
- memset(npre_items_, 0, sizeof(NPredictItem) * npre_items_len_);
- // In order to shorten the comments, j-character candidates predicted by
- // i-character prefix are called P(i,j). All candiates predicted by
- // i-character prefix are called P(i,*)
- // Step 1. Get P(kMaxPredictSize, *) and sort them, here
- // P(kMaxPredictSize, *) == P(kMaxPredictSize, 1)
- for (size_t len = fixed_len; len >0; len--) {
- // How many blank items are available
- size_t this_max = npre_items_len_ - res_total;
- size_t res_this;
- // If the history is longer than 1, and we can not get prediction from
- // lemmas longer than 2, in this case, we will add lemmas with
- // highest scores as the prediction result.
- if (fixed_len > 1 && 1 == len && 0 == res_total) {
- // Try to find if recent n (n>1) characters can be a valid lemma in system
- // dictionary.
- bool nearest_n_word = false;
- for (size_t nlen = 2; nlen <= fixed_len; nlen++) {
- if (dict_trie_->get_lemma_id(fixed_buf + fixed_len - nlen, nlen) > 0) {
- nearest_n_word = true;
- break;
- }
- }
- res_this = dict_trie_->predict_top_lmas(nearest_n_word ? len : 0,
- npre_items_ + res_total,
- this_max, res_total);
- res_total += res_this;
+ size_t MatrixSearch::get_lpis ( const uint16 *splid_str, size_t splid_str_len,
+ LmaPsbItem *lma_buf, size_t max_lma_buf,
+ const char16 *pfullsent, bool sort_by_psb ) {
+ if ( splid_str_len > kMaxLemmaSize )
+ { return 0; }
+ size_t num1 = dict_trie_->get_lpis ( splid_str, splid_str_len,
+ lma_buf, max_lma_buf );
+ size_t num2 = 0;
+ if ( NULL != user_dict_ ) {
+ num2 = user_dict_->get_lpis ( splid_str, splid_str_len,
+ lma_buf + num1, max_lma_buf - num1 );
+ }
+ size_t num = num1 + num2;
+ if ( 0 == num )
+ { return 0; }
+ // Remove repeated items.
+ if ( splid_str_len > 1 ) {
+ LmaPsbStrItem *lpsis = reinterpret_cast<LmaPsbStrItem *> ( lma_buf + num );
+ size_t lpsi_num = ( max_lma_buf - num ) * sizeof ( LmaPsbItem ) /
+ sizeof ( LmaPsbStrItem );
+ assert ( lpsi_num > num );
+ if ( num > lpsi_num ) { num = lpsi_num; }
+ lpsi_num = num;
+ for ( size_t pos = 0; pos < lpsi_num; pos++ ) {
+ lpsis[pos].lpi = lma_buf[pos];
+ get_lemma_str ( lma_buf[pos].id, lpsis[pos].str, kMaxLemmaSize + 1 );
+ }
+ myqsort ( lpsis, lpsi_num, sizeof ( LmaPsbStrItem ), cmp_lpsi_with_str );
+ size_t remain_num = 0;
+ for ( size_t pos = 0; pos < lpsi_num; pos++ ) {
+ if ( pos > 0 && utf16_strcmp ( lpsis[pos].str, lpsis[pos - 1].str ) == 0 ) {
+ if ( lpsis[pos].lpi.psb < lpsis[pos - 1].lpi.psb ) {
+ assert ( remain_num > 0 );
+ lma_buf[remain_num - 1] = lpsis[pos].lpi;
+ }
+ continue;
+ }
+ if ( NULL != pfullsent && utf16_strcmp ( lpsis[pos].str, pfullsent ) == 0 )
+ { continue; }
+ lma_buf[remain_num] = lpsis[pos].lpi;
+ remain_num++;
+ }
+ // Update the result number
+ num = remain_num;
+ } else {
+ // For single character, some characters have more than one spelling, for
+ // example, "de" and "di" are all valid for a Chinese character, so when
+ // the user input "d", repeated items are generated.
+ // For single character lemmas, Hanzis will be gotten
+ for ( size_t pos = 0; pos < num; pos++ ) {
+ char16 hanzis[2];
+ get_lemma_str ( lma_buf[pos].id, hanzis, 2 );
+ lma_buf[pos].hanzi = hanzis[0];
+ }
+ myqsort ( lma_buf, num, sizeof ( LmaPsbItem ), cmp_lpi_with_hanzi );
+ size_t remain_num = 0;
+ for ( size_t pos = 0; pos < num; pos++ ) {
+ if ( pos > 0 && lma_buf[pos].hanzi == lma_buf[pos - 1].hanzi ) {
+ if ( NULL != pfullsent &&
+ static_cast<char16> ( 0 ) == pfullsent[1] &&
+ lma_buf[pos].hanzi == pfullsent[0] )
+ { continue; }
+ if ( lma_buf[pos].psb < lma_buf[pos - 1].psb ) {
+ assert ( remain_num > 0 );
+ assert ( lma_buf[remain_num - 1].hanzi == lma_buf[pos].hanzi );
+ lma_buf[remain_num - 1] = lma_buf[pos];
+ }
+ continue;
+ }
+ if ( NULL != pfullsent &&
+ static_cast<char16> ( 0 ) == pfullsent[1] &&
+ lma_buf[pos].hanzi == pfullsent[0] )
+ { continue; }
+ lma_buf[remain_num] = lma_buf[pos];
+ remain_num++;
+ }
+ num = remain_num;
+ }
+ if ( sort_by_psb ) {
+ myqsort ( lma_buf, num, sizeof ( LmaPsbItem ), cmp_lpi_with_psb );
+ }
+ return num;
}
- // How many blank items are available
- this_max = npre_items_len_ - res_total;
- res_this = 0;
- if (!kOnlyUserDictPredict) {
- res_this =
- dict_trie_->predict(fixed_buf + fixed_len - len, len,
- npre_items_ + res_total, this_max,
- res_total);
+ uint16 MatrixSearch::get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf,
+ uint16 str_max ) {
+ uint16 str_len = 0;
+ if ( is_system_lemma ( id_lemma ) ) {
+ str_len = dict_trie_->get_lemma_str ( id_lemma, str_buf, str_max );
+ } else if ( is_user_lemma ( id_lemma ) ) {
+ if ( NULL != user_dict_ ) {
+ str_len = user_dict_->get_lemma_str ( id_lemma, str_buf, str_max );
+ } else {
+ str_len = 0;
+ str_buf[0] = static_cast<char16> ( '\0' );
+ }
+ } else if ( is_composing_lemma ( id_lemma ) ) {
+ if ( str_max <= 1 )
+ { return 0; }
+ str_len = c_phrase_.sublma_start[c_phrase_.sublma_num];
+ if ( str_len > str_max - 1 )
+ { str_len = str_max - 1; }
+ utf16_strncpy ( str_buf, c_phrase_.chn_str, str_len );
+ str_buf[str_len] = ( char16 ) '\0';
+ return str_len;
+ }
+ return str_len;
}
- if (NULL != user_dict_) {
- res_this = res_this +
- user_dict_->predict(fixed_buf + fixed_len - len, len,
- npre_items_ + res_total + res_this,
- this_max - res_this, res_total + res_this);
+ uint16 MatrixSearch::get_lemma_splids ( LemmaIdType id_lemma, uint16 *splids,
+ uint16 splids_max, bool arg_valid ) {
+ uint16 splid_num = 0;
+ if ( arg_valid ) {
+ for ( splid_num = 0; splid_num < splids_max; splid_num++ ) {
+ if ( spl_trie_->is_half_id ( splids[splid_num] ) )
+ { break; }
+ }
+ if ( splid_num == splids_max )
+ { return splid_num; }
+ }
+ if ( is_system_lemma ( id_lemma ) ) {
+ splid_num = dict_trie_->get_lemma_splids ( id_lemma, splids, splids_max,
+ arg_valid );
+ } else if ( is_user_lemma ( id_lemma ) ) {
+ if ( NULL != user_dict_ ) {
+ splid_num = user_dict_->get_lemma_splids ( id_lemma, splids, splids_max,
+ arg_valid );
+ } else {
+ splid_num = 0;
+ }
+ } else if ( is_composing_lemma ( id_lemma ) ) {
+ if ( c_phrase_.length > splids_max ) {
+ return 0;
+ }
+ for ( uint16 pos = 0; pos < c_phrase_.length; pos++ ) {
+ splids[pos] = c_phrase_.spl_ids[pos];
+ if ( spl_trie_->is_half_id ( splids[pos] ) ) {
+ return 0;
+ }
+ }
+ }
+ return splid_num;
}
- if (kPredictLimitGt1) {
- myqsort(npre_items_ + res_total, res_this, sizeof(NPredictItem),
- cmp_npre_by_score);
-
- if (len > 3) {
- if (res_this > kMaxPredictNumByGt3)
- res_this = kMaxPredictNumByGt3;
- } else if (3 == len) {
- if (res_this > kMaxPredictNumBy3)
- res_this = kMaxPredictNumBy3;
- } else if (2 == len) {
- if (res_this > kMaxPredictNumBy2)
- res_this = kMaxPredictNumBy2;
- }
+ size_t MatrixSearch::inner_predict ( const char16 *fixed_buf, uint16 fixed_len,
+ char16 predict_buf[][kMaxPredictSize + 1],
+ size_t buf_len ) {
+ size_t res_total = 0;
+ memset ( npre_items_, 0, sizeof ( NPredictItem ) * npre_items_len_ );
+ // In order to shorten the comments, j-character candidates predicted by
+ // i-character prefix are called P(i,j). All candiates predicted by
+ // i-character prefix are called P(i,*)
+ // Step 1. Get P(kMaxPredictSize, *) and sort them, here
+ // P(kMaxPredictSize, *) == P(kMaxPredictSize, 1)
+ for ( size_t len = fixed_len; len > 0; len-- ) {
+ // How many blank items are available
+ size_t this_max = npre_items_len_ - res_total;
+ size_t res_this;
+ // If the history is longer than 1, and we can not get prediction from
+ // lemmas longer than 2, in this case, we will add lemmas with
+ // highest scores as the prediction result.
+ if ( fixed_len > 1 && 1 == len && 0 == res_total ) {
+ // Try to find if recent n (n>1) characters can be a valid lemma in system
+ // dictionary.
+ bool nearest_n_word = false;
+ for ( size_t nlen = 2; nlen <= fixed_len; nlen++ ) {
+ if ( dict_trie_->get_lemma_id ( fixed_buf + fixed_len - nlen, nlen ) > 0 ) {
+ nearest_n_word = true;
+ break;
+ }
+ }
+ res_this = dict_trie_->predict_top_lmas ( nearest_n_word ? len : 0,
+ npre_items_ + res_total,
+ this_max, res_total );
+ res_total += res_this;
+ }
+ // How many blank items are available
+ this_max = npre_items_len_ - res_total;
+ res_this = 0;
+ if ( !kOnlyUserDictPredict ) {
+ res_this =
+ dict_trie_->predict ( fixed_buf + fixed_len - len, len,
+ npre_items_ + res_total, this_max,
+ res_total );
+ }
+ if ( NULL != user_dict_ ) {
+ res_this = res_this +
+ user_dict_->predict ( fixed_buf + fixed_len - len, len,
+ npre_items_ + res_total + res_this,
+ this_max - res_this, res_total + res_this );
+ }
+ if ( kPredictLimitGt1 ) {
+ myqsort ( npre_items_ + res_total, res_this, sizeof ( NPredictItem ),
+ cmp_npre_by_score );
+ if ( len > 3 ) {
+ if ( res_this > kMaxPredictNumByGt3 )
+ { res_this = kMaxPredictNumByGt3; }
+ } else if ( 3 == len ) {
+ if ( res_this > kMaxPredictNumBy3 )
+ { res_this = kMaxPredictNumBy3; }
+ } else if ( 2 == len ) {
+ if ( res_this > kMaxPredictNumBy2 )
+ { res_this = kMaxPredictNumBy2; }
+ }
+ }
+ res_total += res_this;
+ }
+ res_total = remove_duplicate_npre ( npre_items_, res_total );
+ if ( kPreferLongHistoryPredict ) {
+ myqsort ( npre_items_, res_total, sizeof ( NPredictItem ),
+ cmp_npre_by_hislen_score );
+ } else {
+ myqsort ( npre_items_, res_total, sizeof ( NPredictItem ),
+ cmp_npre_by_score );
+ }
+ if ( buf_len < res_total ) {
+ res_total = buf_len;
+ }
+ if ( kPrintDebug2 ) {
+ printf ( "/////////////////Predicted Items Begin////////////////////>>\n" );
+ for ( size_t i = 0; i < res_total; i++ ) {
+ printf ( "---" );
+ for ( size_t j = 0; j < kMaxPredictSize; j++ ) {
+ printf ( "%d ", npre_items_[i].pre_hzs[j] );
+ }
+ printf ( "\n" );
+ }
+ printf ( "<<///////////////Predicted Items End////////////////////////\n" );
+ }
+ for ( size_t i = 0; i < res_total; i++ ) {
+ utf16_strncpy ( predict_buf[i], npre_items_[i].pre_hzs,
+ kMaxPredictSize );
+ predict_buf[i][kMaxPredictSize] = '\0';
+ }
+ return res_total;
}
- res_total += res_this;
- }
-
- res_total = remove_duplicate_npre(npre_items_, res_total);
-
- if (kPreferLongHistoryPredict) {
- myqsort(npre_items_, res_total, sizeof(NPredictItem),
- cmp_npre_by_hislen_score);
- } else {
- myqsort(npre_items_, res_total, sizeof(NPredictItem),
- cmp_npre_by_score);
- }
-
- if (buf_len < res_total) {
- res_total = buf_len;
- }
-
- if (kPrintDebug2) {
- printf("/////////////////Predicted Items Begin////////////////////>>\n");
- for (size_t i = 0; i < res_total; i++) {
- printf("---");
- for (size_t j = 0; j < kMaxPredictSize; j++) {
- printf("%d ", npre_items_[i].pre_hzs[j]);
- }
- printf("\n");
+ size_t MatrixSearch::get_predicts ( const char16 fixed_buf[],
+ char16 predict_buf[][kMaxPredictSize + 1],
+ size_t buf_len ) {
+ size_t fixed_len = utf16_strlen ( fixed_buf );
+ if ( 0 == fixed_len || fixed_len > kMaxPredictSize || 0 == buf_len )
+ { return 0; }
+ return inner_predict ( fixed_buf, fixed_len, predict_buf, buf_len );
}
- printf("<<///////////////Predicted Items End////////////////////////\n");
- }
-
- for (size_t i = 0; i < res_total; i++) {
- utf16_strncpy(predict_buf[i], npre_items_[i].pre_hzs,
- kMaxPredictSize);
- predict_buf[i][kMaxPredictSize] = '\0';
- }
-
- return res_total;
-}
-
-size_t MatrixSearch::get_predicts(const char16 fixed_buf[],
- char16 predict_buf[][kMaxPredictSize + 1],
- size_t buf_len) {
- size_t fixed_len = utf16_strlen(fixed_buf);
- if (0 ==fixed_len || fixed_len > kMaxPredictSize || 0 == buf_len)
- return 0;
-
- return inner_predict(fixed_buf, fixed_len, predict_buf, buf_len);
-}
} // namespace ime_pinyin
diff --git a/jni/share/mystdlib.cpp b/jni/share/mystdlib.cpp
index 93bbcc9..86e069c 100755
--- a/jni/share/mystdlib.cpp
+++ b/jni/share/mystdlib.cpp
@@ -18,17 +18,17 @@
namespace ime_pinyin {
-// For debug purpose. You can add a fixed version of qsort and bsearch functions
-// here so that the output will be totally the same under different platforms.
+ // For debug purpose. You can add a fixed version of qsort and bsearch functions
+ // here so that the output will be totally the same under different platforms.
-void myqsort(void *p, size_t n, size_t es,
- int (*cmp)(const void *, const void *)) {
- qsort(p,n, es, cmp);
-}
+ void myqsort ( void *p, size_t n, size_t es,
+ int ( *cmp ) ( const void *, const void * ) ) {
+ qsort ( p, n, es, cmp );
+ }
-void *mybsearch(const void *k, const void *b,
- size_t n, size_t es,
- int (*cmp)(const void *, const void *)) {
- return bsearch(k, b, n, es, cmp);
-}
+ void *mybsearch ( const void *k, const void *b,
+ size_t n, size_t es,
+ int ( *cmp ) ( const void *, const void * ) ) {
+ return bsearch ( k, b, n, es, cmp );
+ }
} // namespace ime_pinyin
diff --git a/jni/share/ngram.cpp b/jni/share/ngram.cpp
index 104b853..1ccbf34 100755
--- a/jni/share/ngram.cpp
+++ b/jni/share/ngram.cpp
@@ -26,317 +26,267 @@ namespace ime_pinyin {
#define ADD_COUNT 0.3
-int comp_double(const void *p1, const void *p2) {
- if (*static_cast<const double*>(p1) < *static_cast<const double*>(p2))
- return -1;
- if (*static_cast<const double*>(p1) > *static_cast<const double*>(p2))
- return 1;
- return 0;
-}
-
-inline double distance(double freq, double code) {
- // return fabs(freq - code);
- return freq * fabs(log(freq) - log(code));
-}
-
-// Find the index of the code value which is nearest to the given freq
-int qsearch_nearest(double code_book[], double freq, int start, int end) {
- if (start == end)
- return start;
-
- if (start + 1 == end) {
- if (distance(freq, code_book[end]) > distance(freq, code_book[start]))
- return start;
- return end;
- }
-
- int mid = (start + end) / 2;
-
- if (code_book[mid] > freq)
- return qsearch_nearest(code_book, freq, start, mid);
- else
- return qsearch_nearest(code_book, freq, mid, end);
-}
-
-size_t update_code_idx(double freqs[], size_t num, double code_book[],
- CODEBOOK_TYPE *code_idx) {
- size_t changed = 0;
- for (size_t pos = 0; pos < num; pos++) {
- CODEBOOK_TYPE idx;
- idx = qsearch_nearest(code_book, freqs[pos], 0, kCodeBookSize - 1);
- if (idx != code_idx[pos])
- changed++;
- code_idx[pos] = idx;
- }
- return changed;
-}
-
-double recalculate_kernel(double freqs[], size_t num, double code_book[],
- CODEBOOK_TYPE *code_idx) {
- double ret = 0;
-
- size_t *item_num = new size_t[kCodeBookSize];
- assert(item_num);
- memset(item_num, 0, sizeof(size_t) * kCodeBookSize);
-
- double *cb_new = new double[kCodeBookSize];
- assert(cb_new);
- memset(cb_new, 0, sizeof(double) * kCodeBookSize);
-
- for (size_t pos = 0; pos < num; pos++) {
- ret += distance(freqs[pos], code_book[code_idx[pos]]);
-
- cb_new[code_idx[pos]] += freqs[pos];
- item_num[code_idx[pos]] += 1;
- }
-
- for (size_t code = 0; code < kCodeBookSize; code++) {
- assert(item_num[code] > 0);
- code_book[code] = cb_new[code] / item_num[code];
- }
-
- delete [] item_num;
- delete [] cb_new;
-
- return ret;
-}
+ int comp_double ( const void *p1, const void *p2 ) {
+ if ( *static_cast<const double *> ( p1 ) < *static_cast<const double *> ( p2 ) )
+ { return -1; }
+ if ( *static_cast<const double *> ( p1 ) > *static_cast<const double *> ( p2 ) )
+ { return 1; }
+ return 0;
+ }
-void iterate_codes(double freqs[], size_t num, double code_book[],
- CODEBOOK_TYPE *code_idx) {
- size_t iter_num = 0;
- double delta_last = 0;
- do {
- size_t changed = update_code_idx(freqs, num, code_book, code_idx);
+ inline double distance ( double freq, double code ) {
+ // return fabs(freq - code);
+ return freq * fabs ( log ( freq ) - log ( code ) );
+ }
- double delta = recalculate_kernel(freqs, num, code_book, code_idx);
+ // Find the index of the code value which is nearest to the given freq
+ int qsearch_nearest ( double code_book[], double freq, int start, int end ) {
+ if ( start == end )
+ { return start; }
+ if ( start + 1 == end ) {
+ if ( distance ( freq, code_book[end] ) > distance ( freq, code_book[start] ) )
+ { return start; }
+ return end;
+ }
+ int mid = ( start + end ) / 2;
+ if ( code_book[mid] > freq )
+ { return qsearch_nearest ( code_book, freq, start, mid ); }
+ else
+ { return qsearch_nearest ( code_book, freq, mid, end ); }
+ }
- if (kPrintDebug0) {
- printf("---Unigram codebook iteration: %d : %d, %.9f\n",
- iter_num, changed, delta);
+ size_t update_code_idx ( double freqs[], size_t num, double code_book[],
+ CODEBOOK_TYPE *code_idx ) {
+ size_t changed = 0;
+ for ( size_t pos = 0; pos < num; pos++ ) {
+ CODEBOOK_TYPE idx;
+ idx = qsearch_nearest ( code_book, freqs[pos], 0, kCodeBookSize - 1 );
+ if ( idx != code_idx[pos] )
+ { changed++; }
+ code_idx[pos] = idx;
+ }
+ return changed;
}
- iter_num++;
- if (iter_num > 1 &&
- (delta == 0 || fabs(delta_last - delta)/fabs(delta) < 0.000000001))
- break;
- delta_last = delta;
- } while (true);
-}
+ double recalculate_kernel ( double freqs[], size_t num, double code_book[],
+ CODEBOOK_TYPE *code_idx ) {
+ double ret = 0;
+ size_t *item_num = new size_t[kCodeBookSize];
+ assert ( item_num );
+ memset ( item_num, 0, sizeof ( size_t ) * kCodeBookSize );
+ double *cb_new = new double[kCodeBookSize];
+ assert ( cb_new );
+ memset ( cb_new, 0, sizeof ( double ) * kCodeBookSize );
+ for ( size_t pos = 0; pos < num; pos++ ) {
+ ret += distance ( freqs[pos], code_book[code_idx[pos]] );
+ cb_new[code_idx[pos]] += freqs[pos];
+ item_num[code_idx[pos]] += 1;
+ }
+ for ( size_t code = 0; code < kCodeBookSize; code++ ) {
+ assert ( item_num[code] > 0 );
+ code_book[code] = cb_new[code] / item_num[code];
+ }
+ delete [] item_num;
+ delete [] cb_new;
+ return ret;
+ }
+ void iterate_codes ( double freqs[], size_t num, double code_book[],
+ CODEBOOK_TYPE *code_idx ) {
+ size_t iter_num = 0;
+ double delta_last = 0;
+ do {
+ size_t changed = update_code_idx ( freqs, num, code_book, code_idx );
+ double delta = recalculate_kernel ( freqs, num, code_book, code_idx );
+ if ( kPrintDebug0 ) {
+ printf ( "---Unigram codebook iteration: %d : %d, %.9f\n",
+ iter_num, changed, delta );
+ }
+ iter_num++;
+ if ( iter_num > 1 &&
+ ( delta == 0 || fabs ( delta_last - delta ) / fabs ( delta ) < 0.000000001 ) )
+ { break; }
+ delta_last = delta;
+ } while ( true );
+ }
-NGram* NGram::instance_ = NULL;
-NGram::NGram() {
- initialized_ = false;
- idx_num_ = 0;
- lma_freq_idx_ = NULL;
- sys_score_compensation_ = 0;
+ NGram *NGram::instance_ = NULL;
+ NGram::NGram() {
+ initialized_ = false;
+ idx_num_ = 0;
+ lma_freq_idx_ = NULL;
+ sys_score_compensation_ = 0;
#ifdef ___BUILD_MODEL___
- freq_codes_df_ = NULL;
+ freq_codes_df_ = NULL;
#endif
- freq_codes_ = NULL;
-}
-
-NGram::~NGram() {
- if (NULL != lma_freq_idx_)
- free(lma_freq_idx_);
+ freq_codes_ = NULL;
+ }
+ NGram::~NGram() {
+ if ( NULL != lma_freq_idx_ )
+ { free ( lma_freq_idx_ ); }
#ifdef ___BUILD_MODEL___
- if (NULL != freq_codes_df_)
- free(freq_codes_df_);
+ if ( NULL != freq_codes_df_ )
+ { free ( freq_codes_df_ ); }
#endif
+ if ( NULL != freq_codes_ )
+ { free ( freq_codes_ ); }
+ }
- if (NULL != freq_codes_)
- free(freq_codes_);
-}
-
-NGram& NGram::get_instance() {
- if (NULL == instance_)
- instance_ = new NGram();
- return *instance_;
-}
-
-bool NGram::save_ngram(FILE *fp) {
- if (!initialized_ || NULL == fp)
- return false;
-
- if (0 == idx_num_ || NULL == freq_codes_ || NULL == lma_freq_idx_)
- return false;
-
- if (fwrite(&idx_num_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(freq_codes_, sizeof(LmaScoreType), kCodeBookSize, fp) !=
- kCodeBookSize)
- return false;
-
- if (fwrite(lma_freq_idx_, sizeof(CODEBOOK_TYPE), idx_num_, fp) != idx_num_)
- return false;
-
- return true;
-}
-
-bool NGram::load_ngram(FILE *fp) {
- if (NULL == fp)
- return false;
-
- initialized_ = false;
-
- if (fread(&idx_num_, sizeof(size_t), 1, fp) != 1 )
- return false;
-
- if (NULL != lma_freq_idx_)
- free(lma_freq_idx_);
-
- if (NULL != freq_codes_)
- free(freq_codes_);
-
- lma_freq_idx_ = static_cast<CODEBOOK_TYPE*>
- (malloc(idx_num_ * sizeof(CODEBOOK_TYPE)));
- freq_codes_ = static_cast<LmaScoreType*>
- (malloc(kCodeBookSize * sizeof(LmaScoreType)));
-
- if (NULL == lma_freq_idx_ || NULL == freq_codes_)
- return false;
-
- if (fread(freq_codes_, sizeof(LmaScoreType), kCodeBookSize, fp) !=
- kCodeBookSize)
- return false;
-
- if (fread(lma_freq_idx_, sizeof(CODEBOOK_TYPE), idx_num_, fp) != idx_num_)
- return false;
-
- initialized_ = true;
-
- total_freq_none_sys_ = 0;
- return true;
-}
-
-void NGram::set_total_freq_none_sys(size_t freq_none_sys) {
- total_freq_none_sys_ = freq_none_sys;
- if (0 == total_freq_none_sys_) {
- sys_score_compensation_ = 0;
- } else {
- double factor = static_cast<double>(kSysDictTotalFreq) / (
- kSysDictTotalFreq + total_freq_none_sys_);
- sys_score_compensation_ = static_cast<float>(
- log(factor) * kLogValueAmplifier);
- }
-}
-
-// The caller makes sure this oject is initialized.
-float NGram::get_uni_psb(LemmaIdType lma_id) {
- return static_cast<float>(freq_codes_[lma_freq_idx_[lma_id]]) +
- sys_score_compensation_;
-}
-
-float NGram::convert_psb_to_score(double psb) {
- float score = static_cast<float>(
- log(psb) * static_cast<double>(kLogValueAmplifier));
- if (score > static_cast<float>(kMaxScore)) {
- score = static_cast<float>(kMaxScore);
- }
- return score;
-}
-
-#ifdef ___BUILD_MODEL___
-bool NGram::build_unigram(LemmaEntry *lemma_arr, size_t lemma_num,
- LemmaIdType next_idx_unused) {
- if (NULL == lemma_arr || 0 == lemma_num || next_idx_unused <= 1)
- return false;
-
- double total_freq = 0;
- double *freqs = new double[next_idx_unused];
- if (NULL == freqs)
- return false;
-
- freqs[0] = ADD_COUNT;
- total_freq += freqs[0];
- LemmaIdType idx_now = 0;
- for (size_t pos = 0; pos < lemma_num; pos++) {
- if (lemma_arr[pos].idx_by_hz == idx_now)
- continue;
- idx_now++;
-
- assert(lemma_arr[pos].idx_by_hz == idx_now);
-
- freqs[idx_now] = lemma_arr[pos].freq;
- if (freqs[idx_now] <= 0)
- freqs[idx_now] = 0.3;
-
- total_freq += freqs[idx_now];
- }
-
- double max_freq = 0;
- idx_num_ = idx_now + 1;
- assert(idx_now + 1 == next_idx_unused);
-
- for (size_t pos = 0; pos < idx_num_; pos++) {
- freqs[pos] = freqs[pos] / total_freq;
- assert(freqs[pos] > 0);
- if (freqs[pos] > max_freq)
- max_freq = freqs[pos];
- }
-
- // calculate the code book
- if (NULL == freq_codes_df_)
- freq_codes_df_ = new double[kCodeBookSize];
- assert(freq_codes_df_);
- memset(freq_codes_df_, 0, sizeof(double) * kCodeBookSize);
+ NGram &NGram::get_instance() {
+ if ( NULL == instance_ )
+ { instance_ = new NGram(); }
+ return *instance_;
+ }
- if (NULL == freq_codes_)
- freq_codes_ = new LmaScoreType[kCodeBookSize];
- assert(freq_codes_);
- memset(freq_codes_, 0, sizeof(LmaScoreType) * kCodeBookSize);
+ bool NGram::save_ngram ( FILE *fp ) {
+ if ( !initialized_ || NULL == fp )
+ { return false; }
+ if ( 0 == idx_num_ || NULL == freq_codes_ || NULL == lma_freq_idx_ )
+ { return false; }
+ if ( fwrite ( &idx_num_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( freq_codes_, sizeof ( LmaScoreType ), kCodeBookSize, fp ) !=
+ kCodeBookSize )
+ { return false; }
+ if ( fwrite ( lma_freq_idx_, sizeof ( CODEBOOK_TYPE ), idx_num_, fp ) != idx_num_ )
+ { return false; }
+ return true;
+ }
- size_t freq_pos = 0;
- for (size_t code_pos = 0; code_pos < kCodeBookSize; code_pos++) {
- bool found = true;
+ bool NGram::load_ngram ( FILE *fp ) {
+ if ( NULL == fp )
+ { return false; }
+ initialized_ = false;
+ if ( fread ( &idx_num_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( NULL != lma_freq_idx_ )
+ { free ( lma_freq_idx_ ); }
+ if ( NULL != freq_codes_ )
+ { free ( freq_codes_ ); }
+ lma_freq_idx_ = static_cast<CODEBOOK_TYPE *>
+ ( malloc ( idx_num_ * sizeof ( CODEBOOK_TYPE ) ) );
+ freq_codes_ = static_cast<LmaScoreType *>
+ ( malloc ( kCodeBookSize * sizeof ( LmaScoreType ) ) );
+ if ( NULL == lma_freq_idx_ || NULL == freq_codes_ )
+ { return false; }
+ if ( fread ( freq_codes_, sizeof ( LmaScoreType ), kCodeBookSize, fp ) !=
+ kCodeBookSize )
+ { return false; }
+ if ( fread ( lma_freq_idx_, sizeof ( CODEBOOK_TYPE ), idx_num_, fp ) != idx_num_ )
+ { return false; }
+ initialized_ = true;
+ total_freq_none_sys_ = 0;
+ return true;
+ }
- while (found) {
- found = false;
- double cand = freqs[freq_pos];
- for (size_t i = 0; i < code_pos; i++)
- if (freq_codes_df_[i] == cand) {
- found = true;
- break;
+ void NGram::set_total_freq_none_sys ( size_t freq_none_sys ) {
+ total_freq_none_sys_ = freq_none_sys;
+ if ( 0 == total_freq_none_sys_ ) {
+ sys_score_compensation_ = 0;
+ } else {
+ double factor = static_cast<double> ( kSysDictTotalFreq ) / (
+ kSysDictTotalFreq + total_freq_none_sys_ );
+ sys_score_compensation_ = static_cast<float> (
+ log ( factor ) * kLogValueAmplifier );
}
- if (found)
- freq_pos++;
}
- freq_codes_df_[code_pos] = freqs[freq_pos];
- freq_pos++;
- }
-
- myqsort(freq_codes_df_, kCodeBookSize, sizeof(double), comp_double);
-
- if (NULL == lma_freq_idx_)
- lma_freq_idx_ = new CODEBOOK_TYPE[idx_num_];
- assert(lma_freq_idx_);
-
- iterate_codes(freqs, idx_num_, freq_codes_df_, lma_freq_idx_);
-
- delete [] freqs;
-
- if (kPrintDebug0) {
- printf("\n------Language Model Unigram Codebook------\n");
- }
+ // The caller makes sure this oject is initialized.
+ float NGram::get_uni_psb ( LemmaIdType lma_id ) {
+ return static_cast<float> ( freq_codes_[lma_freq_idx_[lma_id]] ) +
+ sys_score_compensation_;
+ }
- for (size_t code_pos = 0; code_pos < kCodeBookSize; code_pos++) {
- double log_score = log(freq_codes_df_[code_pos]);
- float final_score = convert_psb_to_score(freq_codes_df_[code_pos]);
- if (kPrintDebug0) {
- printf("code:%d, probability:%.9f, log score:%.3f, final score: %.3f\n",
- code_pos, freq_codes_df_[code_pos], log_score, final_score);
+ float NGram::convert_psb_to_score ( double psb ) {
+ float score = static_cast<float> (
+ log ( psb ) * static_cast<double> ( kLogValueAmplifier ) );
+ if ( score > static_cast<float> ( kMaxScore ) ) {
+ score = static_cast<float> ( kMaxScore );
+ }
+ return score;
}
- freq_codes_[code_pos] = static_cast<LmaScoreType>(final_score);
- }
- initialized_ = true;
- return true;
-}
+#ifdef ___BUILD_MODEL___
+ bool NGram::build_unigram ( LemmaEntry *lemma_arr, size_t lemma_num,
+ LemmaIdType next_idx_unused ) {
+ if ( NULL == lemma_arr || 0 == lemma_num || next_idx_unused <= 1 )
+ { return false; }
+ double total_freq = 0;
+ double *freqs = new double[next_idx_unused];
+ if ( NULL == freqs )
+ { return false; }
+ freqs[0] = ADD_COUNT;
+ total_freq += freqs[0];
+ LemmaIdType idx_now = 0;
+ for ( size_t pos = 0; pos < lemma_num; pos++ ) {
+ if ( lemma_arr[pos].idx_by_hz == idx_now )
+ { continue; }
+ idx_now++;
+ assert ( lemma_arr[pos].idx_by_hz == idx_now );
+ freqs[idx_now] = lemma_arr[pos].freq;
+ if ( freqs[idx_now] <= 0 )
+ { freqs[idx_now] = 0.3; }
+ total_freq += freqs[idx_now];
+ }
+ double max_freq = 0;
+ idx_num_ = idx_now + 1;
+ assert ( idx_now + 1 == next_idx_unused );
+ for ( size_t pos = 0; pos < idx_num_; pos++ ) {
+ freqs[pos] = freqs[pos] / total_freq;
+ assert ( freqs[pos] > 0 );
+ if ( freqs[pos] > max_freq )
+ { max_freq = freqs[pos]; }
+ }
+ // calculate the code book
+ if ( NULL == freq_codes_df_ )
+ { freq_codes_df_ = new double[kCodeBookSize]; }
+ assert ( freq_codes_df_ );
+ memset ( freq_codes_df_, 0, sizeof ( double ) * kCodeBookSize );
+ if ( NULL == freq_codes_ )
+ { freq_codes_ = new LmaScoreType[kCodeBookSize]; }
+ assert ( freq_codes_ );
+ memset ( freq_codes_, 0, sizeof ( LmaScoreType ) * kCodeBookSize );
+ size_t freq_pos = 0;
+ for ( size_t code_pos = 0; code_pos < kCodeBookSize; code_pos++ ) {
+ bool found = true;
+ while ( found ) {
+ found = false;
+ double cand = freqs[freq_pos];
+ for ( size_t i = 0; i < code_pos; i++ )
+ if ( freq_codes_df_[i] == cand ) {
+ found = true;
+ break;
+ }
+ if ( found )
+ { freq_pos++; }
+ }
+ freq_codes_df_[code_pos] = freqs[freq_pos];
+ freq_pos++;
+ }
+ myqsort ( freq_codes_df_, kCodeBookSize, sizeof ( double ), comp_double );
+ if ( NULL == lma_freq_idx_ )
+ { lma_freq_idx_ = new CODEBOOK_TYPE[idx_num_]; }
+ assert ( lma_freq_idx_ );
+ iterate_codes ( freqs, idx_num_, freq_codes_df_, lma_freq_idx_ );
+ delete [] freqs;
+ if ( kPrintDebug0 ) {
+ printf ( "\n------Language Model Unigram Codebook------\n" );
+ }
+ for ( size_t code_pos = 0; code_pos < kCodeBookSize; code_pos++ ) {
+ double log_score = log ( freq_codes_df_[code_pos] );
+ float final_score = convert_psb_to_score ( freq_codes_df_[code_pos] );
+ if ( kPrintDebug0 ) {
+ printf ( "code:%d, probability:%.9f, log score:%.3f, final score: %.3f\n",
+ code_pos, freq_codes_df_[code_pos], log_score, final_score );
+ }
+ freq_codes_[code_pos] = static_cast<LmaScoreType> ( final_score );
+ }
+ initialized_ = true;
+ return true;
+ }
#endif
} // namespace ime_pinyin
diff --git a/jni/share/pinyinime.cpp b/jni/share/pinyinime.cpp
index 550da7b..a72f3b4 100755
--- a/jni/share/pinyinime.cpp
+++ b/jni/share/pinyinime.cpp
@@ -24,162 +24,148 @@
extern "C" {
#endif
- using namespace ime_pinyin;
+ using namespace ime_pinyin;
- // The maximum number of the prediction items.
- static const size_t kMaxPredictNum = 500;
+ // The maximum number of the prediction items.
+ static const size_t kMaxPredictNum = 500;
- // Used to search Pinyin string and give the best candidate.
- MatrixSearch* matrix_search = NULL;
+ // Used to search Pinyin string and give the best candidate.
+ MatrixSearch *matrix_search = NULL;
- char16 predict_buf[kMaxPredictNum][kMaxPredictSize + 1];
+ char16 predict_buf[kMaxPredictNum][kMaxPredictSize + 1];
- bool im_open_decoder(const char *fn_sys_dict, const char *fn_usr_dict) {
- if (NULL != matrix_search)
- delete matrix_search;
-
- matrix_search = new MatrixSearch();
- if (NULL == matrix_search) {
- return false;
+ bool im_open_decoder ( const char *fn_sys_dict, const char *fn_usr_dict ) {
+ if ( NULL != matrix_search )
+ { delete matrix_search; }
+ matrix_search = new MatrixSearch();
+ if ( NULL == matrix_search ) {
+ return false;
+ }
+ return matrix_search->init ( fn_sys_dict, fn_usr_dict );
}
- return matrix_search->init(fn_sys_dict, fn_usr_dict);
- }
-
- bool im_open_decoder_fd(int sys_fd, long start_offset, long length,
- const char *fn_usr_dict) {
- if (NULL != matrix_search)
- delete matrix_search;
-
- matrix_search = new MatrixSearch();
- if (NULL == matrix_search)
- return false;
-
- return matrix_search->init_fd(sys_fd, start_offset, length, fn_usr_dict);
- }
-
- void im_close_decoder() {
- if (NULL != matrix_search) {
- matrix_search->close();
- delete matrix_search;
+ bool im_open_decoder_fd ( int sys_fd, long start_offset, long length,
+ const char *fn_usr_dict ) {
+ if ( NULL != matrix_search )
+ { delete matrix_search; }
+ matrix_search = new MatrixSearch();
+ if ( NULL == matrix_search )
+ { return false; }
+ return matrix_search->init_fd ( sys_fd, start_offset, length, fn_usr_dict );
}
- matrix_search = NULL;
- }
- void im_set_max_lens(size_t max_sps_len, size_t max_hzs_len) {
- if (NULL != matrix_search) {
- matrix_search->set_max_lens(max_sps_len, max_hzs_len);
+ void im_close_decoder() {
+ if ( NULL != matrix_search ) {
+ matrix_search->close();
+ delete matrix_search;
+ }
+ matrix_search = NULL;
}
- }
-
- void im_flush_cache() {
- if (NULL != matrix_search)
- matrix_search->flush_cache();
- }
-
- // To be updated.
- size_t im_search(const char* pybuf, size_t pylen) {
- if (NULL == matrix_search)
- return 0;
-
- matrix_search->search(pybuf, pylen);
- return matrix_search->get_candidate_num();
- }
- size_t im_delsearch(size_t pos, bool is_pos_in_splid,
- bool clear_fixed_this_step) {
- if (NULL == matrix_search)
- return 0;
- matrix_search->delsearch(pos, is_pos_in_splid, clear_fixed_this_step);
- return matrix_search->get_candidate_num();
- }
-
- void im_reset_search() {
- if (NULL == matrix_search)
- return;
-
- matrix_search->reset_search();
- }
-
- // To be removed
- size_t im_add_letter(char ch) {
- return 0;
- }
-
- const char* im_get_sps_str(size_t *decoded_len) {
- if (NULL == matrix_search)
- return NULL;
-
- return matrix_search->get_pystr(decoded_len);
- }
+ void im_set_max_lens ( size_t max_sps_len, size_t max_hzs_len ) {
+ if ( NULL != matrix_search ) {
+ matrix_search->set_max_lens ( max_sps_len, max_hzs_len );
+ }
+ }
- char16* im_get_candidate(size_t cand_id, char16* cand_str,
- size_t max_len) {
- if (NULL == matrix_search)
- return NULL;
+ void im_flush_cache() {
+ if ( NULL != matrix_search )
+ { matrix_search->flush_cache(); }
+ }
- return matrix_search->get_candidate(cand_id, cand_str, max_len);
- }
+ // To be updated.
+ size_t im_search ( const char *pybuf, size_t pylen ) {
+ if ( NULL == matrix_search )
+ { return 0; }
+ matrix_search->search ( pybuf, pylen );
+ return matrix_search->get_candidate_num();
+ }
- size_t im_get_spl_start_pos(const uint16 *&spl_start) {
- if (NULL == matrix_search)
- return 0;
+ size_t im_delsearch ( size_t pos, bool is_pos_in_splid,
+ bool clear_fixed_this_step ) {
+ if ( NULL == matrix_search )
+ { return 0; }
+ matrix_search->delsearch ( pos, is_pos_in_splid, clear_fixed_this_step );
+ return matrix_search->get_candidate_num();
+ }
- return matrix_search->get_spl_start(spl_start);
- }
+ void im_reset_search() {
+ if ( NULL == matrix_search )
+ { return; }
+ matrix_search->reset_search();
+ }
- size_t im_choose(size_t choice_id) {
- if (NULL == matrix_search)
- return 0;
+ // To be removed
+ size_t im_add_letter ( char ch ) {
+ return 0;
+ }
- return matrix_search->choose(choice_id);
- }
+ const char *im_get_sps_str ( size_t *decoded_len ) {
+ if ( NULL == matrix_search )
+ { return NULL; }
+ return matrix_search->get_pystr ( decoded_len );
+ }
- size_t im_cancel_last_choice() {
- if (NULL == matrix_search)
- return 0;
+ char16 *im_get_candidate ( size_t cand_id, char16 *cand_str,
+ size_t max_len ) {
+ if ( NULL == matrix_search )
+ { return NULL; }
+ return matrix_search->get_candidate ( cand_id, cand_str, max_len );
+ }
- return matrix_search->cancel_last_choice();
- }
+ size_t im_get_spl_start_pos ( const uint16 *&spl_start ) {
+ if ( NULL == matrix_search )
+ { return 0; }
+ return matrix_search->get_spl_start ( spl_start );
+ }
- size_t im_get_fixed_len() {
- if (NULL == matrix_search)
- return 0;
+ size_t im_choose ( size_t choice_id ) {
+ if ( NULL == matrix_search )
+ { return 0; }
+ return matrix_search->choose ( choice_id );
+ }
- return matrix_search->get_fixedlen();
- }
+ size_t im_cancel_last_choice() {
+ if ( NULL == matrix_search )
+ { return 0; }
+ return matrix_search->cancel_last_choice();
+ }
- // To be removed
- bool im_cancel_input() {
- return true;
- }
+ size_t im_get_fixed_len() {
+ if ( NULL == matrix_search )
+ { return 0; }
+ return matrix_search->get_fixedlen();
+ }
+ // To be removed
+ bool im_cancel_input() {
+ return true;
+ }
- size_t im_get_predicts(const char16 *his_buf,
- char16 (*&pre_buf)[kMaxPredictSize + 1]) {
- if (NULL == his_buf)
- return 0;
- size_t fixed_len = utf16_strlen(his_buf);
- const char16 *fixed_ptr = his_buf;
- if (fixed_len > kMaxPredictSize) {
- fixed_ptr += fixed_len - kMaxPredictSize;
- fixed_len = kMaxPredictSize;
+ size_t im_get_predicts ( const char16 *his_buf,
+ char16 ( *&pre_buf ) [kMaxPredictSize + 1] ) {
+ if ( NULL == his_buf )
+ { return 0; }
+ size_t fixed_len = utf16_strlen ( his_buf );
+ const char16 *fixed_ptr = his_buf;
+ if ( fixed_len > kMaxPredictSize ) {
+ fixed_ptr += fixed_len - kMaxPredictSize;
+ fixed_len = kMaxPredictSize;
+ }
+ pre_buf = predict_buf;
+ return matrix_search->get_predicts ( his_buf, pre_buf, kMaxPredictNum );
}
- pre_buf = predict_buf;
- return matrix_search->get_predicts(his_buf, pre_buf, kMaxPredictNum);
- }
-
- void im_enable_shm_as_szm(bool enable) {
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- spl_trie.szm_enable_shm(enable);
- }
+ void im_enable_shm_as_szm ( bool enable ) {
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ spl_trie.szm_enable_shm ( enable );
+ }
- void im_enable_ym_as_szm(bool enable) {
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- spl_trie.szm_enable_ym(enable);
- }
+ void im_enable_ym_as_szm ( bool enable ) {
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ spl_trie.szm_enable_ym ( enable );
+ }
#ifdef __cplusplus
}
diff --git a/jni/share/searchutility.cpp b/jni/share/searchutility.cpp
index 281da38..e1d46d5 100755
--- a/jni/share/searchutility.cpp
+++ b/jni/share/searchutility.cpp
@@ -20,191 +20,177 @@
namespace ime_pinyin {
-bool is_system_lemma(LemmaIdType lma_id) {
- return (0 < lma_id && lma_id <= kSysDictIdEnd);
-}
-
-bool is_user_lemma(LemmaIdType lma_id) {
- return (kUserDictIdStart <= lma_id && lma_id <= kUserDictIdEnd);
-}
-
-bool is_composing_lemma(LemmaIdType lma_id) {
- return (kLemmaIdComposing == lma_id);
-}
-
-int cmp_lpi_with_psb(const void *p1, const void *p2) {
- if ((static_cast<const LmaPsbItem*>(p1))->psb >
- (static_cast<const LmaPsbItem*>(p2))->psb)
- return 1;
- if ((static_cast<const LmaPsbItem*>(p1))->psb <
- (static_cast<const LmaPsbItem*>(p2))->psb)
- return -1;
- return 0;
-}
-
-int cmp_lpi_with_unified_psb(const void *p1, const void *p2) {
- const LmaPsbItem *item1 = static_cast<const LmaPsbItem*>(p1);
- const LmaPsbItem *item2 = static_cast<const LmaPsbItem*>(p2);
-
- // The real unified psb is psb1 / lma_len1 and psb2 * lma_len2
- // But we use psb1 * lma_len2 and psb2 * lma_len1 to get better
- // precision.
- size_t up1 = item1->psb * (item2->lma_len);
- size_t up2 = item2->psb * (item1->lma_len);
- if (up1 < up2) {
- return -1;
- }
- if (up1 > up2) {
- return 1;
- }
- return 0;
-}
-
-int cmp_lpi_with_id(const void *p1, const void *p2) {
- if ((static_cast<const LmaPsbItem*>(p1))->id <
- (static_cast<const LmaPsbItem*>(p2))->id)
- return -1;
- if ((static_cast<const LmaPsbItem*>(p1))->id >
- (static_cast<const LmaPsbItem*>(p2))->id)
- return 1;
- return 0;
-}
-
-int cmp_lpi_with_hanzi(const void *p1, const void *p2) {
- if ((static_cast<const LmaPsbItem*>(p1))->hanzi <
- (static_cast<const LmaPsbItem*>(p2))->hanzi)
- return -1;
- if ((static_cast<const LmaPsbItem*>(p1))->hanzi >
- (static_cast<const LmaPsbItem*>(p2))->hanzi)
- return 1;
-
- return 0;
-}
-
-int cmp_lpsi_with_str(const void *p1, const void *p2) {
- return utf16_strcmp((static_cast<const LmaPsbStrItem*>(p1))->str,
- (static_cast<const LmaPsbStrItem*>(p2))->str);
-}
-
-
-int cmp_hanzis_1(const void *p1, const void *p2) {
- if (*static_cast<const char16*>(p1) <
- *static_cast<const char16*>(p2))
- return -1;
-
- if (*static_cast<const char16*>(p1) >
- *static_cast<const char16*>(p2))
- return 1;
- return 0;
-}
-
-int cmp_hanzis_2(const void *p1, const void *p2) {
- return utf16_strncmp(static_cast<const char16*>(p1),
- static_cast<const char16*>(p2), 2);
-}
-
-int cmp_hanzis_3(const void *p1, const void *p2) {
- return utf16_strncmp(static_cast<const char16*>(p1),
- static_cast<const char16*>(p2), 3);
-}
-
-int cmp_hanzis_4(const void *p1, const void *p2) {
- return utf16_strncmp(static_cast<const char16*>(p1),
- static_cast<const char16*>(p2), 4);
-}
-
-int cmp_hanzis_5(const void *p1, const void *p2) {
- return utf16_strncmp(static_cast<const char16*>(p1),
- static_cast<const char16*>(p2), 5);
-}
-
-int cmp_hanzis_6(const void *p1, const void *p2) {
- return utf16_strncmp(static_cast<const char16*>(p1),
- static_cast<const char16*>(p2), 6);
-}
-
-int cmp_hanzis_7(const void *p1, const void *p2) {
- return utf16_strncmp(static_cast<const char16*>(p1),
- static_cast<const char16*>(p2), 7);
-}
-
-int cmp_hanzis_8(const void *p1, const void *p2) {
- return utf16_strncmp(static_cast<const char16*>(p1),
- static_cast<const char16*>(p2), 8);
-}
-
-int cmp_npre_by_score(const void *p1, const void *p2) {
- if ((static_cast<const NPredictItem*>(p1))->psb >
- (static_cast<const NPredictItem*>(p2))->psb)
- return 1;
-
- if ((static_cast<const NPredictItem*>(p1))->psb <
- (static_cast<const NPredictItem*>(p2))->psb)
- return -1;
-
- return 0;
-}
-
-int cmp_npre_by_hislen_score(const void *p1, const void *p2) {
- if ((static_cast<const NPredictItem*>(p1))->his_len <
- (static_cast<const NPredictItem*>(p2))->his_len)
- return 1;
-
- if ((static_cast<const NPredictItem*>(p1))->his_len >
- (static_cast<const NPredictItem*>(p2))->his_len)
- return -1;
-
- if ((static_cast<const NPredictItem*>(p1))->psb >
- (static_cast<const NPredictItem*>(p2))->psb)
- return 1;
-
- if ((static_cast<const NPredictItem*>(p1))->psb <
- (static_cast<const NPredictItem*>(p2))->psb)
- return -1;
-
- return 0;
-}
-
-int cmp_npre_by_hanzi_score(const void *p1, const void *p2) {
- int ret_v = (utf16_strncmp((static_cast<const NPredictItem*>(p1))->pre_hzs,
- (static_cast<const NPredictItem*>(p2))->pre_hzs, kMaxPredictSize));
- if (0 != ret_v)
- return ret_v;
-
- if ((static_cast<const NPredictItem*>(p1))->psb >
- (static_cast<const NPredictItem*>(p2))->psb)
- return 1;
-
- if ((static_cast<const NPredictItem*>(p1))->psb <
- (static_cast<const NPredictItem*>(p2))->psb)
- return -1;
-
- return 0;
-}
-
-size_t remove_duplicate_npre(NPredictItem *npre_items, size_t npre_num) {
- if (NULL == npre_items || 0 == npre_num)
- return 0;
-
- myqsort(npre_items, npre_num, sizeof(NPredictItem), cmp_npre_by_hanzi_score);
-
- size_t remain_num = 1; // The first one is reserved.
- for (size_t pos = 1; pos < npre_num; pos++) {
- if (utf16_strncmp(npre_items[pos].pre_hzs,
- npre_items[remain_num - 1].pre_hzs,
- kMaxPredictSize) != 0) {
- if (remain_num != pos) {
- npre_items[remain_num] = npre_items[pos];
- }
- remain_num++;
- }
- }
- return remain_num;
-}
-
-size_t align_to_size_t(size_t size) {
- size_t s = sizeof(size_t);
- return (size + s -1) / s * s;
-}
+ bool is_system_lemma ( LemmaIdType lma_id ) {
+ return ( 0 < lma_id && lma_id <= kSysDictIdEnd );
+ }
+
+ bool is_user_lemma ( LemmaIdType lma_id ) {
+ return ( kUserDictIdStart <= lma_id && lma_id <= kUserDictIdEnd );
+ }
+
+ bool is_composing_lemma ( LemmaIdType lma_id ) {
+ return ( kLemmaIdComposing == lma_id );
+ }
+
+ int cmp_lpi_with_psb ( const void *p1, const void *p2 ) {
+ if ( ( static_cast<const LmaPsbItem *> ( p1 ) )->psb >
+ ( static_cast<const LmaPsbItem *> ( p2 ) )->psb )
+ { return 1; }
+ if ( ( static_cast<const LmaPsbItem *> ( p1 ) )->psb <
+ ( static_cast<const LmaPsbItem *> ( p2 ) )->psb )
+ { return -1; }
+ return 0;
+ }
+
+ int cmp_lpi_with_unified_psb ( const void *p1, const void *p2 ) {
+ const LmaPsbItem *item1 = static_cast<const LmaPsbItem *> ( p1 );
+ const LmaPsbItem *item2 = static_cast<const LmaPsbItem *> ( p2 );
+ // The real unified psb is psb1 / lma_len1 and psb2 * lma_len2
+ // But we use psb1 * lma_len2 and psb2 * lma_len1 to get better
+ // precision.
+ size_t up1 = item1->psb * ( item2->lma_len );
+ size_t up2 = item2->psb * ( item1->lma_len );
+ if ( up1 < up2 ) {
+ return -1;
+ }
+ if ( up1 > up2 ) {
+ return 1;
+ }
+ return 0;
+ }
+
+ int cmp_lpi_with_id ( const void *p1, const void *p2 ) {
+ if ( ( static_cast<const LmaPsbItem *> ( p1 ) )->id <
+ ( static_cast<const LmaPsbItem *> ( p2 ) )->id )
+ { return -1; }
+ if ( ( static_cast<const LmaPsbItem *> ( p1 ) )->id >
+ ( static_cast<const LmaPsbItem *> ( p2 ) )->id )
+ { return 1; }
+ return 0;
+ }
+
+ int cmp_lpi_with_hanzi ( const void *p1, const void *p2 ) {
+ if ( ( static_cast<const LmaPsbItem *> ( p1 ) )->hanzi <
+ ( static_cast<const LmaPsbItem *> ( p2 ) )->hanzi )
+ { return -1; }
+ if ( ( static_cast<const LmaPsbItem *> ( p1 ) )->hanzi >
+ ( static_cast<const LmaPsbItem *> ( p2 ) )->hanzi )
+ { return 1; }
+ return 0;
+ }
+
+ int cmp_lpsi_with_str ( const void *p1, const void *p2 ) {
+ return utf16_strcmp ( ( static_cast<const LmaPsbStrItem *> ( p1 ) )->str,
+ ( static_cast<const LmaPsbStrItem *> ( p2 ) )->str );
+ }
+
+
+ int cmp_hanzis_1 ( const void *p1, const void *p2 ) {
+ if ( *static_cast<const char16 *> ( p1 ) <
+ *static_cast<const char16 *> ( p2 ) )
+ { return -1; }
+ if ( *static_cast<const char16 *> ( p1 ) >
+ *static_cast<const char16 *> ( p2 ) )
+ { return 1; }
+ return 0;
+ }
+
+ int cmp_hanzis_2 ( const void *p1, const void *p2 ) {
+ return utf16_strncmp ( static_cast<const char16 *> ( p1 ),
+ static_cast<const char16 *> ( p2 ), 2 );
+ }
+
+ int cmp_hanzis_3 ( const void *p1, const void *p2 ) {
+ return utf16_strncmp ( static_cast<const char16 *> ( p1 ),
+ static_cast<const char16 *> ( p2 ), 3 );
+ }
+
+ int cmp_hanzis_4 ( const void *p1, const void *p2 ) {
+ return utf16_strncmp ( static_cast<const char16 *> ( p1 ),
+ static_cast<const char16 *> ( p2 ), 4 );
+ }
+
+ int cmp_hanzis_5 ( const void *p1, const void *p2 ) {
+ return utf16_strncmp ( static_cast<const char16 *> ( p1 ),
+ static_cast<const char16 *> ( p2 ), 5 );
+ }
+
+ int cmp_hanzis_6 ( const void *p1, const void *p2 ) {
+ return utf16_strncmp ( static_cast<const char16 *> ( p1 ),
+ static_cast<const char16 *> ( p2 ), 6 );
+ }
+
+ int cmp_hanzis_7 ( const void *p1, const void *p2 ) {
+ return utf16_strncmp ( static_cast<const char16 *> ( p1 ),
+ static_cast<const char16 *> ( p2 ), 7 );
+ }
+
+ int cmp_hanzis_8 ( const void *p1, const void *p2 ) {
+ return utf16_strncmp ( static_cast<const char16 *> ( p1 ),
+ static_cast<const char16 *> ( p2 ), 8 );
+ }
+
+ int cmp_npre_by_score ( const void *p1, const void *p2 ) {
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->psb >
+ ( static_cast<const NPredictItem *> ( p2 ) )->psb )
+ { return 1; }
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->psb <
+ ( static_cast<const NPredictItem *> ( p2 ) )->psb )
+ { return -1; }
+ return 0;
+ }
+
+ int cmp_npre_by_hislen_score ( const void *p1, const void *p2 ) {
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->his_len <
+ ( static_cast<const NPredictItem *> ( p2 ) )->his_len )
+ { return 1; }
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->his_len >
+ ( static_cast<const NPredictItem *> ( p2 ) )->his_len )
+ { return -1; }
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->psb >
+ ( static_cast<const NPredictItem *> ( p2 ) )->psb )
+ { return 1; }
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->psb <
+ ( static_cast<const NPredictItem *> ( p2 ) )->psb )
+ { return -1; }
+ return 0;
+ }
+
+ int cmp_npre_by_hanzi_score ( const void *p1, const void *p2 ) {
+ int ret_v = ( utf16_strncmp ( ( static_cast<const NPredictItem *> ( p1 ) )->pre_hzs,
+ ( static_cast<const NPredictItem *> ( p2 ) )->pre_hzs, kMaxPredictSize ) );
+ if ( 0 != ret_v )
+ { return ret_v; }
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->psb >
+ ( static_cast<const NPredictItem *> ( p2 ) )->psb )
+ { return 1; }
+ if ( ( static_cast<const NPredictItem *> ( p1 ) )->psb <
+ ( static_cast<const NPredictItem *> ( p2 ) )->psb )
+ { return -1; }
+ return 0;
+ }
+
+ size_t remove_duplicate_npre ( NPredictItem *npre_items, size_t npre_num ) {
+ if ( NULL == npre_items || 0 == npre_num )
+ { return 0; }
+ myqsort ( npre_items, npre_num, sizeof ( NPredictItem ), cmp_npre_by_hanzi_score );
+ size_t remain_num = 1; // The first one is reserved.
+ for ( size_t pos = 1; pos < npre_num; pos++ ) {
+ if ( utf16_strncmp ( npre_items[pos].pre_hzs,
+ npre_items[remain_num - 1].pre_hzs,
+ kMaxPredictSize ) != 0 ) {
+ if ( remain_num != pos ) {
+ npre_items[remain_num] = npre_items[pos];
+ }
+ remain_num++;
+ }
+ }
+ return remain_num;
+ }
+
+ size_t align_to_size_t ( size_t size ) {
+ size_t s = sizeof ( size_t );
+ return ( size + s - 1 ) / s * s;
+ }
} // namespace ime_pinyin
diff --git a/jni/share/spellingtable.cpp b/jni/share/spellingtable.cpp
index 6005e20..29b8d3d 100755
--- a/jni/share/spellingtable.cpp
+++ b/jni/share/spellingtable.cpp
@@ -25,289 +25,243 @@ namespace ime_pinyin {
#ifdef ___BUILD_MODEL___
-const char SpellingTable::
+ const char SpellingTable::
kNotSupportList[kNotSupportNum][kMaxSpellingSize + 1] = {"HM", "HNG", "NG"};
-// "" is the biggest, so that all empty strings will be moved to the end
-// _eb mean empty is biggest
-int compare_raw_spl_eb(const void* p1, const void* p2) {
- if ('\0' == (static_cast<const RawSpelling*>(p1))->str[0])
- return 1;
-
- if ('\0' == (static_cast<const RawSpelling*>(p2))->str[0])
- return -1;
-
- return strcmp((static_cast<const RawSpelling*>(p1))->str,
- (static_cast<const RawSpelling*>(p2))->str);
-}
-
-size_t get_odd_next(size_t value) {
- size_t v_next = value;
- while (true) {
- size_t v_next_sqrt = (size_t)sqrt(v_next);
-
- bool is_odd = true;
- for (size_t v_dv = 2; v_dv < v_next_sqrt + 1; v_dv++) {
- if (v_next % v_dv == 0) {
- is_odd = false;
- break;
- }
+ // "" is the biggest, so that all empty strings will be moved to the end
+ // _eb mean empty is biggest
+ int compare_raw_spl_eb ( const void *p1, const void *p2 ) {
+ if ( '\0' == ( static_cast<const RawSpelling *> ( p1 ) )->str[0] )
+ { return 1; }
+ if ( '\0' == ( static_cast<const RawSpelling *> ( p2 ) )->str[0] )
+ { return -1; }
+ return strcmp ( ( static_cast<const RawSpelling *> ( p1 ) )->str,
+ ( static_cast<const RawSpelling *> ( p2 ) )->str );
}
- if (is_odd)
- return v_next;
-
- v_next++;
- }
-
- // never reach here
- return 0;
-}
-
-SpellingTable::SpellingTable() {
- need_score_ = false;
- raw_spellings_ = NULL;
- spelling_buf_ = NULL;
- spelling_num_ = 0;
- total_freq_ = 0;
- frozen_ = true;
-}
-
-SpellingTable::~SpellingTable() {
- free_resource();
-}
-
-size_t SpellingTable::get_hash_pos(const char* spelling_str) {
- size_t hash_pos = 0;
- for (size_t pos = 0; pos < spelling_size_; pos++) {
- if ('\0' == spelling_str[pos])
- break;
- hash_pos += (size_t)spelling_str[pos];
- }
-
- hash_pos = hash_pos % spelling_max_num_;
- return hash_pos;
-}
-
-size_t SpellingTable::hash_pos_next(size_t hash_pos) {
- hash_pos += 123;
- hash_pos = hash_pos % spelling_max_num_;
- return hash_pos;
-}
-
-void SpellingTable::free_resource() {
- if (NULL != raw_spellings_)
- delete [] raw_spellings_;
- raw_spellings_ = NULL;
-
- if (NULL != spelling_buf_)
- delete [] spelling_buf_;
- spelling_buf_ = NULL;
-}
-
-bool SpellingTable::init_table(size_t pure_spl_size, size_t spl_max_num,
- bool need_score) {
- if (pure_spl_size == 0 || spl_max_num ==0)
- return false;
-
- need_score_ = need_score;
-
- free_resource();
-
- spelling_size_ = pure_spl_size + 1;
- if (need_score)
- spelling_size_ += 1;
- spelling_max_num_ = get_odd_next(spl_max_num);
- spelling_num_ = 0;
-
- raw_spellings_ = new RawSpelling[spelling_max_num_];
- spelling_buf_ = new char[spelling_max_num_ * (spelling_size_)];
- if (NULL == raw_spellings_ || NULL == spelling_buf_) {
- free_resource();
- return false;
- }
-
- memset(raw_spellings_, 0, spelling_max_num_ * sizeof(RawSpelling));
- memset(spelling_buf_, 0, spelling_max_num_ * (spelling_size_));
- frozen_ = false;
- total_freq_ = 0;
- return true;
-}
-
-bool SpellingTable::put_spelling(const char* spelling_str, double freq) {
- if (frozen_ || NULL == spelling_str)
- return false;
-
- for (size_t pos = 0; pos < kNotSupportNum; pos++) {
- if (strcmp(spelling_str, kNotSupportList[pos]) == 0) {
- return false;
+ size_t get_odd_next ( size_t value ) {
+ size_t v_next = value;
+ while ( true ) {
+ size_t v_next_sqrt = ( size_t ) sqrt ( v_next );
+ bool is_odd = true;
+ for ( size_t v_dv = 2; v_dv < v_next_sqrt + 1; v_dv++ ) {
+ if ( v_next % v_dv == 0 ) {
+ is_odd = false;
+ break;
+ }
+ }
+ if ( is_odd )
+ { return v_next; }
+ v_next++;
+ }
+ // never reach here
+ return 0;
}
- }
-
- total_freq_ += freq;
-
- size_t hash_pos = get_hash_pos(spelling_str);
- raw_spellings_[hash_pos].str[spelling_size_ - 1] = '\0';
-
- if (strncmp(raw_spellings_[hash_pos].str, spelling_str,
- spelling_size_ - 1) == 0) {
- raw_spellings_[hash_pos].freq += freq;
- return true;
- }
-
- size_t hash_pos_ori = hash_pos;
-
- while (true) {
- if (strncmp(raw_spellings_[hash_pos].str,
- spelling_str, spelling_size_ - 1) == 0) {
- raw_spellings_[hash_pos].freq += freq;
- return true;
+ SpellingTable::SpellingTable() {
+ need_score_ = false;
+ raw_spellings_ = NULL;
+ spelling_buf_ = NULL;
+ spelling_num_ = 0;
+ total_freq_ = 0;
+ frozen_ = true;
}
- if ('\0' == raw_spellings_[hash_pos].str[0]) {
- raw_spellings_[hash_pos].freq += freq;
- strncpy(raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1);
- raw_spellings_[hash_pos].str[spelling_size_ - 1] = '\0';
- spelling_num_++;
- return true;
+ SpellingTable::~SpellingTable() {
+ free_resource();
}
- hash_pos = hash_pos_next(hash_pos);
- if (hash_pos_ori == hash_pos)
- return false;
- }
-
- // never reach here
- return false;
-}
-
-bool SpellingTable::contain(const char* spelling_str) {
- if (NULL == spelling_str || NULL == spelling_buf_ || frozen_)
- return false;
-
- size_t hash_pos = get_hash_pos(spelling_str);
-
- if ('\0' == raw_spellings_[hash_pos].str[0])
- return false;
-
- if (strncmp(raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1)
- == 0)
- return true;
-
- size_t hash_pos_ori = hash_pos;
-
- while (true) {
- hash_pos = hash_pos_next(hash_pos);
- if (hash_pos_ori == hash_pos)
- return false;
-
- if ('\0' == raw_spellings_[hash_pos].str[0])
- return false;
-
- if (strncmp(raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1)
- == 0)
- return true;
- }
-
- // never reach here
- return false;
-}
-
-const char* SpellingTable::arrange(size_t *item_size, size_t *spl_num) {
- if (NULL == raw_spellings_ || NULL == spelling_buf_ ||
- NULL == item_size || NULL == spl_num)
- return NULL;
-
- qsort(raw_spellings_, spelling_max_num_, sizeof(RawSpelling),
- compare_raw_spl_eb);
-
- // After sorting, only the first spelling_num_ items are valid.
- // Copy them to the destination buffer.
- for (size_t pos = 0; pos < spelling_num_; pos++) {
- strncpy(spelling_buf_ + pos * spelling_size_, raw_spellings_[pos].str,
- spelling_size_);
- }
-
- if (need_score_) {
- if (kPrintDebug0)
- printf("------------Spelling Possiblities--------------\n");
-
- double max_score = 0;
- double min_score = 0;
-
- // After sorting, only the first spelling_num_ items are valid.
- for (size_t pos = 0; pos < spelling_num_; pos++) {
- raw_spellings_[pos].freq /= total_freq_;
- if (need_score_) {
- if (0 == pos) {
- max_score = raw_spellings_[0].freq;
- min_score = max_score;
- } else {
- if (raw_spellings_[pos].freq > max_score)
- max_score = raw_spellings_[pos].freq;
- if (raw_spellings_[pos].freq < min_score)
- min_score = raw_spellings_[pos].freq;
+ size_t SpellingTable::get_hash_pos ( const char *spelling_str ) {
+ size_t hash_pos = 0;
+ for ( size_t pos = 0; pos < spelling_size_; pos++ ) {
+ if ( '\0' == spelling_str[pos] )
+ { break; }
+ hash_pos += ( size_t ) spelling_str[pos];
}
- }
+ hash_pos = hash_pos % spelling_max_num_;
+ return hash_pos;
}
- if (kPrintDebug0)
- printf("-----max psb: %f, min psb: %f\n", max_score, min_score);
-
- max_score = log(max_score);
- min_score = log(min_score);
-
- if (kPrintDebug0)
- printf("-----max log value: %f, min log value: %f\n",
- max_score, min_score);
-
- // The absolute value of min_score is bigger than that of max_score because
- // both of them are negative after log function.
- score_amplifier_ = 1.0 * 255 / min_score;
-
- double average_score = 0;
- for (size_t pos = 0; pos < spelling_num_; pos++) {
- double score = log(raw_spellings_[pos].freq) * score_amplifier_;
- assert(score >= 0);
+ size_t SpellingTable::hash_pos_next ( size_t hash_pos ) {
+ hash_pos += 123;
+ hash_pos = hash_pos % spelling_max_num_;
+ return hash_pos;
+ }
- average_score += score;
+ void SpellingTable::free_resource() {
+ if ( NULL != raw_spellings_ )
+ { delete [] raw_spellings_; }
+ raw_spellings_ = NULL;
+ if ( NULL != spelling_buf_ )
+ { delete [] spelling_buf_; }
+ spelling_buf_ = NULL;
+ }
- // Because of calculation precision issue, score might be a little bigger
- // than 255 after being amplified.
- if (score > 255)
- score = 255;
- char *this_spl_buf = spelling_buf_ + pos * spelling_size_;
- this_spl_buf[spelling_size_ - 1] =
- static_cast<char>((unsigned char)score);
+ bool SpellingTable::init_table ( size_t pure_spl_size, size_t spl_max_num,
+ bool need_score ) {
+ if ( pure_spl_size == 0 || spl_max_num == 0 )
+ { return false; }
+ need_score_ = need_score;
+ free_resource();
+ spelling_size_ = pure_spl_size + 1;
+ if ( need_score )
+ { spelling_size_ += 1; }
+ spelling_max_num_ = get_odd_next ( spl_max_num );
+ spelling_num_ = 0;
+ raw_spellings_ = new RawSpelling[spelling_max_num_];
+ spelling_buf_ = new char[spelling_max_num_ * ( spelling_size_ )];
+ if ( NULL == raw_spellings_ || NULL == spelling_buf_ ) {
+ free_resource();
+ return false;
+ }
+ memset ( raw_spellings_, 0, spelling_max_num_ * sizeof ( RawSpelling ) );
+ memset ( spelling_buf_, 0, spelling_max_num_ * ( spelling_size_ ) );
+ frozen_ = false;
+ total_freq_ = 0;
+ return true;
+ }
- if (kPrintDebug0) {
- printf("---pos:%d, %s, psb:%d\n", pos, this_spl_buf,
- (unsigned char)this_spl_buf[spelling_size_ -1]);
- }
+ bool SpellingTable::put_spelling ( const char *spelling_str, double freq ) {
+ if ( frozen_ || NULL == spelling_str )
+ { return false; }
+ for ( size_t pos = 0; pos < kNotSupportNum; pos++ ) {
+ if ( strcmp ( spelling_str, kNotSupportList[pos] ) == 0 ) {
+ return false;
+ }
+ }
+ total_freq_ += freq;
+ size_t hash_pos = get_hash_pos ( spelling_str );
+ raw_spellings_[hash_pos].str[spelling_size_ - 1] = '\0';
+ if ( strncmp ( raw_spellings_[hash_pos].str, spelling_str,
+ spelling_size_ - 1 ) == 0 ) {
+ raw_spellings_[hash_pos].freq += freq;
+ return true;
+ }
+ size_t hash_pos_ori = hash_pos;
+ while ( true ) {
+ if ( strncmp ( raw_spellings_[hash_pos].str,
+ spelling_str, spelling_size_ - 1 ) == 0 ) {
+ raw_spellings_[hash_pos].freq += freq;
+ return true;
+ }
+ if ( '\0' == raw_spellings_[hash_pos].str[0] ) {
+ raw_spellings_[hash_pos].freq += freq;
+ strncpy ( raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1 );
+ raw_spellings_[hash_pos].str[spelling_size_ - 1] = '\0';
+ spelling_num_++;
+ return true;
+ }
+ hash_pos = hash_pos_next ( hash_pos );
+ if ( hash_pos_ori == hash_pos )
+ { return false; }
+ }
+ // never reach here
+ return false;
}
- average_score /= spelling_num_;
- assert(average_score <= 255);
- average_score_ = static_cast<uint8>(average_score);
- if (kPrintDebug0)
- printf("\n----Score Amplifier: %f, Average Score: %d\n", score_amplifier_,
- average_score_);
- }
+ bool SpellingTable::contain ( const char *spelling_str ) {
+ if ( NULL == spelling_str || NULL == spelling_buf_ || frozen_ )
+ { return false; }
+ size_t hash_pos = get_hash_pos ( spelling_str );
+ if ( '\0' == raw_spellings_[hash_pos].str[0] )
+ { return false; }
+ if ( strncmp ( raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1 )
+ == 0 )
+ { return true; }
+ size_t hash_pos_ori = hash_pos;
+ while ( true ) {
+ hash_pos = hash_pos_next ( hash_pos );
+ if ( hash_pos_ori == hash_pos )
+ { return false; }
+ if ( '\0' == raw_spellings_[hash_pos].str[0] )
+ { return false; }
+ if ( strncmp ( raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1 )
+ == 0 )
+ { return true; }
+ }
+ // never reach here
+ return false;
+ }
- *item_size = spelling_size_;
- *spl_num = spelling_num_;
- frozen_ = true;
- return spelling_buf_;
-}
+ const char *SpellingTable::arrange ( size_t *item_size, size_t *spl_num ) {
+ if ( NULL == raw_spellings_ || NULL == spelling_buf_ ||
+ NULL == item_size || NULL == spl_num )
+ { return NULL; }
+ qsort ( raw_spellings_, spelling_max_num_, sizeof ( RawSpelling ),
+ compare_raw_spl_eb );
+ // After sorting, only the first spelling_num_ items are valid.
+ // Copy them to the destination buffer.
+ for ( size_t pos = 0; pos < spelling_num_; pos++ ) {
+ strncpy ( spelling_buf_ + pos * spelling_size_, raw_spellings_[pos].str,
+ spelling_size_ );
+ }
+ if ( need_score_ ) {
+ if ( kPrintDebug0 )
+ { printf ( "------------Spelling Possiblities--------------\n" ); }
+ double max_score = 0;
+ double min_score = 0;
+ // After sorting, only the first spelling_num_ items are valid.
+ for ( size_t pos = 0; pos < spelling_num_; pos++ ) {
+ raw_spellings_[pos].freq /= total_freq_;
+ if ( need_score_ ) {
+ if ( 0 == pos ) {
+ max_score = raw_spellings_[0].freq;
+ min_score = max_score;
+ } else {
+ if ( raw_spellings_[pos].freq > max_score )
+ { max_score = raw_spellings_[pos].freq; }
+ if ( raw_spellings_[pos].freq < min_score )
+ { min_score = raw_spellings_[pos].freq; }
+ }
+ }
+ }
+ if ( kPrintDebug0 )
+ { printf ( "-----max psb: %f, min psb: %f\n", max_score, min_score ); }
+ max_score = log ( max_score );
+ min_score = log ( min_score );
+ if ( kPrintDebug0 )
+ printf ( "-----max log value: %f, min log value: %f\n",
+ max_score, min_score );
+ // The absolute value of min_score is bigger than that of max_score because
+ // both of them are negative after log function.
+ score_amplifier_ = 1.0 * 255 / min_score;
+ double average_score = 0;
+ for ( size_t pos = 0; pos < spelling_num_; pos++ ) {
+ double score = log ( raw_spellings_[pos].freq ) * score_amplifier_;
+ assert ( score >= 0 );
+ average_score += score;
+ // Because of calculation precision issue, score might be a little bigger
+ // than 255 after being amplified.
+ if ( score > 255 )
+ { score = 255; }
+ char *this_spl_buf = spelling_buf_ + pos * spelling_size_;
+ this_spl_buf[spelling_size_ - 1] =
+ static_cast<char> ( ( unsigned char ) score );
+ if ( kPrintDebug0 ) {
+ printf ( "---pos:%d, %s, psb:%d\n", pos, this_spl_buf,
+ ( unsigned char ) this_spl_buf[spelling_size_ - 1] );
+ }
+ }
+ average_score /= spelling_num_;
+ assert ( average_score <= 255 );
+ average_score_ = static_cast<uint8> ( average_score );
+ if ( kPrintDebug0 )
+ printf ( "\n----Score Amplifier: %f, Average Score: %d\n", score_amplifier_,
+ average_score_ );
+ }
+ *item_size = spelling_size_;
+ *spl_num = spelling_num_;
+ frozen_ = true;
+ return spelling_buf_;
+ }
-float SpellingTable::get_score_amplifier() {
- return static_cast<float>(score_amplifier_);
-}
+ float SpellingTable::get_score_amplifier() {
+ return static_cast<float> ( score_amplifier_ );
+ }
-unsigned char SpellingTable::get_average_score() {
- return average_score_;
-}
+ unsigned char SpellingTable::get_average_score() {
+ return average_score_;
+ }
#endif // ___BUILD_MODEL___
} // namespace ime_pinyin
diff --git a/jni/share/spellingtrie.cpp b/jni/share/spellingtrie.cpp
index 85be46b..97bdd2c 100755
--- a/jni/share/spellingtrie.cpp
+++ b/jni/share/spellingtrie.cpp
@@ -27,802 +27,695 @@
namespace ime_pinyin {
-SpellingTrie* SpellingTrie::instance_ = NULL;
-
-// z/c/s is for Zh/Ch/Sh
-const char SpellingTrie::kHalfId2Sc_[kFullSplIdStart + 1] =
- "0ABCcDEFGHIJKLMNOPQRSsTUVWXYZz";
-
-// Bit 0 : is it a Shengmu char?
-// Bit 1 : is it a Yunmu char? (one char is a Yunmu)
-// Bit 2 : is it enabled in ShouZiMu(first char) mode?
-unsigned char SpellingTrie::char_flags_[] = {
- // a b c d e f g
- 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
- // h i j k l m n
- 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
- // o p q r s t
- 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
- // u v w x y z
- 0x00, 0x00, 0x01, 0x01, 0x01, 0x01
-};
-
-int compare_spl(const void* p1, const void* p2) {
- return strcmp((const char*)(p1), (const char*)(p2));
-}
-
-SpellingTrie::SpellingTrie() {
- spelling_buf_ = NULL;
- spelling_size_ = 0;
- spelling_num_ = 0;
- spl_ym_ids_ = NULL;
- splstr_queried_ = NULL;
- splstr16_queried_ = NULL;
- root_ = NULL;
- dumb_node_ = NULL;
- splitter_node_ = NULL;
- instance_ = NULL;
- ym_buf_ = NULL;
- f2h_ = NULL;
-
- szm_enable_shm(true);
- szm_enable_ym(true);
+ SpellingTrie *SpellingTrie::instance_ = NULL;
+
+ // z/c/s is for Zh/Ch/Sh
+ const char SpellingTrie::kHalfId2Sc_[kFullSplIdStart + 1] =
+ "0ABCcDEFGHIJKLMNOPQRSsTUVWXYZz";
+
+ // Bit 0 : is it a Shengmu char?
+ // Bit 1 : is it a Yunmu char? (one char is a Yunmu)
+ // Bit 2 : is it enabled in ShouZiMu(first char) mode?
+ unsigned char SpellingTrie::char_flags_[] = {
+ // a b c d e f g
+ 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
+ // h i j k l m n
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
+ // o p q r s t
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
+ // u v w x y z
+ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01
+ };
+
+ int compare_spl ( const void *p1, const void *p2 ) {
+ return strcmp ( ( const char * ) ( p1 ), ( const char * ) ( p2 ) );
+ }
+ SpellingTrie::SpellingTrie() {
+ spelling_buf_ = NULL;
+ spelling_size_ = 0;
+ spelling_num_ = 0;
+ spl_ym_ids_ = NULL;
+ splstr_queried_ = NULL;
+ splstr16_queried_ = NULL;
+ root_ = NULL;
+ dumb_node_ = NULL;
+ splitter_node_ = NULL;
+ instance_ = NULL;
+ ym_buf_ = NULL;
+ f2h_ = NULL;
+ szm_enable_shm ( true );
+ szm_enable_ym ( true );
#ifdef ___BUILD_MODEL___
- node_num_ = 0;
+ node_num_ = 0;
#endif
-}
-
-SpellingTrie::~SpellingTrie() {
- if (NULL != spelling_buf_)
- delete [] spelling_buf_;
-
- if (NULL != splstr_queried_)
- delete [] splstr_queried_;
-
- if (NULL != splstr16_queried_)
- delete [] splstr16_queried_;
-
- if (NULL != spl_ym_ids_)
- delete [] spl_ym_ids_;
-
- if (NULL != root_) {
- free_son_trie(root_);
- delete root_;
- }
-
- if (NULL != dumb_node_) {
- delete [] dumb_node_;
- }
-
- if (NULL != splitter_node_) {
- delete [] splitter_node_;
- }
-
- if (NULL != instance_) {
- delete instance_;
- instance_ = NULL;
- }
-
- if (NULL != ym_buf_)
- delete [] ym_buf_;
-
- if (NULL != f2h_)
- delete [] f2h_;
-}
-
-bool SpellingTrie::if_valid_id_update(uint16 *splid) const {
- if (NULL == splid || 0 == *splid)
- return false;
-
- if (*splid >= kFullSplIdStart)
- return true;
- if (*splid < kFullSplIdStart) {
- char ch = kHalfId2Sc_[*splid];
- if (ch > 'Z') {
- return true;
- } else {
- if (szm_is_enabled(ch)) {
- return true;
- } else if (is_yunmu_char(ch)) {
- assert(h2f_num_[*splid] > 0);
- *splid = h2f_start_[*splid];
+ }
+
+ SpellingTrie::~SpellingTrie() {
+ if ( NULL != spelling_buf_ )
+ { delete [] spelling_buf_; }
+ if ( NULL != splstr_queried_ )
+ { delete [] splstr_queried_; }
+ if ( NULL != splstr16_queried_ )
+ { delete [] splstr16_queried_; }
+ if ( NULL != spl_ym_ids_ )
+ { delete [] spl_ym_ids_; }
+ if ( NULL != root_ ) {
+ free_son_trie ( root_ );
+ delete root_;
+ }
+ if ( NULL != dumb_node_ ) {
+ delete [] dumb_node_;
+ }
+ if ( NULL != splitter_node_ ) {
+ delete [] splitter_node_;
+ }
+ if ( NULL != instance_ ) {
+ delete instance_;
+ instance_ = NULL;
+ }
+ if ( NULL != ym_buf_ )
+ { delete [] ym_buf_; }
+ if ( NULL != f2h_ )
+ { delete [] f2h_; }
+ }
+
+ bool SpellingTrie::if_valid_id_update ( uint16 *splid ) const {
+ if ( NULL == splid || 0 == *splid )
+ { return false; }
+ if ( *splid >= kFullSplIdStart )
+ { return true; }
+ if ( *splid < kFullSplIdStart ) {
+ char ch = kHalfId2Sc_[*splid];
+ if ( ch > 'Z' ) {
+ return true;
+ } else {
+ if ( szm_is_enabled ( ch ) ) {
+ return true;
+ } else if ( is_yunmu_char ( ch ) ) {
+ assert ( h2f_num_[*splid] > 0 );
+ *splid = h2f_start_[*splid];
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool SpellingTrie::is_half_id ( uint16 splid ) const {
+ if ( 0 == splid || splid >= kFullSplIdStart )
+ { return false; }
return true;
- }
- }
- }
- return false;
-}
-
-bool SpellingTrie::is_half_id(uint16 splid) const {
- if (0 == splid || splid >= kFullSplIdStart)
- return false;
-
- return true;
-}
-
-bool SpellingTrie::is_full_id(uint16 splid) const {
- if (splid < kFullSplIdStart || splid >= kFullSplIdStart + spelling_num_)
- return false;
- return true;
-}
-
-bool SpellingTrie::half_full_compatible(uint16 half_id, uint16 full_id) const {
- uint16 half_fr_full = full_to_half(full_id);
-
- if (half_fr_full == half_id)
- return true;
-
- // &~0x20 is used to conver the char to upper case.
- // So that Zh/Ch/Sh(whose char is z/c/s) can be matched with Z/C/S.
- char ch_f = (kHalfId2Sc_[half_fr_full] & (~0x20));
- char ch_h = kHalfId2Sc_[half_id];
- if (ch_f == ch_h)
- return true;
-
- return false;
-}
-
-bool SpellingTrie::is_half_id_yunmu(uint16 splid) const {
- if (0 == splid || splid >= kFullSplIdStart)
- return false;
-
- char ch = kHalfId2Sc_[splid];
- // If ch >= 'a', that means the half id is one of Zh/Ch/Sh
- if (ch >= 'a') {
- return false;
- }
-
- return char_flags_[ch - 'A'] & kHalfIdYunmuMask;
-}
-
-bool SpellingTrie::is_shengmu_char(char ch) const {
- return char_flags_[ch - 'A'] & kHalfIdShengmuMask;
-}
-
-bool SpellingTrie::is_yunmu_char(char ch) const {
- return char_flags_[ch - 'A'] & kHalfIdYunmuMask;
-}
-
-bool SpellingTrie::is_szm_char(char ch) const {
- return is_shengmu_char(ch) || is_yunmu_char(ch);
-}
-
-bool SpellingTrie::szm_is_enabled(char ch) const {
- return char_flags_[ch - 'A'] & kHalfIdSzmMask;
-}
-
-void SpellingTrie::szm_enable_shm(bool enable) {
- if (enable) {
- for (char ch = 'A'; ch <= 'Z'; ch++) {
- if (is_shengmu_char(ch))
- char_flags_[ch - 'A'] = char_flags_[ch - 'A'] | kHalfIdSzmMask;
- }
- } else {
- for (char ch = 'A'; ch <= 'Z'; ch++) {
- if (is_shengmu_char(ch))
- char_flags_[ch - 'A'] = char_flags_[ch - 'A'] & (kHalfIdSzmMask ^ 0xff);
- }
- }
-}
-
-void SpellingTrie::szm_enable_ym(bool enable) {
- if (enable) {
- for (char ch = 'A'; ch <= 'Z'; ch++) {
- if (is_yunmu_char(ch))
- char_flags_[ch - 'A'] = char_flags_[ch - 'A'] | kHalfIdSzmMask;
- }
- } else {
- for (char ch = 'A'; ch <= 'Z'; ch++) {
- if (is_yunmu_char(ch))
- char_flags_[ch - 'A'] = char_flags_[ch - 'A'] & (kHalfIdSzmMask ^ 0xff);
- }
- }
-}
-
-bool SpellingTrie::is_szm_enabled(char ch) const {
- return char_flags_[ch - 'A'] & kHalfIdSzmMask;
-}
-
-const SpellingTrie* SpellingTrie::get_cpinstance() {
- return &get_instance();
-}
-
-SpellingTrie& SpellingTrie::get_instance() {
- if (NULL == instance_)
- instance_ = new SpellingTrie();
-
- return *instance_;
-}
-
-uint16 SpellingTrie::half2full_num(uint16 half_id) const {
- if (NULL == root_ || half_id >= kFullSplIdStart)
- return 0;
- return h2f_num_[half_id];
-}
-
-uint16 SpellingTrie::half_to_full(uint16 half_id, uint16 *spl_id_start) const {
- if (NULL == spl_id_start || NULL == root_ || half_id >= kFullSplIdStart)
- return 0;
-
- *spl_id_start = h2f_start_[half_id];
- return h2f_num_[half_id];
-}
-
-uint16 SpellingTrie::full_to_half(uint16 full_id) const {
- if (NULL == root_ || full_id < kFullSplIdStart ||
- full_id > spelling_num_ + kFullSplIdStart)
- return 0;
-
- return f2h_[full_id - kFullSplIdStart];
-}
-
-void SpellingTrie::free_son_trie(SpellingNode* node) {
- if (NULL == node)
- return;
-
- for (size_t pos = 0; pos < node->num_of_son; pos++) {
- free_son_trie(node->first_son + pos);
- }
-
- if (NULL != node->first_son)
- delete [] node->first_son;
-}
-
-bool SpellingTrie::construct(const char* spelling_arr, size_t item_size,
- size_t item_num, float score_amplifier,
- unsigned char average_score) {
- if (spelling_arr == NULL)
- return false;
-
- memset(h2f_start_, 0, sizeof(uint16) * kFullSplIdStart);
- memset(h2f_num_, 0, sizeof(uint16) * kFullSplIdStart);
-
- // If the arr is the same as the buf, means this function is called by
- // load_table(), the table data are ready; otherwise the array should be
- // saved.
- if (spelling_arr != spelling_buf_) {
- if (NULL != spelling_buf_)
- delete [] spelling_buf_;
- spelling_buf_ = new char[item_size * item_num];
- if (NULL == spelling_buf_)
- return false;
- memcpy(spelling_buf_, spelling_arr, sizeof(char) * item_size * item_num);
- }
-
- spelling_size_ = item_size;
- spelling_num_ = item_num;
-
- score_amplifier_ = score_amplifier;
- average_score_ = average_score;
-
- if (NULL != splstr_queried_)
- delete [] splstr_queried_;
- splstr_queried_ = new char[spelling_size_];
- if (NULL == splstr_queried_)
- return false;
-
- if (NULL != splstr16_queried_)
- delete [] splstr16_queried_;
- splstr16_queried_ = new char16[spelling_size_];
- if (NULL == splstr16_queried_)
- return false;
-
- // First, sort the buf to ensure they are in ascendant order
- qsort(spelling_buf_, spelling_num_, spelling_size_, compare_spl);
+ }
-#ifdef ___BUILD_MODEL___
- node_num_ = 1;
-#endif
+ bool SpellingTrie::is_full_id ( uint16 splid ) const {
+ if ( splid < kFullSplIdStart || splid >= kFullSplIdStart + spelling_num_ )
+ { return false; }
+ return true;
+ }
- root_ = new SpellingNode();
- memset(root_, 0, sizeof(SpellingNode));
+ bool SpellingTrie::half_full_compatible ( uint16 half_id, uint16 full_id ) const {
+ uint16 half_fr_full = full_to_half ( full_id );
+ if ( half_fr_full == half_id )
+ { return true; }
+ // &~0x20 is used to conver the char to upper case.
+ // So that Zh/Ch/Sh(whose char is z/c/s) can be matched with Z/C/S.
+ char ch_f = ( kHalfId2Sc_[half_fr_full] & ( ~0x20 ) );
+ char ch_h = kHalfId2Sc_[half_id];
+ if ( ch_f == ch_h )
+ { return true; }
+ return false;
+ }
- dumb_node_ = new SpellingNode();
- memset(dumb_node_, 0, sizeof(SpellingNode));
- dumb_node_->score = average_score_;
+ bool SpellingTrie::is_half_id_yunmu ( uint16 splid ) const {
+ if ( 0 == splid || splid >= kFullSplIdStart )
+ { return false; }
+ char ch = kHalfId2Sc_[splid];
+ // If ch >= 'a', that means the half id is one of Zh/Ch/Sh
+ if ( ch >= 'a' ) {
+ return false;
+ }
+ return char_flags_[ch - 'A'] & kHalfIdYunmuMask;
+ }
- splitter_node_ = new SpellingNode();
- memset(splitter_node_, 0, sizeof(SpellingNode));
- splitter_node_->score = average_score_;
+ bool SpellingTrie::is_shengmu_char ( char ch ) const {
+ return char_flags_[ch - 'A'] & kHalfIdShengmuMask;
+ }
- memset(level1_sons_, 0, sizeof(SpellingNode*) * kValidSplCharNum);
+ bool SpellingTrie::is_yunmu_char ( char ch ) const {
+ return char_flags_[ch - 'A'] & kHalfIdYunmuMask;
+ }
- root_->first_son = construct_spellings_subset(0, spelling_num_, 0, root_);
+ bool SpellingTrie::is_szm_char ( char ch ) const {
+ return is_shengmu_char ( ch ) || is_yunmu_char ( ch );
+ }
- // Root's score should be cleared.
- root_->score = 0;
+ bool SpellingTrie::szm_is_enabled ( char ch ) const {
+ return char_flags_[ch - 'A'] & kHalfIdSzmMask;
+ }
- if (NULL == root_->first_son)
- return false;
+ void SpellingTrie::szm_enable_shm ( bool enable ) {
+ if ( enable ) {
+ for ( char ch = 'A'; ch <= 'Z'; ch++ ) {
+ if ( is_shengmu_char ( ch ) )
+ { char_flags_[ch - 'A'] = char_flags_[ch - 'A'] | kHalfIdSzmMask; }
+ }
+ } else {
+ for ( char ch = 'A'; ch <= 'Z'; ch++ ) {
+ if ( is_shengmu_char ( ch ) )
+ { char_flags_[ch - 'A'] = char_flags_[ch - 'A'] & ( kHalfIdSzmMask ^ 0xff ); }
+ }
+ }
+ }
- h2f_start_[0] = h2f_num_[0] = 0;
+ void SpellingTrie::szm_enable_ym ( bool enable ) {
+ if ( enable ) {
+ for ( char ch = 'A'; ch <= 'Z'; ch++ ) {
+ if ( is_yunmu_char ( ch ) )
+ { char_flags_[ch - 'A'] = char_flags_[ch - 'A'] | kHalfIdSzmMask; }
+ }
+ } else {
+ for ( char ch = 'A'; ch <= 'Z'; ch++ ) {
+ if ( is_yunmu_char ( ch ) )
+ { char_flags_[ch - 'A'] = char_flags_[ch - 'A'] & ( kHalfIdSzmMask ^ 0xff ); }
+ }
+ }
+ }
- if (!build_f2h())
- return false;
+ bool SpellingTrie::is_szm_enabled ( char ch ) const {
+ return char_flags_[ch - 'A'] & kHalfIdSzmMask;
+ }
-#ifdef ___BUILD_MODEL___
- if (kPrintDebug0) {
- printf("---SpellingTrie Nodes: %d\n", node_num_);
- }
- return build_ym_info();
-#else
- return true;
-#endif
-}
+ const SpellingTrie *SpellingTrie::get_cpinstance() {
+ return &get_instance();
+ }
-#ifdef ___BUILD_MODEL___
-const char* SpellingTrie::get_ym_str(const char *spl_str) {
- bool start_ZCS = false;
- if (is_shengmu_char(*spl_str)) {
- if ('Z' == *spl_str || 'C' == *spl_str || 'S' == *spl_str)
- start_ZCS = true;
- spl_str += 1;
- if (start_ZCS && 'h' == *spl_str)
- spl_str += 1;
- }
- return spl_str;
-}
-
-bool SpellingTrie::build_ym_info() {
- bool sucess;
- SpellingTable *spl_table = new SpellingTable();
-
- sucess = spl_table->init_table(kMaxPinyinSize - 1, 2 * kMaxYmNum, false);
- assert(sucess);
-
- for (uint16 pos = 0; pos < spelling_num_; pos++) {
- const char *spl_str = spelling_buf_ + spelling_size_ * pos;
- spl_str = get_ym_str(spl_str);
- if ('\0' != spl_str[0]) {
- sucess = spl_table->put_spelling(spl_str, 0);
- assert(sucess);
- }
- }
-
- size_t ym_item_size; // '\0' is included
- size_t ym_num;
- const char* ym_buf;
- ym_buf = spl_table->arrange(&ym_item_size, &ym_num);
-
- if (NULL != ym_buf_)
- delete [] ym_buf_;
- ym_buf_ = new char[ym_item_size * ym_num];
- if (NULL == ym_buf_) {
- delete spl_table;
- return false;
- }
-
- memcpy(ym_buf_, ym_buf, sizeof(char) * ym_item_size * ym_num);
- ym_size_ = ym_item_size;
- ym_num_ = ym_num;
-
- delete spl_table;
-
- // Generate the maping from the spelling ids to the Yunmu ids.
- if (spl_ym_ids_)
- delete spl_ym_ids_;
- spl_ym_ids_ = new uint8[spelling_num_ + kFullSplIdStart];
- if (NULL == spl_ym_ids_)
- return false;
-
- memset(spl_ym_ids_, 0, sizeof(uint8) * (spelling_num_ + kFullSplIdStart));
-
- for (uint16 id = 1; id < spelling_num_ + kFullSplIdStart; id++) {
- const char *str = get_spelling_str(id);
-
- str = get_ym_str(str);
- if ('\0' != str[0]) {
- uint8 ym_id = get_ym_id(str);
- spl_ym_ids_[id] = ym_id;
- assert(ym_id > 0);
- } else {
- spl_ym_ids_[id] = 0;
- }
- }
- return true;
-}
-#endif
+ SpellingTrie &SpellingTrie::get_instance() {
+ if ( NULL == instance_ )
+ { instance_ = new SpellingTrie(); }
+ return *instance_;
+ }
-SpellingNode* SpellingTrie::construct_spellings_subset(
- size_t item_start, size_t item_end, size_t level, SpellingNode* parent) {
- if (level >= spelling_size_ || item_end <= item_start || NULL == parent)
- return NULL;
+ uint16 SpellingTrie::half2full_num ( uint16 half_id ) const {
+ if ( NULL == root_ || half_id >= kFullSplIdStart )
+ { return 0; }
+ return h2f_num_[half_id];
+ }
- SpellingNode *first_son = NULL;
- uint16 num_of_son = 0;
- unsigned char min_son_score = 255;
+ uint16 SpellingTrie::half_to_full ( uint16 half_id, uint16 *spl_id_start ) const {
+ if ( NULL == spl_id_start || NULL == root_ || half_id >= kFullSplIdStart )
+ { return 0; }
+ *spl_id_start = h2f_start_[half_id];
+ return h2f_num_[half_id];
+ }
- const char *spelling_last_start = spelling_buf_ + spelling_size_ * item_start;
- char char_for_node = spelling_last_start[level];
- assert(char_for_node >= 'A' && char_for_node <= 'Z' ||
- 'h' == char_for_node);
+ uint16 SpellingTrie::full_to_half ( uint16 full_id ) const {
+ if ( NULL == root_ || full_id < kFullSplIdStart ||
+ full_id > spelling_num_ + kFullSplIdStart )
+ { return 0; }
+ return f2h_[full_id - kFullSplIdStart];
+ }
- // Scan the array to find how many sons
- for (size_t i = item_start + 1; i < item_end; i++) {
- const char *spelling_current = spelling_buf_ + spelling_size_ * i;
- char char_current = spelling_current[level];
- if (char_current != char_for_node) {
- num_of_son++;
- char_for_node = char_current;
+ void SpellingTrie::free_son_trie ( SpellingNode *node ) {
+ if ( NULL == node )
+ { return; }
+ for ( size_t pos = 0; pos < node->num_of_son; pos++ ) {
+ free_son_trie ( node->first_son + pos );
+ }
+ if ( NULL != node->first_son )
+ { delete [] node->first_son; }
}
- }
- num_of_son++;
- // Allocate memory
+ bool SpellingTrie::construct ( const char *spelling_arr, size_t item_size,
+ size_t item_num, float score_amplifier,
+ unsigned char average_score ) {
+ if ( spelling_arr == NULL )
+ { return false; }
+ memset ( h2f_start_, 0, sizeof ( uint16 ) * kFullSplIdStart );
+ memset ( h2f_num_, 0, sizeof ( uint16 ) * kFullSplIdStart );
+ // If the arr is the same as the buf, means this function is called by
+ // load_table(), the table data are ready; otherwise the array should be
+ // saved.
+ if ( spelling_arr != spelling_buf_ ) {
+ if ( NULL != spelling_buf_ )
+ { delete [] spelling_buf_; }
+ spelling_buf_ = new char[item_size * item_num];
+ if ( NULL == spelling_buf_ )
+ { return false; }
+ memcpy ( spelling_buf_, spelling_arr, sizeof ( char ) * item_size * item_num );
+ }
+ spelling_size_ = item_size;
+ spelling_num_ = item_num;
+ score_amplifier_ = score_amplifier;
+ average_score_ = average_score;
+ if ( NULL != splstr_queried_ )
+ { delete [] splstr_queried_; }
+ splstr_queried_ = new char[spelling_size_];
+ if ( NULL == splstr_queried_ )
+ { return false; }
+ if ( NULL != splstr16_queried_ )
+ { delete [] splstr16_queried_; }
+ splstr16_queried_ = new char16[spelling_size_];
+ if ( NULL == splstr16_queried_ )
+ { return false; }
+ // First, sort the buf to ensure they are in ascendant order
+ qsort ( spelling_buf_, spelling_num_, spelling_size_, compare_spl );
#ifdef ___BUILD_MODEL___
- node_num_ += num_of_son;
+ node_num_ = 1;
#endif
- first_son = new SpellingNode[num_of_son];
- memset(first_son, 0, sizeof(SpellingNode)*num_of_son);
-
- // Now begin construct tree
- size_t son_pos = 0;
+ root_ = new SpellingNode();
+ memset ( root_, 0, sizeof ( SpellingNode ) );
+ dumb_node_ = new SpellingNode();
+ memset ( dumb_node_, 0, sizeof ( SpellingNode ) );
+ dumb_node_->score = average_score_;
+ splitter_node_ = new SpellingNode();
+ memset ( splitter_node_, 0, sizeof ( SpellingNode ) );
+ splitter_node_->score = average_score_;
+ memset ( level1_sons_, 0, sizeof ( SpellingNode * ) * kValidSplCharNum );
+ root_->first_son = construct_spellings_subset ( 0, spelling_num_, 0, root_ );
+ // Root's score should be cleared.
+ root_->score = 0;
+ if ( NULL == root_->first_son )
+ { return false; }
+ h2f_start_[0] = h2f_num_[0] = 0;
+ if ( !build_f2h() )
+ { return false; }
+#ifdef ___BUILD_MODEL___
+ if ( kPrintDebug0 ) {
+ printf ( "---SpellingTrie Nodes: %d\n", node_num_ );
+ }
+ return build_ym_info();
+#else
+ return true;
+#endif
+ }
- spelling_last_start = spelling_buf_ + spelling_size_ * item_start;
- char_for_node = spelling_last_start[level];
+#ifdef ___BUILD_MODEL___
+ const char *SpellingTrie::get_ym_str ( const char *spl_str ) {
+ bool start_ZCS = false;
+ if ( is_shengmu_char ( *spl_str ) ) {
+ if ( 'Z' == *spl_str || 'C' == *spl_str || 'S' == *spl_str )
+ { start_ZCS = true; }
+ spl_str += 1;
+ if ( start_ZCS && 'h' == *spl_str )
+ { spl_str += 1; }
+ }
+ return spl_str;
+ }
- bool spelling_endable = true;
- if (spelling_last_start[level + 1] != '\0')
- spelling_endable = false;
+ bool SpellingTrie::build_ym_info() {
+ bool sucess;
+ SpellingTable *spl_table = new SpellingTable();
+ sucess = spl_table->init_table ( kMaxPinyinSize - 1, 2 * kMaxYmNum, false );
+ assert ( sucess );
+ for ( uint16 pos = 0; pos < spelling_num_; pos++ ) {
+ const char *spl_str = spelling_buf_ + spelling_size_ * pos;
+ spl_str = get_ym_str ( spl_str );
+ if ( '\0' != spl_str[0] ) {
+ sucess = spl_table->put_spelling ( spl_str, 0 );
+ assert ( sucess );
+ }
+ }
+ size_t ym_item_size; // '\0' is included
+ size_t ym_num;
+ const char *ym_buf;
+ ym_buf = spl_table->arrange ( &ym_item_size, &ym_num );
+ if ( NULL != ym_buf_ )
+ { delete [] ym_buf_; }
+ ym_buf_ = new char[ym_item_size * ym_num];
+ if ( NULL == ym_buf_ ) {
+ delete spl_table;
+ return false;
+ }
+ memcpy ( ym_buf_, ym_buf, sizeof ( char ) * ym_item_size * ym_num );
+ ym_size_ = ym_item_size;
+ ym_num_ = ym_num;
+ delete spl_table;
+ // Generate the maping from the spelling ids to the Yunmu ids.
+ if ( spl_ym_ids_ )
+ { delete spl_ym_ids_; }
+ spl_ym_ids_ = new uint8[spelling_num_ + kFullSplIdStart];
+ if ( NULL == spl_ym_ids_ )
+ { return false; }
+ memset ( spl_ym_ids_, 0, sizeof ( uint8 ) * ( spelling_num_ + kFullSplIdStart ) );
+ for ( uint16 id = 1; id < spelling_num_ + kFullSplIdStart; id++ ) {
+ const char *str = get_spelling_str ( id );
+ str = get_ym_str ( str );
+ if ( '\0' != str[0] ) {
+ uint8 ym_id = get_ym_id ( str );
+ spl_ym_ids_[id] = ym_id;
+ assert ( ym_id > 0 );
+ } else {
+ spl_ym_ids_[id] = 0;
+ }
+ }
+ return true;
+ }
+#endif
- size_t item_start_next = item_start;
+ SpellingNode *SpellingTrie::construct_spellings_subset (
+ size_t item_start, size_t item_end, size_t level, SpellingNode *parent ) {
+ if ( level >= spelling_size_ || item_end <= item_start || NULL == parent )
+ { return NULL; }
+ SpellingNode *first_son = NULL;
+ uint16 num_of_son = 0;
+ unsigned char min_son_score = 255;
+ const char *spelling_last_start = spelling_buf_ + spelling_size_ * item_start;
+ char char_for_node = spelling_last_start[level];
+ assert ( char_for_node >= 'A' && char_for_node <= 'Z' ||
+ 'h' == char_for_node );
+ // Scan the array to find how many sons
+ for ( size_t i = item_start + 1; i < item_end; i++ ) {
+ const char *spelling_current = spelling_buf_ + spelling_size_ * i;
+ char char_current = spelling_current[level];
+ if ( char_current != char_for_node ) {
+ num_of_son++;
+ char_for_node = char_current;
+ }
+ }
+ num_of_son++;
+ // Allocate memory
+#ifdef ___BUILD_MODEL___
+ node_num_ += num_of_son;
+#endif
+ first_son = new SpellingNode[num_of_son];
+ memset ( first_son, 0, sizeof ( SpellingNode ) *num_of_son );
+ // Now begin construct tree
+ size_t son_pos = 0;
+ spelling_last_start = spelling_buf_ + spelling_size_ * item_start;
+ char_for_node = spelling_last_start[level];
+ bool spelling_endable = true;
+ if ( spelling_last_start[level + 1] != '\0' )
+ { spelling_endable = false; }
+ size_t item_start_next = item_start;
+ for ( size_t i = item_start + 1; i < item_end; i++ ) {
+ const char *spelling_current = spelling_buf_ + spelling_size_ * i;
+ char char_current = spelling_current[level];
+ assert ( is_valid_spl_char ( char_current ) );
+ if ( char_current != char_for_node ) {
+ // Construct a node
+ SpellingNode *node_current = first_son + son_pos;
+ node_current->char_this_node = char_for_node;
+ // For quick search in the first level
+ if ( 0 == level )
+ { level1_sons_[char_for_node - 'A'] = node_current; }
+ if ( spelling_endable ) {
+ node_current->spelling_idx = kFullSplIdStart + item_start_next;
+ }
+ if ( spelling_last_start[level + 1] != '\0' || i - item_start_next > 1 ) {
+ size_t real_start = item_start_next;
+ if ( spelling_last_start[level + 1] == '\0' )
+ { real_start++; }
+ node_current->first_son =
+ construct_spellings_subset ( real_start, i, level + 1,
+ node_current );
+ if ( real_start == item_start_next + 1 ) {
+ uint16 score_this = static_cast<unsigned char> (
+ spelling_last_start[spelling_size_ - 1] );
+ if ( score_this < node_current->score )
+ { node_current->score = score_this; }
+ }
+ } else {
+ node_current->first_son = NULL;
+ node_current->score = static_cast<unsigned char> (
+ spelling_last_start[spelling_size_ - 1] );
+ }
+ if ( node_current->score < min_son_score )
+ { min_son_score = node_current->score; }
+ bool is_half = false;
+ if ( level == 0 && is_szm_char ( char_for_node ) ) {
+ node_current->spelling_idx =
+ static_cast<uint16> ( char_for_node - 'A' + 1 );
+ if ( char_for_node > 'C' )
+ { node_current->spelling_idx++; }
+ if ( char_for_node > 'S' )
+ { node_current->spelling_idx++; }
+ h2f_num_[node_current->spelling_idx] = i - item_start_next;
+ is_half = true;
+ } else if ( level == 1 && char_for_node == 'h' ) {
+ char ch_level0 = spelling_last_start[0];
+ uint16 part_id = 0;
+ if ( ch_level0 == 'C' )
+ { part_id = 'C' - 'A' + 1 + 1; }
+ else if ( ch_level0 == 'S' )
+ { part_id = 'S' - 'A' + 1 + 2; }
+ else if ( ch_level0 == 'Z' )
+ { part_id = 'Z' - 'A' + 1 + 3; }
+ if ( 0 != part_id ) {
+ node_current->spelling_idx = part_id;
+ h2f_num_[node_current->spelling_idx] = i - item_start_next;
+ is_half = true;
+ }
+ }
+ if ( is_half ) {
+ if ( h2f_num_[node_current->spelling_idx] > 0 )
+ h2f_start_[node_current->spelling_idx] =
+ item_start_next + kFullSplIdStart;
+ else
+ { h2f_start_[node_current->spelling_idx] = 0; }
+ }
+ // for next sibling
+ spelling_last_start = spelling_current;
+ char_for_node = char_current;
+ item_start_next = i;
+ spelling_endable = true;
+ if ( spelling_current[level + 1] != '\0' )
+ { spelling_endable = false; }
+ son_pos++;
+ }
+ }
+ // the last one
+ SpellingNode *node_current = first_son + son_pos;
+ node_current->char_this_node = char_for_node;
+ // For quick search in the first level
+ if ( 0 == level )
+ { level1_sons_[char_for_node - 'A'] = node_current; }
+ if ( spelling_endable ) {
+ node_current->spelling_idx = kFullSplIdStart + item_start_next;
+ }
+ if ( spelling_last_start[level + 1] != '\0' ||
+ item_end - item_start_next > 1 ) {
+ size_t real_start = item_start_next;
+ if ( spelling_last_start[level + 1] == '\0' )
+ { real_start++; }
+ node_current->first_son =
+ construct_spellings_subset ( real_start, item_end, level + 1,
+ node_current );
+ if ( real_start == item_start_next + 1 ) {
+ uint16 score_this = static_cast<unsigned char> (
+ spelling_last_start[spelling_size_ - 1] );
+ if ( score_this < node_current->score )
+ { node_current->score = score_this; }
+ }
+ } else {
+ node_current->first_son = NULL;
+ node_current->score = static_cast<unsigned char> (
+ spelling_last_start[spelling_size_ - 1] );
+ }
+ if ( node_current->score < min_son_score )
+ { min_son_score = node_current->score; }
+ assert ( son_pos + 1 == num_of_son );
+ bool is_half = false;
+ if ( level == 0 && szm_is_enabled ( char_for_node ) ) {
+ node_current->spelling_idx = static_cast<uint16> ( char_for_node - 'A' + 1 );
+ if ( char_for_node > 'C' )
+ { node_current->spelling_idx++; }
+ if ( char_for_node > 'S' )
+ { node_current->spelling_idx++; }
+ h2f_num_[node_current->spelling_idx] = item_end - item_start_next;
+ is_half = true;
+ } else if ( level == 1 && char_for_node == 'h' ) {
+ char ch_level0 = spelling_last_start[0];
+ uint16 part_id = 0;
+ if ( ch_level0 == 'C' )
+ { part_id = 'C' - 'A' + 1 + 1; }
+ else if ( ch_level0 == 'S' )
+ { part_id = 'S' - 'A' + 1 + 2; }
+ else if ( ch_level0 == 'Z' )
+ { part_id = 'Z' - 'A' + 1 + 3; }
+ if ( 0 != part_id ) {
+ node_current->spelling_idx = part_id;
+ h2f_num_[node_current->spelling_idx] = item_end - item_start_next;
+ is_half = true;
+ }
+ }
+ if ( is_half ) {
+ if ( h2f_num_[node_current->spelling_idx] > 0 )
+ h2f_start_[node_current->spelling_idx] =
+ item_start_next + kFullSplIdStart;
+ else
+ { h2f_start_[node_current->spelling_idx] = 0; }
+ }
+ parent->num_of_son = num_of_son;
+ parent->score = min_son_score;
+ return first_son;
+ }
- for (size_t i = item_start + 1; i < item_end; i++) {
- const char *spelling_current = spelling_buf_ + spelling_size_ * i;
- char char_current = spelling_current[level];
- assert(is_valid_spl_char(char_current));
+ bool SpellingTrie::save_spl_trie ( FILE *fp ) {
+ if ( NULL == fp || NULL == spelling_buf_ )
+ { return false; }
+ if ( fwrite ( &spelling_size_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( &spelling_num_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( &score_amplifier_, sizeof ( float ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( &average_score_, sizeof ( unsigned char ), 1, fp ) != 1 )
+ { return false; }
+ if ( fwrite ( spelling_buf_, sizeof ( char ) * spelling_size_,
+ spelling_num_, fp ) != spelling_num_ )
+ { return false; }
+ return true;
+ }
- if (char_current != char_for_node) {
- // Construct a node
- SpellingNode *node_current = first_son + son_pos;
- node_current->char_this_node = char_for_node;
+ bool SpellingTrie::load_spl_trie ( FILE *fp ) {
+ if ( NULL == fp )
+ { return false; }
+ if ( fread ( &spelling_size_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fread ( &spelling_num_, sizeof ( size_t ), 1, fp ) != 1 )
+ { return false; }
+ if ( fread ( &score_amplifier_, sizeof ( float ), 1, fp ) != 1 )
+ { return false; }
+ if ( fread ( &average_score_, sizeof ( unsigned char ), 1, fp ) != 1 )
+ { return false; }
+ if ( NULL != spelling_buf_ )
+ { delete [] spelling_buf_; }
+ spelling_buf_ = new char[spelling_size_ * spelling_num_];
+ if ( NULL == spelling_buf_ )
+ { return false; }
+ if ( fread ( spelling_buf_, sizeof ( char ) * spelling_size_,
+ spelling_num_, fp ) != spelling_num_ )
+ { return false; }
+ return construct ( spelling_buf_, spelling_size_, spelling_num_,
+ score_amplifier_, average_score_ );
+ }
- // For quick search in the first level
- if (0 == level)
- level1_sons_[char_for_node - 'A'] = node_current;
+ bool SpellingTrie::build_f2h() {
+ if ( NULL != f2h_ )
+ { delete [] f2h_; }
+ f2h_ = new uint16[spelling_num_];
+ if ( NULL == f2h_ )
+ { return false; }
+ for ( uint16 hid = 0; hid < kFullSplIdStart; hid++ ) {
+ for ( uint16 fid = h2f_start_[hid];
+ fid < h2f_start_[hid] + h2f_num_[hid]; fid++ )
+ { f2h_[fid - kFullSplIdStart] = hid; }
+ }
+ return true;
+ }
- if (spelling_endable) {
- node_current->spelling_idx = kFullSplIdStart + item_start_next;
- }
+ size_t SpellingTrie::get_spelling_num() {
+ return spelling_num_;
+ }
- if (spelling_last_start[level + 1] != '\0' || i - item_start_next > 1) {
- size_t real_start = item_start_next;
- if (spelling_last_start[level + 1] == '\0')
- real_start++;
+ uint8 SpellingTrie::get_ym_id ( const char *ym_str ) {
+ if ( NULL == ym_str || NULL == ym_buf_ )
+ { return 0; }
+ for ( uint8 pos = 0; pos < ym_num_; pos++ )
+ if ( strcmp ( ym_buf_ + ym_size_ * pos, ym_str ) == 0 )
+ { return pos + 1; }
+ return 0;
+ }
- node_current->first_son =
- construct_spellings_subset(real_start, i, level + 1,
- node_current);
+ const char *SpellingTrie::get_spelling_str ( uint16 splid ) {
+ splstr_queried_[0] = '\0';
+ if ( splid >= kFullSplIdStart ) {
+ splid -= kFullSplIdStart;
+ snprintf ( splstr_queried_, spelling_size_, "%s",
+ spelling_buf_ + splid * spelling_size_ );
+ } else {
+ if ( splid == 'C' - 'A' + 1 + 1 ) {
+ snprintf ( splstr_queried_, spelling_size_, "%s", "Ch" );
+ } else if ( splid == 'S' - 'A' + 1 + 2 ) {
+ snprintf ( splstr_queried_, spelling_size_, "%s", "Sh" );
+ } else if ( splid == 'Z' - 'A' + 1 + 3 ) {
+ snprintf ( splstr_queried_, spelling_size_, "%s", "Zh" );
+ } else {
+ if ( splid > 'C' - 'A' + 1 )
+ { splid--; }
+ if ( splid > 'S' - 'A' + 1 )
+ { splid--; }
+ splstr_queried_[0] = 'A' + splid - 1;
+ splstr_queried_[1] = '\0';
+ }
+ }
+ return splstr_queried_;
+ }
- if (real_start == item_start_next + 1) {
- uint16 score_this = static_cast<unsigned char>(
- spelling_last_start[spelling_size_ - 1]);
- if (score_this < node_current->score)
- node_current->score = score_this;
+ const char16 *SpellingTrie::get_spelling_str16 ( uint16 splid ) {
+ splstr16_queried_[0] = '\0';
+ if ( splid >= kFullSplIdStart ) {
+ splid -= kFullSplIdStart;
+ for ( size_t pos = 0; pos < spelling_size_; pos++ ) {
+ splstr16_queried_[pos] = static_cast<char16>
+ ( spelling_buf_[splid * spelling_size_ + pos] );
+ }
+ } else {
+ if ( splid == 'C' - 'A' + 1 + 1 ) {
+ splstr16_queried_[0] = static_cast<char16> ( 'C' );
+ splstr16_queried_[1] = static_cast<char16> ( 'h' );
+ splstr16_queried_[2] = static_cast<char16> ( '\0' );
+ } else if ( splid == 'S' - 'A' + 1 + 2 ) {
+ splstr16_queried_[0] = static_cast<char16> ( 'S' );
+ splstr16_queried_[1] = static_cast<char16> ( 'h' );
+ splstr16_queried_[2] = static_cast<char16> ( '\0' );
+ } else if ( splid == 'Z' - 'A' + 1 + 3 ) {
+ splstr16_queried_[0] = static_cast<char16> ( 'Z' );
+ splstr16_queried_[1] = static_cast<char16> ( 'h' );
+ splstr16_queried_[2] = static_cast<char16> ( '\0' );
+ } else {
+ if ( splid > 'C' - 'A' + 1 )
+ { splid--; }
+ if ( splid > 'S' - 'A' + 1 )
+ { splid--; }
+ splstr16_queried_[0] = 'A' + splid - 1;
+ splstr16_queried_[1] = '\0';
+ }
}
- } else {
- node_current->first_son = NULL;
- node_current->score = static_cast<unsigned char>(
- spelling_last_start[spelling_size_ - 1]);
- }
-
- if (node_current->score < min_son_score)
- min_son_score = node_current->score;
-
- bool is_half = false;
- if (level == 0 && is_szm_char(char_for_node)) {
- node_current->spelling_idx =
- static_cast<uint16>(char_for_node - 'A' + 1);
-
- if (char_for_node > 'C')
- node_current->spelling_idx++;
- if (char_for_node > 'S')
- node_current->spelling_idx++;
-
- h2f_num_[node_current->spelling_idx] = i - item_start_next;
- is_half = true;
- } else if (level == 1 && char_for_node == 'h') {
- char ch_level0 = spelling_last_start[0];
- uint16 part_id = 0;
- if (ch_level0 == 'C')
- part_id = 'C' - 'A' + 1 + 1;
- else if (ch_level0 == 'S')
- part_id = 'S' - 'A' + 1 + 2;
- else if (ch_level0 == 'Z')
- part_id = 'Z' - 'A' + 1 + 3;
- if (0 != part_id) {
- node_current->spelling_idx = part_id;
- h2f_num_[node_current->spelling_idx] = i - item_start_next;
- is_half = true;
+ return splstr16_queried_;
+ }
+
+ size_t SpellingTrie::get_spelling_str16 ( uint16 splid, char16 *splstr16,
+ size_t splstr16_len ) {
+ if ( NULL == splstr16 || splstr16_len < kMaxPinyinSize + 1 ) { return 0; }
+ if ( splid >= kFullSplIdStart ) {
+ splid -= kFullSplIdStart;
+ for ( size_t pos = 0; pos <= kMaxPinyinSize; pos++ ) {
+ splstr16[pos] = static_cast<char16>
+ ( spelling_buf_[splid * spelling_size_ + pos] );
+ if ( static_cast<char16> ( '\0' ) == splstr16[pos] ) {
+ return pos;
+ }
+ }
+ } else {
+ if ( splid == 'C' - 'A' + 1 + 1 ) {
+ splstr16[0] = static_cast<char16> ( 'C' );
+ splstr16[1] = static_cast<char16> ( 'h' );
+ splstr16[2] = static_cast<char16> ( '\0' );
+ return 2;
+ } else if ( splid == 'S' - 'A' + 1 + 2 ) {
+ splstr16[0] = static_cast<char16> ( 'S' );
+ splstr16[1] = static_cast<char16> ( 'h' );
+ splstr16[2] = static_cast<char16> ( '\0' );
+ return 2;
+ } else if ( splid == 'Z' - 'A' + 1 + 3 ) {
+ splstr16[0] = static_cast<char16> ( 'Z' );
+ splstr16[1] = static_cast<char16> ( 'h' );
+ splstr16[2] = static_cast<char16> ( '\0' );
+ return 2;
+ } else {
+ if ( splid > 'C' - 'A' + 1 )
+ { splid--; }
+ if ( splid > 'S' - 'A' + 1 )
+ { splid--; }
+ splstr16[0] = 'A' + splid - 1;
+ splstr16[1] = '\0';
+ return 1;
+ }
}
- }
-
- if (is_half) {
- if (h2f_num_[node_current->spelling_idx] > 0)
- h2f_start_[node_current->spelling_idx] =
- item_start_next + kFullSplIdStart;
- else
- h2f_start_[node_current->spelling_idx] = 0;
- }
-
- // for next sibling
- spelling_last_start = spelling_current;
- char_for_node = char_current;
- item_start_next = i;
- spelling_endable = true;
- if (spelling_current[level + 1] != '\0')
- spelling_endable = false;
-
- son_pos++;
- }
- }
-
- // the last one
- SpellingNode *node_current = first_son + son_pos;
- node_current->char_this_node = char_for_node;
-
- // For quick search in the first level
- if (0 == level)
- level1_sons_[char_for_node - 'A'] = node_current;
-
- if (spelling_endable) {
- node_current->spelling_idx = kFullSplIdStart + item_start_next;
- }
-
- if (spelling_last_start[level + 1] != '\0' ||
- item_end - item_start_next > 1) {
- size_t real_start = item_start_next;
- if (spelling_last_start[level + 1] == '\0')
- real_start++;
-
- node_current->first_son =
- construct_spellings_subset(real_start, item_end, level + 1,
- node_current);
-
- if (real_start == item_start_next + 1) {
- uint16 score_this = static_cast<unsigned char>(
- spelling_last_start[spelling_size_ - 1]);
- if (score_this < node_current->score)
- node_current->score = score_this;
- }
- } else {
- node_current->first_son = NULL;
- node_current->score = static_cast<unsigned char>(
- spelling_last_start[spelling_size_ - 1]);
- }
-
- if (node_current->score < min_son_score)
- min_son_score = node_current->score;
-
- assert(son_pos + 1 == num_of_son);
-
- bool is_half = false;
- if (level == 0 && szm_is_enabled(char_for_node)) {
- node_current->spelling_idx = static_cast<uint16>(char_for_node - 'A' + 1);
-
- if (char_for_node > 'C')
- node_current->spelling_idx++;
- if (char_for_node > 'S')
- node_current->spelling_idx++;
-
- h2f_num_[node_current->spelling_idx] = item_end - item_start_next;
- is_half = true;
- } else if (level == 1 && char_for_node == 'h') {
- char ch_level0 = spelling_last_start[0];
- uint16 part_id = 0;
- if (ch_level0 == 'C')
- part_id = 'C' - 'A' + 1 + 1;
- else if (ch_level0 == 'S')
- part_id = 'S' - 'A' + 1 + 2;
- else if (ch_level0 == 'Z')
- part_id = 'Z' - 'A' + 1 + 3;
- if (0 != part_id) {
- node_current->spelling_idx = part_id;
- h2f_num_[node_current->spelling_idx] = item_end - item_start_next;
- is_half = true;
- }
- }
- if (is_half) {
- if (h2f_num_[node_current->spelling_idx] > 0)
- h2f_start_[node_current->spelling_idx] =
- item_start_next + kFullSplIdStart;
- else
- h2f_start_[node_current->spelling_idx] = 0;
- }
-
- parent->num_of_son = num_of_son;
- parent->score = min_son_score;
- return first_son;
-}
-
-bool SpellingTrie::save_spl_trie(FILE *fp) {
- if (NULL == fp || NULL == spelling_buf_)
- return false;
-
- if (fwrite(&spelling_size_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(&spelling_num_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fwrite(&score_amplifier_, sizeof(float), 1, fp) != 1)
- return false;
-
- if (fwrite(&average_score_, sizeof(unsigned char), 1, fp) != 1)
- return false;
-
- if (fwrite(spelling_buf_, sizeof(char) * spelling_size_,
- spelling_num_, fp) != spelling_num_)
- return false;
-
- return true;
-}
-
-bool SpellingTrie::load_spl_trie(FILE *fp) {
- if (NULL == fp)
- return false;
-
- if (fread(&spelling_size_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fread(&spelling_num_, sizeof(size_t), 1, fp) != 1)
- return false;
-
- if (fread(&score_amplifier_, sizeof(float), 1, fp) != 1)
- return false;
-
- if (fread(&average_score_, sizeof(unsigned char), 1, fp) != 1)
- return false;
-
- if (NULL != spelling_buf_)
- delete [] spelling_buf_;
-
- spelling_buf_ = new char[spelling_size_ * spelling_num_];
- if (NULL == spelling_buf_)
- return false;
-
- if (fread(spelling_buf_, sizeof(char) * spelling_size_,
- spelling_num_, fp) != spelling_num_)
- return false;
-
- return construct(spelling_buf_, spelling_size_, spelling_num_,
- score_amplifier_, average_score_);
-}
-
-bool SpellingTrie::build_f2h() {
- if (NULL != f2h_)
- delete [] f2h_;
- f2h_ = new uint16[spelling_num_];
- if (NULL == f2h_)
- return false;
-
- for (uint16 hid = 0; hid < kFullSplIdStart; hid++) {
- for (uint16 fid = h2f_start_[hid];
- fid < h2f_start_[hid] + h2f_num_[hid]; fid++)
- f2h_[fid - kFullSplIdStart] = hid;
- }
-
- return true;
-}
-
-size_t SpellingTrie::get_spelling_num() {
- return spelling_num_;
-}
-
-uint8 SpellingTrie::get_ym_id(const char *ym_str) {
- if (NULL == ym_str || NULL == ym_buf_)
- return 0;
-
- for (uint8 pos = 0; pos < ym_num_; pos++)
- if (strcmp(ym_buf_ + ym_size_ * pos, ym_str) == 0)
- return pos + 1;
-
- return 0;
-}
-
-const char* SpellingTrie::get_spelling_str(uint16 splid) {
- splstr_queried_[0] = '\0';
-
- if (splid >= kFullSplIdStart) {
- splid -= kFullSplIdStart;
- snprintf(splstr_queried_, spelling_size_, "%s",
- spelling_buf_ + splid * spelling_size_);
- } else {
- if (splid == 'C' - 'A' + 1 + 1) {
- snprintf(splstr_queried_, spelling_size_, "%s", "Ch");
- } else if (splid == 'S' - 'A' + 1 + 2) {
- snprintf(splstr_queried_, spelling_size_, "%s", "Sh");
- } else if (splid == 'Z' - 'A' + 1 + 3) {
- snprintf(splstr_queried_, spelling_size_, "%s", "Zh");
- } else {
- if (splid > 'C' - 'A' + 1)
- splid--;
- if (splid > 'S' - 'A' + 1)
- splid--;
- splstr_queried_[0] = 'A' + splid - 1;
- splstr_queried_[1] = '\0';
- }
- }
- return splstr_queried_;
-}
-
-const char16* SpellingTrie::get_spelling_str16(uint16 splid) {
- splstr16_queried_[0] = '\0';
-
- if (splid >= kFullSplIdStart) {
- splid -= kFullSplIdStart;
- for (size_t pos = 0; pos < spelling_size_; pos++) {
- splstr16_queried_[pos] = static_cast<char16>
- (spelling_buf_[splid * spelling_size_ + pos]);
- }
- } else {
- if (splid == 'C' - 'A' + 1 + 1) {
- splstr16_queried_[0] = static_cast<char16>('C');
- splstr16_queried_[1] = static_cast<char16>('h');
- splstr16_queried_[2] = static_cast<char16>('\0');
- } else if (splid == 'S' - 'A' + 1 + 2) {
- splstr16_queried_[0] = static_cast<char16>('S');
- splstr16_queried_[1] = static_cast<char16>('h');
- splstr16_queried_[2] = static_cast<char16>('\0');
- } else if (splid == 'Z' - 'A' + 1 + 3) {
- splstr16_queried_[0] = static_cast<char16>('Z');
- splstr16_queried_[1] = static_cast<char16>('h');
- splstr16_queried_[2] = static_cast<char16>('\0');
- } else {
- if (splid > 'C' - 'A' + 1)
- splid--;
- if (splid > 'S' - 'A' + 1)
- splid--;
- splstr16_queried_[0] = 'A' + splid - 1;
- splstr16_queried_[1] = '\0';
- }
- }
- return splstr16_queried_;
-}
-
-size_t SpellingTrie::get_spelling_str16(uint16 splid, char16 *splstr16,
- size_t splstr16_len) {
- if (NULL == splstr16 || splstr16_len < kMaxPinyinSize + 1) return 0;
-
- if (splid >= kFullSplIdStart) {
- splid -= kFullSplIdStart;
- for (size_t pos = 0; pos <= kMaxPinyinSize; pos++) {
- splstr16[pos] = static_cast<char16>
- (spelling_buf_[splid * spelling_size_ + pos]);
- if (static_cast<char16>('\0') == splstr16[pos]) {
- return pos;
- }
- }
- } else {
- if (splid == 'C' - 'A' + 1 + 1) {
- splstr16[0] = static_cast<char16>('C');
- splstr16[1] = static_cast<char16>('h');
- splstr16[2] = static_cast<char16>('\0');
- return 2;
- } else if (splid == 'S' - 'A' + 1 + 2) {
- splstr16[0] = static_cast<char16>('S');
- splstr16[1] = static_cast<char16>('h');
- splstr16[2] = static_cast<char16>('\0');
- return 2;
- } else if (splid == 'Z' - 'A' + 1 + 3) {
- splstr16[0] = static_cast<char16>('Z');
- splstr16[1] = static_cast<char16>('h');
- splstr16[2] = static_cast<char16>('\0');
- return 2;
- } else {
- if (splid > 'C' - 'A' + 1)
- splid--;
- if (splid > 'S' - 'A' + 1)
- splid--;
- splstr16[0] = 'A' + splid - 1;
- splstr16[1] = '\0';
- return 1;
- }
- }
-
- // Not reachable.
- return 0;
-}
+ // Not reachable.
+ return 0;
+ }
} // namespace ime_pinyin
diff --git a/jni/share/splparser.cpp b/jni/share/splparser.cpp
index d75aec6..b9ccf22 100755
--- a/jni/share/splparser.cpp
+++ b/jni/share/splparser.cpp
@@ -19,323 +19,281 @@
namespace ime_pinyin {
-SpellingParser::SpellingParser() {
- spl_trie_ = SpellingTrie::get_cpinstance();
-}
-
-bool SpellingParser::is_valid_to_parse(char ch) {
- return SpellingTrie::is_valid_spl_char(ch);
-}
-
-uint16 SpellingParser::splstr_to_idxs(const char *splstr, uint16 str_len,
- uint16 spl_idx[], uint16 start_pos[],
- uint16 max_size, bool &last_is_pre) {
- if (NULL == splstr || 0 == max_size || 0 == str_len)
- return 0;
-
- if (!SpellingTrie::is_valid_spl_char(splstr[0]))
- return 0;
-
- last_is_pre = false;
-
- const SpellingNode *node_this = spl_trie_->root_;
-
- uint16 str_pos = 0;
- uint16 idx_num = 0;
- if (NULL != start_pos)
- start_pos[0] = 0;
- bool last_is_splitter = false;
-
- while (str_pos < str_len) {
- char char_this = splstr[str_pos];
- // all characters outside of [a, z] are considered as splitters
- if (!SpellingTrie::is_valid_spl_char(char_this)) {
- // test if the current node is endable
- uint16 id_this = node_this->spelling_idx;
- if (spl_trie_->if_valid_id_update(&id_this)) {
- spl_idx[idx_num] = id_this;
-
- idx_num++;
- str_pos++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- if (idx_num >= max_size)
- return idx_num;
-
- node_this = spl_trie_->root_;
- last_is_splitter = true;
- continue;
- } else {
- if (last_is_splitter) {
- str_pos++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- continue;
- } else {
- return idx_num;
- }
- }
+ SpellingParser::SpellingParser() {
+ spl_trie_ = SpellingTrie::get_cpinstance();
}
- last_is_splitter = false;
-
- SpellingNode *found_son = NULL;
+ bool SpellingParser::is_valid_to_parse ( char ch ) {
+ return SpellingTrie::is_valid_spl_char ( ch );
+ }
- if (0 == str_pos) {
- if (char_this >= 'a')
- found_son = spl_trie_->level1_sons_[char_this - 'a'];
- else
- found_son = spl_trie_->level1_sons_[char_this - 'A'];
- } else {
- SpellingNode *first_son = node_this->first_son;
- // Because for Zh/Ch/Sh nodes, they are the last in the buffer and
- // frequently used, so we scan from the end.
- for (int i = 0; i < node_this->num_of_son; i++) {
- SpellingNode *this_son = first_son + i;
- if (SpellingTrie::is_same_spl_char(
- this_son->char_this_node, char_this)) {
- found_son = this_son;
- break;
+ uint16 SpellingParser::splstr_to_idxs ( const char *splstr, uint16 str_len,
+ uint16 spl_idx[], uint16 start_pos[],
+ uint16 max_size, bool &last_is_pre ) {
+ if ( NULL == splstr || 0 == max_size || 0 == str_len )
+ { return 0; }
+ if ( !SpellingTrie::is_valid_spl_char ( splstr[0] ) )
+ { return 0; }
+ last_is_pre = false;
+ const SpellingNode *node_this = spl_trie_->root_;
+ uint16 str_pos = 0;
+ uint16 idx_num = 0;
+ if ( NULL != start_pos )
+ { start_pos[0] = 0; }
+ bool last_is_splitter = false;
+ while ( str_pos < str_len ) {
+ char char_this = splstr[str_pos];
+ // all characters outside of [a, z] are considered as splitters
+ if ( !SpellingTrie::is_valid_spl_char ( char_this ) ) {
+ // test if the current node is endable
+ uint16 id_this = node_this->spelling_idx;
+ if ( spl_trie_->if_valid_id_update ( &id_this ) ) {
+ spl_idx[idx_num] = id_this;
+ idx_num++;
+ str_pos++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
+ if ( idx_num >= max_size )
+ { return idx_num; }
+ node_this = spl_trie_->root_;
+ last_is_splitter = true;
+ continue;
+ } else {
+ if ( last_is_splitter ) {
+ str_pos++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
+ continue;
+ } else {
+ return idx_num;
+ }
+ }
+ }
+ last_is_splitter = false;
+ SpellingNode *found_son = NULL;
+ if ( 0 == str_pos ) {
+ if ( char_this >= 'a' )
+ { found_son = spl_trie_->level1_sons_[char_this - 'a']; }
+ else
+ { found_son = spl_trie_->level1_sons_[char_this - 'A']; }
+ } else {
+ SpellingNode *first_son = node_this->first_son;
+ // Because for Zh/Ch/Sh nodes, they are the last in the buffer and
+ // frequently used, so we scan from the end.
+ for ( int i = 0; i < node_this->num_of_son; i++ ) {
+ SpellingNode *this_son = first_son + i;
+ if ( SpellingTrie::is_same_spl_char (
+ this_son->char_this_node, char_this ) ) {
+ found_son = this_son;
+ break;
+ }
+ }
+ }
+ // found, just move the current node pointer to the the son
+ if ( NULL != found_son ) {
+ node_this = found_son;
+ } else {
+ // not found, test if it is endable
+ uint16 id_this = node_this->spelling_idx;
+ if ( spl_trie_->if_valid_id_update ( &id_this ) ) {
+ // endable, remember the index
+ spl_idx[idx_num] = id_this;
+ idx_num++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
+ if ( idx_num >= max_size )
+ { return idx_num; }
+ node_this = spl_trie_->root_;
+ continue;
+ } else {
+ return idx_num;
+ }
+ }
+ str_pos++;
+ }
+ uint16 id_this = node_this->spelling_idx;
+ if ( spl_trie_->if_valid_id_update ( &id_this ) ) {
+ // endable, remember the index
+ spl_idx[idx_num] = id_this;
+ idx_num++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
}
- }
+ last_is_pre = !last_is_splitter;
+ return idx_num;
}
- // found, just move the current node pointer to the the son
- if (NULL != found_son) {
- node_this = found_son;
- } else {
- // not found, test if it is endable
- uint16 id_this = node_this->spelling_idx;
- if (spl_trie_->if_valid_id_update(&id_this)) {
- // endable, remember the index
- spl_idx[idx_num] = id_this;
-
- idx_num++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- if (idx_num >= max_size)
- return idx_num;
- node_this = spl_trie_->root_;
- continue;
- } else {
+ uint16 SpellingParser::splstr_to_idxs_f ( const char *splstr, uint16 str_len,
+ uint16 spl_idx[], uint16 start_pos[],
+ uint16 max_size, bool &last_is_pre ) {
+ uint16 idx_num = splstr_to_idxs ( splstr, str_len, spl_idx, start_pos,
+ max_size, last_is_pre );
+ for ( uint16 pos = 0; pos < idx_num; pos++ ) {
+ if ( spl_trie_->is_half_id_yunmu ( spl_idx[pos] ) ) {
+ spl_trie_->half_to_full ( spl_idx[pos], spl_idx + pos );
+ if ( pos == idx_num - 1 ) {
+ last_is_pre = false;
+ }
+ }
+ }
return idx_num;
- }
}
- str_pos++;
- }
-
- uint16 id_this = node_this->spelling_idx;
- if (spl_trie_->if_valid_id_update(&id_this)) {
- // endable, remember the index
- spl_idx[idx_num] = id_this;
-
- idx_num++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- }
-
- last_is_pre = !last_is_splitter;
-
- return idx_num;
-}
-
-uint16 SpellingParser::splstr_to_idxs_f(const char *splstr, uint16 str_len,
- uint16 spl_idx[], uint16 start_pos[],
- uint16 max_size, bool &last_is_pre) {
- uint16 idx_num = splstr_to_idxs(splstr, str_len, spl_idx, start_pos,
- max_size, last_is_pre);
- for (uint16 pos = 0; pos < idx_num; pos++) {
- if (spl_trie_->is_half_id_yunmu(spl_idx[pos])) {
- spl_trie_->half_to_full(spl_idx[pos], spl_idx + pos);
- if (pos == idx_num - 1) {
+ uint16 SpellingParser::splstr16_to_idxs ( const char16 *splstr, uint16 str_len,
+ uint16 spl_idx[], uint16 start_pos[],
+ uint16 max_size, bool &last_is_pre ) {
+ if ( NULL == splstr || 0 == max_size || 0 == str_len )
+ { return 0; }
+ if ( !SpellingTrie::is_valid_spl_char ( splstr[0] ) )
+ { return 0; }
last_is_pre = false;
- }
- }
- }
- return idx_num;
-}
-
-uint16 SpellingParser::splstr16_to_idxs(const char16 *splstr, uint16 str_len,
- uint16 spl_idx[], uint16 start_pos[],
- uint16 max_size, bool &last_is_pre) {
- if (NULL == splstr || 0 == max_size || 0 == str_len)
- return 0;
-
- if (!SpellingTrie::is_valid_spl_char(splstr[0]))
- return 0;
-
- last_is_pre = false;
-
- const SpellingNode *node_this = spl_trie_->root_;
-
- uint16 str_pos = 0;
- uint16 idx_num = 0;
- if (NULL != start_pos)
- start_pos[0] = 0;
- bool last_is_splitter = false;
-
- while (str_pos < str_len) {
- char16 char_this = splstr[str_pos];
- // all characters outside of [a, z] are considered as splitters
- if (!SpellingTrie::is_valid_spl_char(char_this)) {
- // test if the current node is endable
- uint16 id_this = node_this->spelling_idx;
- if (spl_trie_->if_valid_id_update(&id_this)) {
- spl_idx[idx_num] = id_this;
-
- idx_num++;
- str_pos++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- if (idx_num >= max_size)
- return idx_num;
-
- node_this = spl_trie_->root_;
- last_is_splitter = true;
- continue;
- } else {
- if (last_is_splitter) {
- str_pos++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- continue;
- } else {
- return idx_num;
+ const SpellingNode *node_this = spl_trie_->root_;
+ uint16 str_pos = 0;
+ uint16 idx_num = 0;
+ if ( NULL != start_pos )
+ { start_pos[0] = 0; }
+ bool last_is_splitter = false;
+ while ( str_pos < str_len ) {
+ char16 char_this = splstr[str_pos];
+ // all characters outside of [a, z] are considered as splitters
+ if ( !SpellingTrie::is_valid_spl_char ( char_this ) ) {
+ // test if the current node is endable
+ uint16 id_this = node_this->spelling_idx;
+ if ( spl_trie_->if_valid_id_update ( &id_this ) ) {
+ spl_idx[idx_num] = id_this;
+ idx_num++;
+ str_pos++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
+ if ( idx_num >= max_size )
+ { return idx_num; }
+ node_this = spl_trie_->root_;
+ last_is_splitter = true;
+ continue;
+ } else {
+ if ( last_is_splitter ) {
+ str_pos++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
+ continue;
+ } else {
+ return idx_num;
+ }
+ }
+ }
+ last_is_splitter = false;
+ SpellingNode *found_son = NULL;
+ if ( 0 == str_pos ) {
+ if ( char_this >= 'a' )
+ { found_son = spl_trie_->level1_sons_[char_this - 'a']; }
+ else
+ { found_son = spl_trie_->level1_sons_[char_this - 'A']; }
+ } else {
+ SpellingNode *first_son = node_this->first_son;
+ // Because for Zh/Ch/Sh nodes, they are the last in the buffer and
+ // frequently used, so we scan from the end.
+ for ( int i = 0; i < node_this->num_of_son; i++ ) {
+ SpellingNode *this_son = first_son + i;
+ if ( SpellingTrie::is_same_spl_char (
+ this_son->char_this_node, char_this ) ) {
+ found_son = this_son;
+ break;
+ }
+ }
+ }
+ // found, just move the current node pointer to the the son
+ if ( NULL != found_son ) {
+ node_this = found_son;
+ } else {
+ // not found, test if it is endable
+ uint16 id_this = node_this->spelling_idx;
+ if ( spl_trie_->if_valid_id_update ( &id_this ) ) {
+ // endable, remember the index
+ spl_idx[idx_num] = id_this;
+ idx_num++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
+ if ( idx_num >= max_size )
+ { return idx_num; }
+ node_this = spl_trie_->root_;
+ continue;
+ } else {
+ return idx_num;
+ }
+ }
+ str_pos++;
}
- }
- }
-
- last_is_splitter = false;
-
- SpellingNode *found_son = NULL;
-
- if (0 == str_pos) {
- if (char_this >= 'a')
- found_son = spl_trie_->level1_sons_[char_this - 'a'];
- else
- found_son = spl_trie_->level1_sons_[char_this - 'A'];
- } else {
- SpellingNode *first_son = node_this->first_son;
- // Because for Zh/Ch/Sh nodes, they are the last in the buffer and
- // frequently used, so we scan from the end.
- for (int i = 0; i < node_this->num_of_son; i++) {
- SpellingNode *this_son = first_son + i;
- if (SpellingTrie::is_same_spl_char(
- this_son->char_this_node, char_this)) {
- found_son = this_son;
- break;
+ uint16 id_this = node_this->spelling_idx;
+ if ( spl_trie_->if_valid_id_update ( &id_this ) ) {
+ // endable, remember the index
+ spl_idx[idx_num] = id_this;
+ idx_num++;
+ if ( NULL != start_pos )
+ { start_pos[idx_num] = str_pos; }
}
- }
+ last_is_pre = !last_is_splitter;
+ return idx_num;
}
- // found, just move the current node pointer to the the son
- if (NULL != found_son) {
- node_this = found_son;
- } else {
- // not found, test if it is endable
- uint16 id_this = node_this->spelling_idx;
- if (spl_trie_->if_valid_id_update(&id_this)) {
- // endable, remember the index
- spl_idx[idx_num] = id_this;
-
- idx_num++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- if (idx_num >= max_size)
- return idx_num;
- node_this = spl_trie_->root_;
- continue;
- } else {
+ uint16 SpellingParser::splstr16_to_idxs_f ( const char16 *splstr, uint16 str_len,
+ uint16 spl_idx[], uint16 start_pos[],
+ uint16 max_size, bool &last_is_pre ) {
+ uint16 idx_num = splstr16_to_idxs ( splstr, str_len, spl_idx, start_pos,
+ max_size, last_is_pre );
+ for ( uint16 pos = 0; pos < idx_num; pos++ ) {
+ if ( spl_trie_->is_half_id_yunmu ( spl_idx[pos] ) ) {
+ spl_trie_->half_to_full ( spl_idx[pos], spl_idx + pos );
+ if ( pos == idx_num - 1 ) {
+ last_is_pre = false;
+ }
+ }
+ }
return idx_num;
- }
}
- str_pos++;
- }
-
- uint16 id_this = node_this->spelling_idx;
- if (spl_trie_->if_valid_id_update(&id_this)) {
- // endable, remember the index
- spl_idx[idx_num] = id_this;
-
- idx_num++;
- if (NULL != start_pos)
- start_pos[idx_num] = str_pos;
- }
-
- last_is_pre = !last_is_splitter;
-
- return idx_num;
-}
-
-uint16 SpellingParser::splstr16_to_idxs_f(const char16 *splstr, uint16 str_len,
- uint16 spl_idx[], uint16 start_pos[],
- uint16 max_size, bool &last_is_pre) {
- uint16 idx_num = splstr16_to_idxs(splstr, str_len, spl_idx, start_pos,
- max_size, last_is_pre);
- for (uint16 pos = 0; pos < idx_num; pos++) {
- if (spl_trie_->is_half_id_yunmu(spl_idx[pos])) {
- spl_trie_->half_to_full(spl_idx[pos], spl_idx + pos);
- if (pos == idx_num - 1) {
- last_is_pre = false;
- }
+ uint16 SpellingParser::get_splid_by_str ( const char *splstr, uint16 str_len,
+ bool *is_pre ) {
+ if ( NULL == is_pre )
+ { return 0; }
+ uint16 spl_idx[2];
+ uint16 start_pos[3];
+ if ( splstr_to_idxs ( splstr, str_len, spl_idx, start_pos, 2, *is_pre ) != 1 )
+ { return 0; }
+ if ( start_pos[1] != str_len )
+ { return 0; }
+ return spl_idx[0];
}
- }
- return idx_num;
-}
-
-uint16 SpellingParser::get_splid_by_str(const char *splstr, uint16 str_len,
- bool *is_pre) {
- if (NULL == is_pre)
- return 0;
-
- uint16 spl_idx[2];
- uint16 start_pos[3];
-
- if (splstr_to_idxs(splstr, str_len, spl_idx, start_pos, 2, *is_pre) != 1)
- return 0;
-
- if (start_pos[1] != str_len)
- return 0;
- return spl_idx[0];
-}
-
-uint16 SpellingParser::get_splid_by_str_f(const char *splstr, uint16 str_len,
- bool *is_pre) {
- if (NULL == is_pre)
- return 0;
-
- uint16 spl_idx[2];
- uint16 start_pos[3];
- if (splstr_to_idxs(splstr, str_len, spl_idx, start_pos, 2, *is_pre) != 1)
- return 0;
-
- if (start_pos[1] != str_len)
- return 0;
- if (spl_trie_->is_half_id_yunmu(spl_idx[0])) {
- spl_trie_->half_to_full(spl_idx[0], spl_idx);
- *is_pre = false;
- }
-
- return spl_idx[0];
-}
-
-uint16 SpellingParser::get_splids_parallel(const char *splstr, uint16 str_len,
- uint16 splidx[], uint16 max_size,
- uint16 &full_id_num, bool &is_pre) {
- if (max_size <= 0 || !is_valid_to_parse(splstr[0]))
- return 0;
+ uint16 SpellingParser::get_splid_by_str_f ( const char *splstr, uint16 str_len,
+ bool *is_pre ) {
+ if ( NULL == is_pre )
+ { return 0; }
+ uint16 spl_idx[2];
+ uint16 start_pos[3];
+ if ( splstr_to_idxs ( splstr, str_len, spl_idx, start_pos, 2, *is_pre ) != 1 )
+ { return 0; }
+ if ( start_pos[1] != str_len )
+ { return 0; }
+ if ( spl_trie_->is_half_id_yunmu ( spl_idx[0] ) ) {
+ spl_trie_->half_to_full ( spl_idx[0], spl_idx );
+ *is_pre = false;
+ }
+ return spl_idx[0];
+ }
- splidx[0] = get_splid_by_str(splstr, str_len, &is_pre);
- full_id_num = 0;
- if (0 != splidx[0]) {
- if (splidx[0] >= kFullSplIdStart)
- full_id_num = 1;
- return 1;
- }
- return 0;
-}
+ uint16 SpellingParser::get_splids_parallel ( const char *splstr, uint16 str_len,
+ uint16 splidx[], uint16 max_size,
+ uint16 &full_id_num, bool &is_pre ) {
+ if ( max_size <= 0 || !is_valid_to_parse ( splstr[0] ) )
+ { return 0; }
+ splidx[0] = get_splid_by_str ( splstr, str_len, &is_pre );
+ full_id_num = 0;
+ if ( 0 != splidx[0] ) {
+ if ( splidx[0] >= kFullSplIdStart )
+ { full_id_num = 1; }
+ return 1;
+ }
+ return 0;
+ }
} // namespace ime_pinyin
diff --git a/jni/share/sync.cpp b/jni/share/sync.cpp
index 91e27b8..00f61da 100755
--- a/jni/share/sync.cpp
+++ b/jni/share/sync.cpp
@@ -22,91 +22,85 @@
namespace ime_pinyin {
-Sync::Sync()
- : userdict_(NULL),
- dictfile_(NULL),
- last_count_(0) {
-};
-
-Sync::~Sync() {
-}
-
-
-bool Sync::begin(const char * filename) {
- if (userdict_) {
- finish();
- }
-
- if (!filename) {
- return false;
- }
-
- dictfile_ = strdup(filename);
- if (!dictfile_) {
- return false;
- }
-
- userdict_ = new UserDict();
- if (!userdict_) {
- free(dictfile_);
- dictfile_ = NULL;
- return false;
- }
-
- if (userdict_->load_dict((const char*)dictfile_, kUserDictIdStart,
- kUserDictIdEnd) == false) {
- delete userdict_;
- userdict_ = NULL;
- free(dictfile_);
- dictfile_ = NULL;
- return false;
- }
-
- userdict_->set_limit(kUserDictMaxLemmaCount, kUserDictMaxLemmaSize, kUserDictRatio);
-
- return true;
-}
-
-int Sync::put_lemmas(char16 * lemmas, int len) {
- return userdict_->put_lemmas_no_sync_from_utf16le_string(lemmas, len);
-}
-
-int Sync::get_lemmas(char16 * str, int size) {
- return userdict_->get_sync_lemmas_in_utf16le_string_from_beginning(str, size, &last_count_);
-}
-
-int Sync::get_last_got_count() {
- return last_count_;
-}
-
-int Sync::get_total_count() {
- return userdict_->get_sync_count();
-}
-
-void Sync::clear_last_got() {
- if (last_count_ < 0) {
- return;
- }
- userdict_->clear_sync_lemmas(0, last_count_);
- last_count_ = 0;
-}
-
-void Sync::finish() {
- if (userdict_) {
- userdict_->close_dict();
- delete userdict_;
- userdict_ = NULL;
- free(dictfile_);
- dictfile_ = NULL;
- last_count_ = 0;
- }
-}
-
-int Sync::get_capacity() {
- UserDict::UserDictStat stat;
- userdict_->state(&stat);
- return stat.limit_lemma_count - stat.lemma_count;
-}
+ Sync::Sync()
+ : userdict_ ( NULL ),
+ dictfile_ ( NULL ),
+ last_count_ ( 0 ) {
+ };
+
+ Sync::~Sync() {
+ }
+
+
+ bool Sync::begin ( const char *filename ) {
+ if ( userdict_ ) {
+ finish();
+ }
+ if ( !filename ) {
+ return false;
+ }
+ dictfile_ = strdup ( filename );
+ if ( !dictfile_ ) {
+ return false;
+ }
+ userdict_ = new UserDict();
+ if ( !userdict_ ) {
+ free ( dictfile_ );
+ dictfile_ = NULL;
+ return false;
+ }
+ if ( userdict_->load_dict ( ( const char * ) dictfile_, kUserDictIdStart,
+ kUserDictIdEnd ) == false ) {
+ delete userdict_;
+ userdict_ = NULL;
+ free ( dictfile_ );
+ dictfile_ = NULL;
+ return false;
+ }
+ userdict_->set_limit ( kUserDictMaxLemmaCount, kUserDictMaxLemmaSize, kUserDictRatio );
+ return true;
+ }
+
+ int Sync::put_lemmas ( char16 *lemmas, int len ) {
+ return userdict_->put_lemmas_no_sync_from_utf16le_string ( lemmas, len );
+ }
+
+ int Sync::get_lemmas ( char16 *str, int size ) {
+ return userdict_->get_sync_lemmas_in_utf16le_string_from_beginning ( str, size, &last_count_ );
+ }
+
+ int Sync::get_last_got_count() {
+ return last_count_;
+ }
+
+ int Sync::get_total_count() {
+ return userdict_->get_sync_count();
+ }
+
+ void Sync::clear_last_got() {
+ if ( last_count_ < 0 ) {
+ return;
+ }
+ userdict_->clear_sync_lemmas ( 0, last_count_ );
+ last_count_ = 0;
+ }
+
+ void Sync::finish() {
+ if ( userdict_ ) {
+ userdict_->close_dict();
+ delete userdict_;
+ userdict_ = NULL;
+ free ( dictfile_ );
+ dictfile_ = NULL;
+ last_count_ = 0;
+ }
+ }
+
+ int Sync::get_capacity() {
+ UserDict::UserDictStat stat;
+ userdict_->state ( &stat );
+ return stat.limit_lemma_count - stat.lemma_count;
+ }
}
#endif
diff --git a/jni/share/userdict.cpp b/jni/share/userdict.cpp
index 135dd79..a762a3f 100755
--- a/jni/share/userdict.cpp
+++ b/jni/share/userdict.cpp
@@ -35,17 +35,17 @@
namespace ime_pinyin {
#ifdef ___DEBUG_PERF___
-static uint64 _ellapse_ = 0;
-static struct timeval _tv_start_, _tv_end_;
+ static uint64 _ellapse_ = 0;
+ static struct timeval _tv_start_, _tv_end_;
#define DEBUG_PERF_BEGIN \
do { \
- gettimeofday(&_tv_start_, NULL); \
+ gettimeofday(&_tv_start_, NULL); \
} while(0)
#define DEBUG_PERF_END \
do { \
- gettimeofday(&_tv_end_, NULL); \
- _ellapse_ = (_tv_end_.tv_sec - _tv_start_.tv_sec) * 1000000 + \
- (_tv_end_.tv_usec - _tv_start_.tv_usec); \
+ gettimeofday(&_tv_end_, NULL); \
+ _ellapse_ = (_tv_end_.tv_sec - _tv_start_.tv_sec) * 1000000 + \
+ (_tv_end_.tv_usec - _tv_start_.tv_usec); \
} while(0)
#define LOGD_PERF(message) \
LOGD("PERFORMANCE[%s] %llu usec.", message, _ellapse_);
@@ -55,2200 +55,2038 @@ static struct timeval _tv_start_, _tv_end_;
#define LOGD_PERF(message)
#endif
-// XXX File load and write are thread-safe by g_mutex_
-static pthread_mutex_t g_mutex_ = PTHREAD_MUTEX_INITIALIZER;
-static struct timeval g_last_update_ = {0, 0};
+ // XXX File load and write are thread-safe by g_mutex_
+ static pthread_mutex_t g_mutex_ = PTHREAD_MUTEX_INITIALIZER;
+ static struct timeval g_last_update_ = {0, 0};
-inline uint32 UserDict::get_dict_file_size(UserDictInfo * info) {
- return (4 + info->lemma_size + (info->lemma_count << 3)
+ inline uint32 UserDict::get_dict_file_size ( UserDictInfo *info ) {
+ return ( 4 + info->lemma_size + ( info->lemma_count << 3 )
#ifdef ___PREDICT_ENABLED___
- + (info->lemma_count << 2)
+ + ( info->lemma_count << 2 )
#endif
#ifdef ___SYNC_ENABLED___
- + (info->sync_count << 2)
+ + ( info->sync_count << 2 )
#endif
- + sizeof(*info));
-}
+ + sizeof ( *info ) );
+ }
-inline LmaScoreType UserDict::translate_score(int raw_score) {
- // 1) ori_freq: original user frequency
- uint32 ori_freq = extract_score_freq(raw_score);
- // 2) lmt_off: lmt index (week offset for example)
- uint64 lmt_off = ((raw_score & 0xffff0000) >> 16);
- if (kUserDictLMTBitWidth < 16) {
- uint64 mask = ~(1 << kUserDictLMTBitWidth);
- lmt_off &= mask;
- }
- // 3) now_off: current time index (current week offset for example)
- // assuming load_time_ is around current time
- uint64 now_off = load_time_.tv_sec;
- now_off = (now_off - kUserDictLMTSince) / kUserDictLMTGranularity;
- now_off = (now_off << (64 - kUserDictLMTBitWidth));
- now_off = (now_off >> (64 - kUserDictLMTBitWidth));
- // 4) factor: decide expand-factor
- int delta = now_off - lmt_off;
- if (delta > 4)
- delta = 4;
- int factor = 80 - (delta << 4);
-
- double tf = (double)(dict_info_.total_nfreq + total_other_nfreq_);
- return (LmaScoreType)(log((double)factor * (double)ori_freq / tf)
- * NGram::kLogValueAmplifier);
-}
+ inline LmaScoreType UserDict::translate_score ( int raw_score ) {
+ // 1) ori_freq: original user frequency
+ uint32 ori_freq = extract_score_freq ( raw_score );
+ // 2) lmt_off: lmt index (week offset for example)
+ uint64 lmt_off = ( ( raw_score & 0xffff0000 ) >> 16 );
+ if ( kUserDictLMTBitWidth < 16 ) {
+ uint64 mask = ~ ( 1 << kUserDictLMTBitWidth );
+ lmt_off &= mask;
+ }
+ // 3) now_off: current time index (current week offset for example)
+ // assuming load_time_ is around current time
+ uint64 now_off = load_time_.tv_sec;
+ now_off = ( now_off - kUserDictLMTSince ) / kUserDictLMTGranularity;
+ now_off = ( now_off << ( 64 - kUserDictLMTBitWidth ) );
+ now_off = ( now_off >> ( 64 - kUserDictLMTBitWidth ) );
+ // 4) factor: decide expand-factor
+ int delta = now_off - lmt_off;
+ if ( delta > 4 )
+ { delta = 4; }
+ int factor = 80 - ( delta << 4 );
+ double tf = ( double ) ( dict_info_.total_nfreq + total_other_nfreq_ );
+ return ( LmaScoreType ) ( log ( ( double ) factor * ( double ) ori_freq / tf )
+ * NGram::kLogValueAmplifier );
+ }
-inline int UserDict::extract_score_freq(int raw_score) {
- // Frequence stored in lowest 16 bits
- int freq = (raw_score & 0x0000ffff);
- return freq;
-}
+ inline int UserDict::extract_score_freq ( int raw_score ) {
+ // Frequence stored in lowest 16 bits
+ int freq = ( raw_score & 0x0000ffff );
+ return freq;
+ }
-inline uint64 UserDict::extract_score_lmt(int raw_score) {
- uint64 lmt = ((raw_score & 0xffff0000) >> 16);
- if (kUserDictLMTBitWidth < 16) {
- uint64 mask = ~(1 << kUserDictLMTBitWidth);
- lmt &= mask;
- }
- lmt = lmt * kUserDictLMTGranularity + kUserDictLMTSince;
- return lmt;
-}
+ inline uint64 UserDict::extract_score_lmt ( int raw_score ) {
+ uint64 lmt = ( ( raw_score & 0xffff0000 ) >> 16 );
+ if ( kUserDictLMTBitWidth < 16 ) {
+ uint64 mask = ~ ( 1 << kUserDictLMTBitWidth );
+ lmt &= mask;
+ }
+ lmt = lmt * kUserDictLMTGranularity + kUserDictLMTSince;
+ return lmt;
+ }
-inline int UserDict::build_score(uint64 lmt, int freq) {
- lmt = (lmt - kUserDictLMTSince) / kUserDictLMTGranularity;
- lmt = (lmt << (64 - kUserDictLMTBitWidth));
- lmt = (lmt >> (64 - kUserDictLMTBitWidth));
- uint16 lmt16 = (uint16)lmt;
- int s = freq;
- s &= 0x0000ffff;
- s = (lmt16 << 16) | s;
- return s;
-}
+ inline int UserDict::build_score ( uint64 lmt, int freq ) {
+ lmt = ( lmt - kUserDictLMTSince ) / kUserDictLMTGranularity;
+ lmt = ( lmt << ( 64 - kUserDictLMTBitWidth ) );
+ lmt = ( lmt >> ( 64 - kUserDictLMTBitWidth ) );
+ uint16 lmt16 = ( uint16 ) lmt;
+ int s = freq;
+ s &= 0x0000ffff;
+ s = ( lmt16 << 16 ) | s;
+ return s;
+ }
-inline int64 UserDict::utf16le_atoll(uint16 *s, int len) {
- int64 ret = 0;
- if (len <= 0)
- return ret;
-
- int flag = 1;
- const uint16 * endp = s + len;
- if (*s == '-') {
- flag = -1;
- s++;
- } else if (*s == '+') {
- s++;
- }
-
- while (*s >= '0' && *s <= '9' && s < endp) {
- ret += ret * 10 + (*s) - '0';
- s++;
- }
- return ret * flag;
-}
+ inline int64 UserDict::utf16le_atoll ( uint16 *s, int len ) {
+ int64 ret = 0;
+ if ( len <= 0 )
+ { return ret; }
+ int flag = 1;
+ const uint16 *endp = s + len;
+ if ( *s == '-' ) {
+ flag = -1;
+ s++;
+ } else if ( *s == '+' ) {
+ s++;
+ }
+ while ( *s >= '0' && *s <= '9' && s < endp ) {
+ ret += ret * 10 + ( *s ) - '0';
+ s++;
+ }
+ return ret * flag;
+ }
-inline int UserDict::utf16le_lltoa(int64 v, uint16 *s, int size) {
- if (!s || size <= 0)
- return 0;
- uint16 *endp = s + size;
- int ret_len = 0;
- if (v < 0) {
- *(s++) = '-';
- ++ret_len;
- v *= -1;
- }
-
- uint16 *b = s;
- while (s < endp && v != 0) {
- *(s++) = '0' + (v % 10);
- v = v / 10;
- ++ret_len;
- }
-
- if (v != 0)
- return 0;
-
- --s;
-
- while (b < s) {
- *b = *s;
- ++b, --s;
- }
-
- return ret_len;
-}
+ inline int UserDict::utf16le_lltoa ( int64 v, uint16 *s, int size ) {
+ if ( !s || size <= 0 )
+ { return 0; }
+ uint16 *endp = s + size;
+ int ret_len = 0;
+ if ( v < 0 ) {
+ * ( s++ ) = '-';
+ ++ret_len;
+ v *= -1;
+ }
+ uint16 *b = s;
+ while ( s < endp && v != 0 ) {
+ * ( s++ ) = '0' + ( v % 10 );
+ v = v / 10;
+ ++ret_len;
+ }
+ if ( v != 0 )
+ { return 0; }
+ --s;
+ while ( b < s ) {
+ *b = *s;
+ ++b, --s;
+ }
+ return ret_len;
+ }
-inline void UserDict::set_lemma_flag(uint32 offset, uint8 flag) {
- offset &= kUserDictOffsetMask;
- lemmas_[offset] |= flag;
-}
+ inline void UserDict::set_lemma_flag ( uint32 offset, uint8 flag ) {
+ offset &= kUserDictOffsetMask;
+ lemmas_[offset] |= flag;
+ }
-inline char UserDict::get_lemma_flag(uint32 offset) {
- offset &= kUserDictOffsetMask;
- return (char)(lemmas_[offset]);
-}
+ inline char UserDict::get_lemma_flag ( uint32 offset ) {
+ offset &= kUserDictOffsetMask;
+ return ( char ) ( lemmas_[offset] );
+ }
-inline char UserDict::get_lemma_nchar(uint32 offset) {
- offset &= kUserDictOffsetMask;
- return (char)(lemmas_[offset + 1]);
-}
+ inline char UserDict::get_lemma_nchar ( uint32 offset ) {
+ offset &= kUserDictOffsetMask;
+ return ( char ) ( lemmas_[offset + 1] );
+ }
-inline uint16 * UserDict::get_lemma_spell_ids(uint32 offset) {
- offset &= kUserDictOffsetMask;
- return (uint16 *)(lemmas_ + offset + 2);
-}
+ inline uint16 *UserDict::get_lemma_spell_ids ( uint32 offset ) {
+ offset &= kUserDictOffsetMask;
+ return ( uint16 * ) ( lemmas_ + offset + 2 );
+ }
-inline uint16 * UserDict::get_lemma_word(uint32 offset) {
- offset &= kUserDictOffsetMask;
- uint8 nchar = get_lemma_nchar(offset);
- return (uint16 *)(lemmas_ + offset + 2 + (nchar << 1));
-}
+ inline uint16 *UserDict::get_lemma_word ( uint32 offset ) {
+ offset &= kUserDictOffsetMask;
+ uint8 nchar = get_lemma_nchar ( offset );
+ return ( uint16 * ) ( lemmas_ + offset + 2 + ( nchar << 1 ) );
+ }
-inline LemmaIdType UserDict::get_max_lemma_id() {
- // When a lemma is deleted, we don't not claim its id back for
- // simplicity and performance
- return start_id_ + dict_info_.lemma_count - 1;
-}
+ inline LemmaIdType UserDict::get_max_lemma_id() {
+ // When a lemma is deleted, we don't not claim its id back for
+ // simplicity and performance
+ return start_id_ + dict_info_.lemma_count - 1;
+ }
-inline bool UserDict::is_valid_lemma_id(LemmaIdType id) {
- if (id >= start_id_ && id <= get_max_lemma_id())
- return true;
- return false;
-}
+ inline bool UserDict::is_valid_lemma_id ( LemmaIdType id ) {
+ if ( id >= start_id_ && id <= get_max_lemma_id() )
+ { return true; }
+ return false;
+ }
-inline bool UserDict::is_valid_state() {
- if (state_ == USER_DICT_NONE)
- return false;
- return true;
-}
+ inline bool UserDict::is_valid_state() {
+ if ( state_ == USER_DICT_NONE )
+ { return false; }
+ return true;
+ }
-UserDict::UserDict()
- : start_id_(0),
- version_(0),
- lemmas_(NULL),
- offsets_(NULL),
- scores_(NULL),
- ids_(NULL),
+ UserDict::UserDict()
+ : start_id_ ( 0 ),
+ version_ ( 0 ),
+ lemmas_ ( NULL ),
+ offsets_ ( NULL ),
+ scores_ ( NULL ),
+ ids_ ( NULL ),
#ifdef ___PREDICT_ENABLED___
- predicts_(NULL),
+ predicts_ ( NULL ),
#endif
#ifdef ___SYNC_ENABLED___
- syncs_(NULL),
- sync_count_size_(0),
-#endif
- offsets_by_id_(NULL),
- lemma_count_left_(0),
- lemma_size_left_(0),
- dict_file_(NULL),
- state_(USER_DICT_NONE) {
- memset(&dict_info_, 0, sizeof(dict_info_));
- memset(&load_time_, 0, sizeof(load_time_));
+ syncs_ ( NULL ),
+ sync_count_size_ ( 0 ),
+#endif
+ offsets_by_id_ ( NULL ),
+ lemma_count_left_ ( 0 ),
+ lemma_size_left_ ( 0 ),
+ dict_file_ ( NULL ),
+ state_ ( USER_DICT_NONE ) {
+ memset ( &dict_info_, 0, sizeof ( dict_info_ ) );
+ memset ( &load_time_, 0, sizeof ( load_time_ ) );
#ifdef ___CACHE_ENABLED___
- cache_init();
+ cache_init();
#endif
-}
+ }
-UserDict::~UserDict() {
- close_dict();
-}
+ UserDict::~UserDict() {
+ close_dict();
+ }
-bool UserDict::load_dict(const char *file_name, LemmaIdType start_id,
- LemmaIdType end_id) {
+ bool UserDict::load_dict ( const char *file_name, LemmaIdType start_id,
+ LemmaIdType end_id ) {
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_BEGIN;
-#endif
- dict_file_ = strdup(file_name);
- if (!dict_file_)
- return false;
-
- start_id_ = start_id;
-
- if (false == validate(file_name) && false == reset(file_name)) {
- goto error;
- }
- if (false == load(file_name, start_id)) {
- goto error;
- }
-
- state_ = USER_DICT_SYNC;
-
- gettimeofday(&load_time_, NULL);
-
+ DEBUG_PERF_BEGIN;
+#endif
+ dict_file_ = strdup ( file_name );
+ if ( !dict_file_ )
+ { return false; }
+ start_id_ = start_id;
+ if ( false == validate ( file_name ) && false == reset ( file_name ) ) {
+ goto error;
+ }
+ if ( false == load ( file_name, start_id ) ) {
+ goto error;
+ }
+ state_ = USER_DICT_SYNC;
+ gettimeofday ( &load_time_, NULL );
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_END;
- LOGD_PERF("load_dict");
-#endif
- return true;
- error:
- free((void*)dict_file_);
- start_id_ = 0;
- return false;
-}
+ DEBUG_PERF_END;
+ LOGD_PERF ( "load_dict" );
+#endif
+ return true;
+ error:
+ free ( ( void * ) dict_file_ );
+ start_id_ = 0;
+ return false;
+ }
-bool UserDict::close_dict() {
- if (state_ == USER_DICT_NONE)
- return true;
- if (state_ == USER_DICT_SYNC)
- goto out;
-
- // If dictionary is written back by others,
- // we can not simply write back here
- // To do a safe flush, we have to discard all newly added
- // lemmas and try to reload dict file.
- pthread_mutex_lock(&g_mutex_);
- if (load_time_.tv_sec > g_last_update_.tv_sec ||
- (load_time_.tv_sec == g_last_update_.tv_sec &&
- load_time_.tv_usec > g_last_update_.tv_usec)) {
- write_back();
- gettimeofday(&g_last_update_, NULL);
- }
- pthread_mutex_unlock(&g_mutex_);
-
- out:
- free((void*)dict_file_);
- free(lemmas_);
- free(offsets_);
- free(offsets_by_id_);
- free(scores_);
- free(ids_);
+ bool UserDict::close_dict() {
+ if ( state_ == USER_DICT_NONE )
+ { return true; }
+ if ( state_ == USER_DICT_SYNC )
+ { goto out; }
+ // If dictionary is written back by others,
+ // we can not simply write back here
+ // To do a safe flush, we have to discard all newly added
+ // lemmas and try to reload dict file.
+ pthread_mutex_lock ( &g_mutex_ );
+ if ( load_time_.tv_sec > g_last_update_.tv_sec ||
+ ( load_time_.tv_sec == g_last_update_.tv_sec &&
+ load_time_.tv_usec > g_last_update_.tv_usec ) ) {
+ write_back();
+ gettimeofday ( &g_last_update_, NULL );
+ }
+ pthread_mutex_unlock ( &g_mutex_ );
+ out:
+ free ( ( void * ) dict_file_ );
+ free ( lemmas_ );
+ free ( offsets_ );
+ free ( offsets_by_id_ );
+ free ( scores_ );
+ free ( ids_ );
#ifdef ___PREDICT_ENABLED___
- free(predicts_);
+ free ( predicts_ );
#endif
-
- version_ = 0;
- dict_file_ = NULL;
- lemmas_ = NULL;
+ version_ = 0;
+ dict_file_ = NULL;
+ lemmas_ = NULL;
#ifdef ___SYNC_ENABLED___
- syncs_ = NULL;
- sync_count_size_ = 0;
+ syncs_ = NULL;
+ sync_count_size_ = 0;
#endif
- offsets_ = NULL;
- offsets_by_id_ = NULL;
- scores_ = NULL;
- ids_ = NULL;
+ offsets_ = NULL;
+ offsets_by_id_ = NULL;
+ scores_ = NULL;
+ ids_ = NULL;
#ifdef ___PREDICT_ENABLED___
- predicts_ = NULL;
+ predicts_ = NULL;
#endif
+ memset ( &dict_info_, 0, sizeof ( dict_info_ ) );
+ lemma_count_left_ = 0;
+ lemma_size_left_ = 0;
+ state_ = USER_DICT_NONE;
+ return true;
+ }
- memset(&dict_info_, 0, sizeof(dict_info_));
- lemma_count_left_ = 0;
- lemma_size_left_ = 0;
- state_ = USER_DICT_NONE;
-
- return true;
-}
-
-size_t UserDict::number_of_lemmas() {
- return dict_info_.lemma_count;
-}
-
-void UserDict::reset_milestones(uint16 from_step, MileStoneHandle from_handle) {
- return;
-}
-
-MileStoneHandle UserDict::extend_dict(MileStoneHandle from_handle,
- const DictExtPara *dep,
- LmaPsbItem *lpi_items,
- size_t lpi_max, size_t *lpi_num) {
- if (is_valid_state() == false)
- return 0;
+ size_t UserDict::number_of_lemmas() {
+ return dict_info_.lemma_count;
+ }
- bool need_extend = false;
+ void UserDict::reset_milestones ( uint16 from_step, MileStoneHandle from_handle ) {
+ return;
+ }
+ MileStoneHandle UserDict::extend_dict ( MileStoneHandle from_handle,
+ const DictExtPara *dep,
+ LmaPsbItem *lpi_items,
+ size_t lpi_max, size_t *lpi_num ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ bool need_extend = false;
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_BEGIN;
+ DEBUG_PERF_BEGIN;
#endif
- *lpi_num = _get_lpis(dep->splids, dep->splids_extended + 1,
- lpi_items, lpi_max, &need_extend);
+ *lpi_num = _get_lpis ( dep->splids, dep->splids_extended + 1,
+ lpi_items, lpi_max, &need_extend );
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_END;
- LOGD_PERF("extend_dict");
+ DEBUG_PERF_END;
+ LOGD_PERF ( "extend_dict" );
#endif
- return ((*lpi_num > 0 || need_extend) ? 1 : 0);
-}
-
-int UserDict::is_fuzzy_prefix_spell_id(
- const uint16 * id1, uint16 len1, const UserDictSearchable *searchable) {
- if (len1 < searchable->splids_len)
- return 0;
-
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- uint32 i = 0;
- for (i = 0; i < searchable->splids_len; i++) {
- const char py1 = *spl_trie.get_spelling_str(id1[i]);
- uint16 off = 8 * (i % 4);
- const char py2 = ((searchable->signature[i/4] & (0xff << off)) >> off);
- if (py1 == py2)
- continue;
- return 0;
- }
- return 1;
-}
-
-int UserDict::fuzzy_compare_spell_id(
- const uint16 * id1, uint16 len1, const UserDictSearchable *searchable) {
- if (len1 < searchable->splids_len)
- return -1;
- if (len1 > searchable->splids_len)
- return 1;
-
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- uint32 i = 0;
- for (i = 0; i < len1; i++) {
- const char py1 = *spl_trie.get_spelling_str(id1[i]);
- uint16 off = 8 * (i % 4);
- const char py2 = ((searchable->signature[i/4] & (0xff << off)) >> off);
- if (py1 == py2)
- continue;
- if (py1 > py2)
- return 1;
- return -1;
- }
- return 0;
-}
-
-bool UserDict::is_prefix_spell_id(
- const uint16 * fullids, uint16 fulllen,
- const UserDictSearchable *searchable) {
- if (fulllen < searchable->splids_len)
- return false;
-
- uint32 i = 0;
- for (; i < searchable->splids_len; i++) {
- uint16 start_id = searchable->splid_start[i];
- uint16 count = searchable->splid_count[i];
- if (fullids[i] >= start_id && fullids[i] < start_id + count)
- continue;
- else
- return false;
- }
- return true;
-}
-
-bool UserDict::equal_spell_id(
- const uint16 * fullids, uint16 fulllen,
- const UserDictSearchable *searchable) {
- if (fulllen != searchable->splids_len)
- return false;
-
- uint32 i = 0;
- for (; i < fulllen; i++) {
- uint16 start_id = searchable->splid_start[i];
- uint16 count = searchable->splid_count[i];
- if (fullids[i] >= start_id && fullids[i] < start_id + count)
- continue;
- else
- return false;
- }
- return true;
-}
-
-int32 UserDict::locate_first_in_offsets(const UserDictSearchable * searchable) {
- int32 begin = 0;
- int32 end = dict_info_.lemma_count - 1;
- int32 middle = -1;
+ return ( ( *lpi_num > 0 || need_extend ) ? 1 : 0 );
+ }
- int32 first_prefix = middle;
- int32 last_matched = middle;
+ int UserDict::is_fuzzy_prefix_spell_id (
+ const uint16 *id1, uint16 len1, const UserDictSearchable *searchable ) {
+ if ( len1 < searchable->splids_len )
+ { return 0; }
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ uint32 i = 0;
+ for ( i = 0; i < searchable->splids_len; i++ ) {
+ const char py1 = *spl_trie.get_spelling_str ( id1[i] );
+ uint16 off = 8 * ( i % 4 );
+ const char py2 = ( ( searchable->signature[i / 4] & ( 0xff << off ) ) >> off );
+ if ( py1 == py2 )
+ { continue; }
+ return 0;
+ }
+ return 1;
+ }
- while (begin <= end) {
- middle = (begin + end) >> 1;
- uint32 offset = offsets_[middle];
- uint8 nchar = get_lemma_nchar(offset);
- const uint16 * splids = get_lemma_spell_ids(offset);
- int cmp = fuzzy_compare_spell_id(splids, nchar, searchable);
- int pre = is_fuzzy_prefix_spell_id(splids, nchar, searchable);
+ int UserDict::fuzzy_compare_spell_id (
+ const uint16 *id1, uint16 len1, const UserDictSearchable *searchable ) {
+ if ( len1 < searchable->splids_len )
+ { return -1; }
+ if ( len1 > searchable->splids_len )
+ { return 1; }
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ uint32 i = 0;
+ for ( i = 0; i < len1; i++ ) {
+ const char py1 = *spl_trie.get_spelling_str ( id1[i] );
+ uint16 off = 8 * ( i % 4 );
+ const char py2 = ( ( searchable->signature[i / 4] & ( 0xff << off ) ) >> off );
+ if ( py1 == py2 )
+ { continue; }
+ if ( py1 > py2 )
+ { return 1; }
+ return -1;
+ }
+ return 0;
+ }
- if (pre)
- first_prefix = middle;
+ bool UserDict::is_prefix_spell_id (
+ const uint16 *fullids, uint16 fulllen,
+ const UserDictSearchable *searchable ) {
+ if ( fulllen < searchable->splids_len )
+ { return false; }
+ uint32 i = 0;
+ for ( ; i < searchable->splids_len; i++ ) {
+ uint16 start_id = searchable->splid_start[i];
+ uint16 count = searchable->splid_count[i];
+ if ( fullids[i] >= start_id && fullids[i] < start_id + count )
+ { continue; }
+ else
+ { return false; }
+ }
+ return true;
+ }
- if (cmp < 0) {
- begin = middle + 1;
- } else if (cmp > 0) {
- end = middle - 1;
- } else {
- end = middle - 1;
- last_matched = middle;
+ bool UserDict::equal_spell_id (
+ const uint16 *fullids, uint16 fulllen,
+ const UserDictSearchable *searchable ) {
+ if ( fulllen != searchable->splids_len )
+ { return false; }
+ uint32 i = 0;
+ for ( ; i < fulllen; i++ ) {
+ uint16 start_id = searchable->splid_start[i];
+ uint16 count = searchable->splid_count[i];
+ if ( fullids[i] >= start_id && fullids[i] < start_id + count )
+ { continue; }
+ else
+ { return false; }
+ }
+ return true;
}
- }
- return first_prefix;
-}
+ int32 UserDict::locate_first_in_offsets ( const UserDictSearchable *searchable ) {
+ int32 begin = 0;
+ int32 end = dict_info_.lemma_count - 1;
+ int32 middle = -1;
+ int32 first_prefix = middle;
+ int32 last_matched = middle;
+ while ( begin <= end ) {
+ middle = ( begin + end ) >> 1;
+ uint32 offset = offsets_[middle];
+ uint8 nchar = get_lemma_nchar ( offset );
+ const uint16 *splids = get_lemma_spell_ids ( offset );
+ int cmp = fuzzy_compare_spell_id ( splids, nchar, searchable );
+ int pre = is_fuzzy_prefix_spell_id ( splids, nchar, searchable );
+ if ( pre )
+ { first_prefix = middle; }
+ if ( cmp < 0 ) {
+ begin = middle + 1;
+ } else if ( cmp > 0 ) {
+ end = middle - 1;
+ } else {
+ end = middle - 1;
+ last_matched = middle;
+ }
+ }
+ return first_prefix;
+ }
-void UserDict::prepare_locate(UserDictSearchable *searchable,
- const uint16 *splid_str,
- uint16 splid_str_len) {
- searchable->splids_len = splid_str_len;
- memset(searchable->signature, 0, sizeof(searchable->signature));
-
- SpellingTrie &spl_trie = SpellingTrie::get_instance();
- uint32 i = 0;
- for (; i < splid_str_len; i++) {
- if (spl_trie.is_half_id(splid_str[i])) {
- searchable->splid_count[i] =
- spl_trie.half_to_full(splid_str[i],
- &(searchable->splid_start[i]));
- } else {
- searchable->splid_count[i] = 1;
- searchable->splid_start[i] = splid_str[i];
- }
- const unsigned char py = *spl_trie.get_spelling_str(splid_str[i]);
- searchable->signature[i>>2] |= (py << (8 * (i % 4)));
- }
-}
+ void UserDict::prepare_locate ( UserDictSearchable *searchable,
+ const uint16 *splid_str,
+ uint16 splid_str_len ) {
+ searchable->splids_len = splid_str_len;
+ memset ( searchable->signature, 0, sizeof ( searchable->signature ) );
+ SpellingTrie &spl_trie = SpellingTrie::get_instance();
+ uint32 i = 0;
+ for ( ; i < splid_str_len; i++ ) {
+ if ( spl_trie.is_half_id ( splid_str[i] ) ) {
+ searchable->splid_count[i] =
+ spl_trie.half_to_full ( splid_str[i],
+ & ( searchable->splid_start[i] ) );
+ } else {
+ searchable->splid_count[i] = 1;
+ searchable->splid_start[i] = splid_str[i];
+ }
+ const unsigned char py = *spl_trie.get_spelling_str ( splid_str[i] );
+ searchable->signature[i >> 2] |= ( py << ( 8 * ( i % 4 ) ) );
+ }
+ }
-size_t UserDict::get_lpis(const uint16 *splid_str, uint16 splid_str_len,
- LmaPsbItem *lpi_items, size_t lpi_max) {
- return _get_lpis(splid_str, splid_str_len, lpi_items, lpi_max, NULL);
-}
+ size_t UserDict::get_lpis ( const uint16 *splid_str, uint16 splid_str_len,
+ LmaPsbItem *lpi_items, size_t lpi_max ) {
+ return _get_lpis ( splid_str, splid_str_len, lpi_items, lpi_max, NULL );
+ }
-size_t UserDict::_get_lpis(const uint16 *splid_str,
- uint16 splid_str_len, LmaPsbItem *lpi_items,
- size_t lpi_max, bool * need_extend) {
- bool tmp_extend;
- if (!need_extend)
- need_extend = &tmp_extend;
-
- *need_extend = false;
-
- if (is_valid_state() == false)
- return 0;
- if (lpi_max <= 0)
- return 0;
-
- if (0 == pthread_mutex_trylock(&g_mutex_)) {
- if (load_time_.tv_sec < g_last_update_.tv_sec ||
- (load_time_.tv_sec == g_last_update_.tv_sec &&
- load_time_.tv_usec < g_last_update_.tv_usec)) {
- // Others updated disk file, have to reload
- pthread_mutex_unlock(&g_mutex_);
- flush_cache();
- } else {
- pthread_mutex_unlock(&g_mutex_);
- }
- } else {
- }
-
- UserDictSearchable searchable;
- prepare_locate(&searchable, splid_str, splid_str_len);
-
- uint32 max_off = dict_info_.lemma_count;
+ size_t UserDict::_get_lpis ( const uint16 *splid_str,
+ uint16 splid_str_len, LmaPsbItem *lpi_items,
+ size_t lpi_max, bool *need_extend ) {
+ bool tmp_extend;
+ if ( !need_extend )
+ { need_extend = &tmp_extend; }
+ *need_extend = false;
+ if ( is_valid_state() == false )
+ { return 0; }
+ if ( lpi_max <= 0 )
+ { return 0; }
+ if ( 0 == pthread_mutex_trylock ( &g_mutex_ ) ) {
+ if ( load_time_.tv_sec < g_last_update_.tv_sec ||
+ ( load_time_.tv_sec == g_last_update_.tv_sec &&
+ load_time_.tv_usec < g_last_update_.tv_usec ) ) {
+ // Others updated disk file, have to reload
+ pthread_mutex_unlock ( &g_mutex_ );
+ flush_cache();
+ } else {
+ pthread_mutex_unlock ( &g_mutex_ );
+ }
+ } else {
+ }
+ UserDictSearchable searchable;
+ prepare_locate ( &searchable, splid_str, splid_str_len );
+ uint32 max_off = dict_info_.lemma_count;
#ifdef ___CACHE_ENABLED___
- int32 middle;
- uint32 start, count;
- bool cached = cache_hit(&searchable, &start, &count);
- if (cached) {
- middle = start;
- max_off = start + count;
- } else {
- middle = locate_first_in_offsets(&searchable);
- start = middle;
- }
+ int32 middle;
+ uint32 start, count;
+ bool cached = cache_hit ( &searchable, &start, &count );
+ if ( cached ) {
+ middle = start;
+ max_off = start + count;
+ } else {
+ middle = locate_first_in_offsets ( &searchable );
+ start = middle;
+ }
#else
- int32 middle = locate_first_in_offsets(&searchable);
+ int32 middle = locate_first_in_offsets ( &searchable );
#endif
-
- if (middle == -1) {
+ if ( middle == -1 ) {
#ifdef ___CACHE_ENABLED___
- if (!cached)
- cache_push(USER_DICT_MISS_CACHE, &searchable, 0, 0);
-#endif
- return 0;
- }
-
- size_t lpi_current = 0;
-
- bool fuzzy_break = false;
- bool prefix_break = false;
- while ((size_t)middle < max_off && !fuzzy_break && !prefix_break) {
- if (lpi_current >= lpi_max)
- break;
- uint32 offset = offsets_[middle];
- // Ignore deleted lemmas
- if (offset & kUserDictOffsetFlagRemove) {
- middle++;
- continue;
- }
- uint8 nchar = get_lemma_nchar(offset);
- uint16 * splids = get_lemma_spell_ids(offset);
+ if ( !cached )
+ { cache_push ( USER_DICT_MISS_CACHE, &searchable, 0, 0 ); }
+#endif
+ return 0;
+ }
+ size_t lpi_current = 0;
+ bool fuzzy_break = false;
+ bool prefix_break = false;
+ while ( ( size_t ) middle < max_off && !fuzzy_break && !prefix_break ) {
+ if ( lpi_current >= lpi_max )
+ { break; }
+ uint32 offset = offsets_[middle];
+ // Ignore deleted lemmas
+ if ( offset & kUserDictOffsetFlagRemove ) {
+ middle++;
+ continue;
+ }
+ uint8 nchar = get_lemma_nchar ( offset );
+ uint16 *splids = get_lemma_spell_ids ( offset );
#ifdef ___CACHE_ENABLED___
- if (!cached && 0 != fuzzy_compare_spell_id(splids, nchar, &searchable)) {
+ if ( !cached && 0 != fuzzy_compare_spell_id ( splids, nchar, &searchable ) ) {
#else
- if (0 != fuzzy_compare_spell_id(splids, nchar, &searchable)) {
+ if ( 0 != fuzzy_compare_spell_id ( splids, nchar, &searchable ) ) {
+#endif
+ fuzzy_break = true;
+ }
+ if ( prefix_break == false ) {
+ if ( is_fuzzy_prefix_spell_id ( splids, nchar, &searchable ) ) {
+ if ( *need_extend == false &&
+ is_prefix_spell_id ( splids, nchar, &searchable ) ) {
+ *need_extend = true;
+ }
+ } else {
+ prefix_break = true;
+ }
+ }
+ if ( equal_spell_id ( splids, nchar, &searchable ) == true ) {
+ lpi_items[lpi_current].psb = translate_score ( scores_[middle] );
+ lpi_items[lpi_current].id = ids_[middle];
+ lpi_items[lpi_current].lma_len = nchar;
+ lpi_current++;
+ }
+ middle++;
+ }
+#ifdef ___CACHE_ENABLED___
+ if ( !cached ) {
+ count = middle - start;
+ cache_push ( USER_DICT_CACHE, &searchable, start, count );
+ }
#endif
- fuzzy_break = true;
+ return lpi_current;
}
- if (prefix_break == false) {
- if (is_fuzzy_prefix_spell_id(splids, nchar, &searchable)) {
- if (*need_extend == false &&
- is_prefix_spell_id(splids, nchar, &searchable)) {
- *need_extend = true;
+ uint16 UserDict::get_lemma_str ( LemmaIdType id_lemma, char16 *str_buf,
+ uint16 str_max ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ if ( is_valid_lemma_id ( id_lemma ) == false )
+ { return 0; }
+ uint32 offset = offsets_by_id_[id_lemma - start_id_];
+ uint8 nchar = get_lemma_nchar ( offset );
+ char16 *str = get_lemma_word ( offset );
+ uint16 m = nchar < str_max - 1 ? nchar : str_max - 1;
+ int i = 0;
+ for ( ; i < m; i++ ) {
+ str_buf[i] = str[i];
}
- } else {
- prefix_break = true;
- }
+ str_buf[i] = 0;
+ return m;
}
- if (equal_spell_id(splids, nchar, &searchable) == true) {
- lpi_items[lpi_current].psb = translate_score(scores_[middle]);
- lpi_items[lpi_current].id = ids_[middle];
- lpi_items[lpi_current].lma_len = nchar;
- lpi_current++;
+ uint16 UserDict::get_lemma_splids ( LemmaIdType id_lemma, uint16 *splids,
+ uint16 splids_max, bool arg_valid ) {
+ if ( is_valid_lemma_id ( id_lemma ) == false )
+ { return 0; }
+ uint32 offset = offsets_by_id_[id_lemma - start_id_];
+ uint8 nchar = get_lemma_nchar ( offset );
+ const uint16 *ids = get_lemma_spell_ids ( offset );
+ int i = 0;
+ for ( ; i < nchar && i < splids_max; i++ )
+ { splids[i] = ids[i]; }
+ return i;
}
- middle++;
- }
-
-#ifdef ___CACHE_ENABLED___
- if (!cached) {
- count = middle - start;
- cache_push(USER_DICT_CACHE, &searchable, start, count);
- }
-#endif
-
- return lpi_current;
-}
-
-uint16 UserDict::get_lemma_str(LemmaIdType id_lemma, char16* str_buf,
- uint16 str_max) {
- if (is_valid_state() == false)
- return 0;
- if (is_valid_lemma_id(id_lemma) == false)
- return 0;
- uint32 offset = offsets_by_id_[id_lemma - start_id_];
- uint8 nchar = get_lemma_nchar(offset);
- char16 * str = get_lemma_word(offset);
- uint16 m = nchar < str_max -1 ? nchar : str_max - 1;
- int i = 0;
- for (; i < m; i++) {
- str_buf[i] = str[i];
- }
- str_buf[i] = 0;
- return m;
-}
-uint16 UserDict::get_lemma_splids(LemmaIdType id_lemma, uint16 *splids,
- uint16 splids_max, bool arg_valid) {
- if (is_valid_lemma_id(id_lemma) == false)
- return 0;
- uint32 offset = offsets_by_id_[id_lemma - start_id_];
- uint8 nchar = get_lemma_nchar(offset);
- const uint16 * ids = get_lemma_spell_ids(offset);
- int i = 0;
- for (; i < nchar && i < splids_max; i++)
- splids[i] = ids[i];
- return i;
-}
-
-size_t UserDict::predict(const char16 last_hzs[], uint16 hzs_len,
- NPredictItem *npre_items, size_t npre_max,
- size_t b4_used) {
- uint32 new_added = 0;
+ size_t UserDict::predict ( const char16 last_hzs[], uint16 hzs_len,
+ NPredictItem *npre_items, size_t npre_max,
+ size_t b4_used ) {
+ uint32 new_added = 0;
#ifdef ___PREDICT_ENABLED___
- int32 end = dict_info_.lemma_count - 1;
- int j = locate_first_in_predicts((const uint16*)last_hzs, hzs_len);
- if (j == -1)
- return 0;
-
- while (j <= end) {
- uint32 offset = predicts_[j];
- // Ignore deleted lemmas
- if (offset & kUserDictOffsetFlagRemove) {
- j++;
- continue;
- }
- uint32 nchar = get_lemma_nchar(offset);
- uint16 * words = get_lemma_word(offset);
- uint16 * splids = get_lemma_spell_ids(offset);
-
- if (nchar <= hzs_len) {
- j++;
- continue;
- }
-
- if (memcmp(words, last_hzs, hzs_len << 1) == 0) {
- if (new_added >= npre_max) {
+ int32 end = dict_info_.lemma_count - 1;
+ int j = locate_first_in_predicts ( ( const uint16 * ) last_hzs, hzs_len );
+ if ( j == -1 )
+ { return 0; }
+ while ( j <= end ) {
+ uint32 offset = predicts_[j];
+ // Ignore deleted lemmas
+ if ( offset & kUserDictOffsetFlagRemove ) {
+ j++;
+ continue;
+ }
+ uint32 nchar = get_lemma_nchar ( offset );
+ uint16 *words = get_lemma_word ( offset );
+ uint16 *splids = get_lemma_spell_ids ( offset );
+ if ( nchar <= hzs_len ) {
+ j++;
+ continue;
+ }
+ if ( memcmp ( words, last_hzs, hzs_len << 1 ) == 0 ) {
+ if ( new_added >= npre_max ) {
+ return new_added;
+ }
+ uint32 cpy_len =
+ ( nchar < kMaxPredictSize ? ( nchar << 1 ) : ( kMaxPredictSize << 1 ) )
+ - ( hzs_len << 1 );
+ npre_items[new_added].his_len = hzs_len;
+ npre_items[new_added].psb = get_lemma_score ( words, splids, nchar );
+ memcpy ( npre_items[new_added].pre_hzs, words + hzs_len, cpy_len );
+ if ( ( cpy_len >> 1 ) < kMaxPredictSize ) {
+ npre_items[new_added].pre_hzs[cpy_len >> 1] = 0;
+ }
+ new_added++;
+ } else {
+ break;
+ }
+ j++;
+ }
+#endif
return new_added;
- }
- uint32 cpy_len =
- (nchar < kMaxPredictSize ? (nchar << 1) : (kMaxPredictSize << 1))
- - (hzs_len << 1);
- npre_items[new_added].his_len = hzs_len;
- npre_items[new_added].psb = get_lemma_score(words, splids, nchar);
- memcpy(npre_items[new_added].pre_hzs, words + hzs_len, cpy_len);
- if ((cpy_len >> 1) < kMaxPredictSize) {
- npre_items[new_added].pre_hzs[cpy_len >> 1] = 0;
- }
- new_added++;
- } else {
- break;
- }
-
- j++;
- }
-#endif
- return new_added;
-}
-
-int32 UserDict::locate_in_offsets(char16 lemma_str[], uint16 splid_str[],
- uint16 lemma_len) {
- int32 max_off = dict_info_.lemma_count;
+ }
- UserDictSearchable searchable;
- prepare_locate(&searchable, splid_str, lemma_len);
+ int32 UserDict::locate_in_offsets ( char16 lemma_str[], uint16 splid_str[],
+ uint16 lemma_len ) {
+ int32 max_off = dict_info_.lemma_count;
+ UserDictSearchable searchable;
+ prepare_locate ( &searchable, splid_str, lemma_len );
#ifdef ___CACHE_ENABLED___
- int32 off;
- uint32 start, count;
- bool cached = load_cache(&searchable, &start, &count);
- if (cached) {
- off = start;
- max_off = start + count;
- } else {
- off = locate_first_in_offsets(&searchable);
- start = off;
- }
+ int32 off;
+ uint32 start, count;
+ bool cached = load_cache ( &searchable, &start, &count );
+ if ( cached ) {
+ off = start;
+ max_off = start + count;
+ } else {
+ off = locate_first_in_offsets ( &searchable );
+ start = off;
+ }
#else
- int32 off = locate_first_in_offsets(&searchable);
+ int32 off = locate_first_in_offsets ( &searchable );
#endif
-
- if (off == -1) {
- return off;
- }
-
- while (off < max_off) {
- uint32 offset = offsets_[off];
- if (offset & kUserDictOffsetFlagRemove) {
- off++;
- continue;
- }
- uint16 * splids = get_lemma_spell_ids(offset);
+ if ( off == -1 ) {
+ return off;
+ }
+ while ( off < max_off ) {
+ uint32 offset = offsets_[off];
+ if ( offset & kUserDictOffsetFlagRemove ) {
+ off++;
+ continue;
+ }
+ uint16 *splids = get_lemma_spell_ids ( offset );
#ifdef ___CACHE_ENABLED___
- if (!cached && 0 != fuzzy_compare_spell_id(splids, lemma_len, &searchable))
- break;
+ if ( !cached && 0 != fuzzy_compare_spell_id ( splids, lemma_len, &searchable ) )
+ { break; }
#else
- if (0 != fuzzy_compare_spell_id(splids, lemma_len, &searchable))
- break;
-#endif
- if (equal_spell_id(splids, lemma_len, &searchable) == true) {
- uint16 * str = get_lemma_word(offset);
- uint32 i = 0;
- for (i = 0; i < lemma_len; i++) {
- if (str[i] == lemma_str[i])
- continue;
- break;
- }
- if (i < lemma_len) {
- off++;
- continue;
- }
+ if ( 0 != fuzzy_compare_spell_id ( splids, lemma_len, &searchable ) )
+ { break; }
+#endif
+ if ( equal_spell_id ( splids, lemma_len, &searchable ) == true ) {
+ uint16 *str = get_lemma_word ( offset );
+ uint32 i = 0;
+ for ( i = 0; i < lemma_len; i++ ) {
+ if ( str[i] == lemma_str[i] )
+ { continue; }
+ break;
+ }
+ if ( i < lemma_len ) {
+ off++;
+ continue;
+ }
#ifdef ___CACHE_ENABLED___
- // No need to save_cache here, since current function is invoked by
- // put_lemma. It's rarely possible for a user input same lemma twice.
- // That means first time user type a new lemma, it is newly added into
- // user dictionary, then it's possible that user type the same lemma
- // again.
- // Another reason save_cache can not be invoked here is this function
- // aborts when lemma is found, and it never knows the count.
-#endif
- return off;
+ // No need to save_cache here, since current function is invoked by
+ // put_lemma. It's rarely possible for a user input same lemma twice.
+ // That means first time user type a new lemma, it is newly added into
+ // user dictionary, then it's possible that user type the same lemma
+ // again.
+ // Another reason save_cache can not be invoked here is this function
+ // aborts when lemma is found, and it never knows the count.
+#endif
+ return off;
+ }
+ off++;
+ }
+ return -1;
}
- off++;
- }
-
- return -1;
-}
#ifdef ___PREDICT_ENABLED___
-uint32 UserDict::locate_where_to_insert_in_predicts(
- const uint16 * words, int lemma_len) {
- int32 begin = 0;
- int32 end = dict_info_.lemma_count - 1;
- int32 middle = end;
-
- uint32 last_matched = middle;
-
- while (begin <= end) {
- middle = (begin + end) >> 1;
- uint32 offset = offsets_[middle];
- uint8 nchar = get_lemma_nchar(offset);
- const uint16 * ws = get_lemma_word(offset);
-
- uint32 minl = nchar < lemma_len ? nchar : lemma_len;
- uint32 k = 0;
- int cmp = 0;
-
- for (; k < minl; k++) {
- if (ws[k] < words[k]) {
- cmp = -1;
- break;
- } else if (ws[k] > words[k]) {
- cmp = 1;
- break;
- }
- }
- if (cmp == 0) {
- if (nchar < lemma_len)
- cmp = -1;
- else if (nchar > lemma_len)
- cmp = 1;
- }
-
- if (cmp < 0) {
- begin = middle + 1;
- last_matched = middle;
- } else if (cmp > 0) {
- end = middle - 1;
- } else {
- end = middle - 1;
- last_matched = middle;
- }
- }
-
- return last_matched;
-}
+ uint32 UserDict::locate_where_to_insert_in_predicts (
+ const uint16 *words, int lemma_len ) {
+ int32 begin = 0;
+ int32 end = dict_info_.lemma_count - 1;
+ int32 middle = end;
+ uint32 last_matched = middle;
+ while ( begin <= end ) {
+ middle = ( begin + end ) >> 1;
+ uint32 offset = offsets_[middle];
+ uint8 nchar = get_lemma_nchar ( offset );
+ const uint16 *ws = get_lemma_word ( offset );
+ uint32 minl = nchar < lemma_len ? nchar : lemma_len;
+ uint32 k = 0;
+ int cmp = 0;
+ for ( ; k < minl; k++ ) {
+ if ( ws[k] < words[k] ) {
+ cmp = -1;
+ break;
+ } else if ( ws[k] > words[k] ) {
+ cmp = 1;
+ break;
+ }
+ }
+ if ( cmp == 0 ) {
+ if ( nchar < lemma_len )
+ { cmp = -1; }
+ else if ( nchar > lemma_len )
+ { cmp = 1; }
+ }
+ if ( cmp < 0 ) {
+ begin = middle + 1;
+ last_matched = middle;
+ } else if ( cmp > 0 ) {
+ end = middle - 1;
+ } else {
+ end = middle - 1;
+ last_matched = middle;
+ }
+ }
+ return last_matched;
+ }
-int32 UserDict::locate_first_in_predicts(const uint16 * words, int lemma_len) {
- int32 begin = 0;
- int32 end = dict_info_.lemma_count - 1;
- int32 middle = -1;
-
- int32 last_matched = middle;
-
- while (begin <= end) {
- middle = (begin + end) >> 1;
- uint32 offset = offsets_[middle];
- uint8 nchar = get_lemma_nchar(offset);
- const uint16 * ws = get_lemma_word(offset);
-
- uint32 minl = nchar < lemma_len ? nchar : lemma_len;
- uint32 k = 0;
- int cmp = 0;
-
- for (; k < minl; k++) {
- if (ws[k] < words[k]) {
- cmp = -1;
- break;
- } else if (ws[k] > words[k]) {
- cmp = 1;
- break;
- }
- }
- if (cmp == 0) {
- if (nchar >= lemma_len)
- last_matched = middle;
- if (nchar < lemma_len)
- cmp = -1;
- else if (nchar > lemma_len)
- cmp = 1;
- }
-
- if (cmp < 0) {
- begin = middle + 1;
- } else if (cmp > 0) {
- end = middle - 1;
- } else {
- end = middle - 1;
- }
- }
-
- return last_matched;
-}
+ int32 UserDict::locate_first_in_predicts ( const uint16 *words, int lemma_len ) {
+ int32 begin = 0;
+ int32 end = dict_info_.lemma_count - 1;
+ int32 middle = -1;
+ int32 last_matched = middle;
+ while ( begin <= end ) {
+ middle = ( begin + end ) >> 1;
+ uint32 offset = offsets_[middle];
+ uint8 nchar = get_lemma_nchar ( offset );
+ const uint16 *ws = get_lemma_word ( offset );
+ uint32 minl = nchar < lemma_len ? nchar : lemma_len;
+ uint32 k = 0;
+ int cmp = 0;
+ for ( ; k < minl; k++ ) {
+ if ( ws[k] < words[k] ) {
+ cmp = -1;
+ break;
+ } else if ( ws[k] > words[k] ) {
+ cmp = 1;
+ break;
+ }
+ }
+ if ( cmp == 0 ) {
+ if ( nchar >= lemma_len )
+ { last_matched = middle; }
+ if ( nchar < lemma_len )
+ { cmp = -1; }
+ else if ( nchar > lemma_len )
+ { cmp = 1; }
+ }
+ if ( cmp < 0 ) {
+ begin = middle + 1;
+ } else if ( cmp > 0 ) {
+ end = middle - 1;
+ } else {
+ end = middle - 1;
+ }
+ }
+ return last_matched;
+ }
#endif
-LemmaIdType UserDict::get_lemma_id(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len) {
- int32 off = locate_in_offsets(lemma_str, splids, lemma_len);
- if (off == -1) {
- return 0;
- }
-
- return ids_[off];
-}
-
-LmaScoreType UserDict::get_lemma_score(LemmaIdType lemma_id) {
- if (is_valid_state() == false)
- return 0;
- if (is_valid_lemma_id(lemma_id) == false)
- return 0;
-
- return translate_score(_get_lemma_score(lemma_id));
-}
-
-LmaScoreType UserDict::get_lemma_score(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len) {
- if (is_valid_state() == false)
- return 0;
- return translate_score(_get_lemma_score(lemma_str, splids, lemma_len));
-}
-
-int UserDict::_get_lemma_score(LemmaIdType lemma_id) {
- if (is_valid_state() == false)
- return 0;
- if (is_valid_lemma_id(lemma_id) == false)
- return 0;
-
- uint32 offset = offsets_by_id_[lemma_id - start_id_];
-
- uint32 nchar = get_lemma_nchar(offset);
- uint16 * spl = get_lemma_spell_ids(offset);
- uint16 * wrd = get_lemma_word(offset);
-
- int32 off = locate_in_offsets(wrd, spl, nchar);
- if (off == -1) {
- return 0;
- }
+ LemmaIdType UserDict::get_lemma_id ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len ) {
+ int32 off = locate_in_offsets ( lemma_str, splids, lemma_len );
+ if ( off == -1 ) {
+ return 0;
+ }
+ return ids_[off];
+ }
- return scores_[off];
-}
+ LmaScoreType UserDict::get_lemma_score ( LemmaIdType lemma_id ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ if ( is_valid_lemma_id ( lemma_id ) == false )
+ { return 0; }
+ return translate_score ( _get_lemma_score ( lemma_id ) );
+ }
-int UserDict::_get_lemma_score(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len) {
- if (is_valid_state() == false)
- return 0;
+ LmaScoreType UserDict::get_lemma_score ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ return translate_score ( _get_lemma_score ( lemma_str, splids, lemma_len ) );
+ }
- int32 off = locate_in_offsets(lemma_str, splids, lemma_len);
- if (off == -1) {
- return 0;
- }
+ int UserDict::_get_lemma_score ( LemmaIdType lemma_id ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ if ( is_valid_lemma_id ( lemma_id ) == false )
+ { return 0; }
+ uint32 offset = offsets_by_id_[lemma_id - start_id_];
+ uint32 nchar = get_lemma_nchar ( offset );
+ uint16 *spl = get_lemma_spell_ids ( offset );
+ uint16 *wrd = get_lemma_word ( offset );
+ int32 off = locate_in_offsets ( wrd, spl, nchar );
+ if ( off == -1 ) {
+ return 0;
+ }
+ return scores_[off];
+ }
- return scores_[off];
-}
+ int UserDict::_get_lemma_score ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ int32 off = locate_in_offsets ( lemma_str, splids, lemma_len );
+ if ( off == -1 ) {
+ return 0;
+ }
+ return scores_[off];
+ }
#ifdef ___SYNC_ENABLED___
-void UserDict::remove_lemma_from_sync_list(uint32 offset) {
- offset &= kUserDictOffsetMask;
- uint32 i = 0;
- for (; i < dict_info_.sync_count; i++) {
- unsigned int off = (syncs_[i] & kUserDictOffsetMask);
- if (off == offset)
- break;
- }
- if (i < dict_info_.sync_count) {
- syncs_[i] = syncs_[dict_info_.sync_count - 1];
- dict_info_.sync_count--;
- }
-}
+ void UserDict::remove_lemma_from_sync_list ( uint32 offset ) {
+ offset &= kUserDictOffsetMask;
+ uint32 i = 0;
+ for ( ; i < dict_info_.sync_count; i++ ) {
+ unsigned int off = ( syncs_[i] & kUserDictOffsetMask );
+ if ( off == offset )
+ { break; }
+ }
+ if ( i < dict_info_.sync_count ) {
+ syncs_[i] = syncs_[dict_info_.sync_count - 1];
+ dict_info_.sync_count--;
+ }
+ }
#endif
#ifdef ___PREDICT_ENABLED___
-void UserDict::remove_lemma_from_predict_list(uint32 offset) {
- offset &= kUserDictOffsetMask;
- uint32 i = 0;
- for (; i < dict_info_.lemma_count; i++) {
- unsigned int off = (predicts_[i] & kUserDictOffsetMask);
- if (off == offset) {
- predicts_[i] |= kUserDictOffsetFlagRemove;
- break;
- }
- }
-}
+ void UserDict::remove_lemma_from_predict_list ( uint32 offset ) {
+ offset &= kUserDictOffsetMask;
+ uint32 i = 0;
+ for ( ; i < dict_info_.lemma_count; i++ ) {
+ unsigned int off = ( predicts_[i] & kUserDictOffsetMask );
+ if ( off == offset ) {
+ predicts_[i] |= kUserDictOffsetFlagRemove;
+ break;
+ }
+ }
+ }
#endif
-bool UserDict::remove_lemma_by_offset_index(int offset_index) {
- if (is_valid_state() == false)
- return 0;
-
- int32 off = offset_index;
- if (off == -1) {
- return false;
- }
-
- uint32 offset = offsets_[off];
- uint32 nchar = get_lemma_nchar(offset);
-
- offsets_[off] |= kUserDictOffsetFlagRemove;
-
+ bool UserDict::remove_lemma_by_offset_index ( int offset_index ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ int32 off = offset_index;
+ if ( off == -1 ) {
+ return false;
+ }
+ uint32 offset = offsets_[off];
+ uint32 nchar = get_lemma_nchar ( offset );
+ offsets_[off] |= kUserDictOffsetFlagRemove;
#ifdef ___SYNC_ENABLED___
- // Remove corresponding sync item
- remove_lemma_from_sync_list(offset);
+ // Remove corresponding sync item
+ remove_lemma_from_sync_list ( offset );
#endif
-
#ifdef ___PREDICT_ENABLED___
- remove_lemma_from_predict_list(offset);
+ remove_lemma_from_predict_list ( offset );
#endif
- dict_info_.free_count++;
- dict_info_.free_size += (2 + (nchar << 2));
-
- if (state_ < USER_DICT_OFFSET_DIRTY)
- state_ = USER_DICT_OFFSET_DIRTY;
- return true;
-}
-
-bool UserDict::remove_lemma(LemmaIdType lemma_id) {
- if (is_valid_state() == false)
- return 0;
- if (is_valid_lemma_id(lemma_id) == false)
- return false;
- uint32 offset = offsets_by_id_[lemma_id - start_id_];
-
- uint32 nchar = get_lemma_nchar(offset);
- uint16 * spl = get_lemma_spell_ids(offset);
- uint16 * wrd = get_lemma_word(offset);
-
- int32 off = locate_in_offsets(wrd, spl, nchar);
+ dict_info_.free_count++;
+ dict_info_.free_size += ( 2 + ( nchar << 2 ) );
+ if ( state_ < USER_DICT_OFFSET_DIRTY )
+ { state_ = USER_DICT_OFFSET_DIRTY; }
+ return true;
+ }
- return remove_lemma_by_offset_index(off);
-}
+ bool UserDict::remove_lemma ( LemmaIdType lemma_id ) {
+ if ( is_valid_state() == false )
+ { return 0; }
+ if ( is_valid_lemma_id ( lemma_id ) == false )
+ { return false; }
+ uint32 offset = offsets_by_id_[lemma_id - start_id_];
+ uint32 nchar = get_lemma_nchar ( offset );
+ uint16 *spl = get_lemma_spell_ids ( offset );
+ uint16 *wrd = get_lemma_word ( offset );
+ int32 off = locate_in_offsets ( wrd, spl, nchar );
+ return remove_lemma_by_offset_index ( off );
+ }
-void UserDict::flush_cache() {
- LemmaIdType start_id = start_id_;
- const char * file = strdup(dict_file_);
- if (!file)
- return;
- close_dict();
- load_dict(file, start_id, kUserDictIdEnd);
- free((void*)file);
+ void UserDict::flush_cache() {
+ LemmaIdType start_id = start_id_;
+ const char *file = strdup ( dict_file_ );
+ if ( !file )
+ { return; }
+ close_dict();
+ load_dict ( file, start_id, kUserDictIdEnd );
+ free ( ( void * ) file );
#ifdef ___CACHE_ENABLED___
- cache_init();
+ cache_init();
#endif
- return;
-}
+ return;
+ }
-bool UserDict::reset(const char *file) {
- FILE *fp = fopen(file, "w+");
- if (!fp) {
- return false;
- }
- uint32 version = kUserDictVersion;
- size_t wred = fwrite(&version, 1, 4, fp);
- UserDictInfo info;
- memset(&info, 0, sizeof(info));
- // By default, no limitation for lemma count and size
- // thereby, reclaim_ratio is never used
- wred += fwrite(&info, 1, sizeof(info), fp);
- if (wred != sizeof(info) + sizeof(version)) {
- fclose(fp);
- unlink(file);
- return false;
- }
- fclose(fp);
- return true;
-}
+ bool UserDict::reset ( const char *file ) {
+ FILE *fp = fopen ( file, "w+" );
+ if ( !fp ) {
+ return false;
+ }
+ uint32 version = kUserDictVersion;
+ size_t wred = fwrite ( &version, 1, 4, fp );
+ UserDictInfo info;
+ memset ( &info, 0, sizeof ( info ) );
+ // By default, no limitation for lemma count and size
+ // thereby, reclaim_ratio is never used
+ wred += fwrite ( &info, 1, sizeof ( info ), fp );
+ if ( wred != sizeof ( info ) + sizeof ( version ) ) {
+ fclose ( fp );
+ unlink ( file );
+ return false;
+ }
+ fclose ( fp );
+ return true;
+ }
-bool UserDict::validate(const char *file) {
- // b is ignored in POSIX compatible os including Linux
- // while b is important flag for Windows to specify binary mode
- FILE *fp = fopen(file, "rb");
- if (!fp) {
- return false;
- }
-
- size_t size;
- size_t readed;
- uint32 version;
- UserDictInfo dict_info;
-
- // validate
- int err = fseek(fp, 0, SEEK_END);
- if (err) {
- goto error;
- }
-
- size = ftell(fp);
- if (size < 4 + sizeof(dict_info)) {
- goto error;
- }
-
- err = fseek(fp, 0, SEEK_SET);
- if (err) {
- goto error;
- }
-
- readed = fread(&version, 1, sizeof(version), fp);
- if (readed < sizeof(version)) {
- goto error;
- }
- if (version != kUserDictVersion) {
- goto error;
- }
-
- err = fseek(fp, -1 * sizeof(dict_info), SEEK_END);
- if (err) {
- goto error;
- }
-
- readed = fread(&dict_info, 1, sizeof(dict_info), fp);
- if (readed != sizeof(dict_info)) {
- goto error;
- }
-
- if (size != get_dict_file_size(&dict_info)) {
- goto error;
- }
-
- fclose(fp);
- return true;
-
- error:
- fclose(fp);
- return false;
-}
+ bool UserDict::validate ( const char *file ) {
+ // b is ignored in POSIX compatible os including Linux
+ // while b is important flag for Windows to specify binary mode
+ FILE *fp = fopen ( file, "rb" );
+ if ( !fp ) {
+ return false;
+ }
+ size_t size;
+ size_t readed;
+ uint32 version;
+ UserDictInfo dict_info;
+ // validate
+ int err = fseek ( fp, 0, SEEK_END );
+ if ( err ) {
+ goto error;
+ }
+ size = ftell ( fp );
+ if ( size < 4 + sizeof ( dict_info ) ) {
+ goto error;
+ }
+ err = fseek ( fp, 0, SEEK_SET );
+ if ( err ) {
+ goto error;
+ }
+ readed = fread ( &version, 1, sizeof ( version ), fp );
+ if ( readed < sizeof ( version ) ) {
+ goto error;
+ }
+ if ( version != kUserDictVersion ) {
+ goto error;
+ }
+ err = fseek ( fp, -1 * sizeof ( dict_info ), SEEK_END );
+ if ( err ) {
+ goto error;
+ }
+ readed = fread ( &dict_info, 1, sizeof ( dict_info ), fp );
+ if ( readed != sizeof ( dict_info ) ) {
+ goto error;
+ }
+ if ( size != get_dict_file_size ( &dict_info ) ) {
+ goto error;
+ }
+ fclose ( fp );
+ return true;
+ error:
+ fclose ( fp );
+ return false;
+ }
-bool UserDict::load(const char *file, LemmaIdType start_id) {
- if (0 != pthread_mutex_trylock(&g_mutex_)) {
- return false;
- }
- // b is ignored in POSIX compatible os including Linux
- // while b is important flag for Windows to specify binary mode
- FILE *fp = fopen(file, "rb");
- if (!fp) {
- pthread_mutex_unlock(&g_mutex_);
- return false;
- }
-
- size_t readed, toread;
- UserDictInfo dict_info;
- uint8 *lemmas = NULL;
- uint32 *offsets = NULL;
+ bool UserDict::load ( const char *file, LemmaIdType start_id ) {
+ if ( 0 != pthread_mutex_trylock ( &g_mutex_ ) ) {
+ return false;
+ }
+ // b is ignored in POSIX compatible os including Linux
+ // while b is important flag for Windows to specify binary mode
+ FILE *fp = fopen ( file, "rb" );
+ if ( !fp ) {
+ pthread_mutex_unlock ( &g_mutex_ );
+ return false;
+ }
+ size_t readed, toread;
+ UserDictInfo dict_info;
+ uint8 *lemmas = NULL;
+ uint32 *offsets = NULL;
#ifdef ___SYNC_ENABLED___
- uint32 *syncs = NULL;
+ uint32 *syncs = NULL;
#endif
- uint32 *scores = NULL;
- uint32 *ids = NULL;
- uint32 *offsets_by_id = NULL;
+ uint32 *scores = NULL;
+ uint32 *ids = NULL;
+ uint32 *offsets_by_id = NULL;
#ifdef ___PREDICT_ENABLED___
- uint32 *predicts = NULL;
-#endif
- size_t i;
- int err;
-
- err = fseek(fp, -1 * sizeof(dict_info), SEEK_END);
- if (err) goto error;
-
- readed = fread(&dict_info, 1, sizeof(dict_info), fp);
- if (readed != sizeof(dict_info)) goto error;
-
- lemmas = (uint8 *)malloc(
- dict_info.lemma_size +
- (kUserDictPreAlloc * (2 + (kUserDictAverageNchar << 2))));
-
- if (!lemmas) goto error;
-
- offsets = (uint32 *)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2);
- if (!offsets) goto error;
-
+ uint32 *predicts = NULL;
+#endif
+ size_t i;
+ int err;
+ err = fseek ( fp, -1 * sizeof ( dict_info ), SEEK_END );
+ if ( err ) { goto error; }
+ readed = fread ( &dict_info, 1, sizeof ( dict_info ), fp );
+ if ( readed != sizeof ( dict_info ) ) { goto error; }
+ lemmas = ( uint8 * ) malloc (
+ dict_info.lemma_size +
+ ( kUserDictPreAlloc * ( 2 + ( kUserDictAverageNchar << 2 ) ) ) );
+ if ( !lemmas ) { goto error; }
+ offsets = ( uint32 * ) malloc ( ( dict_info.lemma_count + kUserDictPreAlloc ) << 2 );
+ if ( !offsets ) { goto error; }
#ifdef ___PREDICT_ENABLED___
- predicts = (uint32 *)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2);
- if (!predicts) goto error;
+ predicts = ( uint32 * ) malloc ( ( dict_info.lemma_count + kUserDictPreAlloc ) << 2 );
+ if ( !predicts ) { goto error; }
#endif
-
#ifdef ___SYNC_ENABLED___
- syncs = (uint32 *)malloc((dict_info.sync_count + kUserDictPreAlloc) << 2);
- if (!syncs) goto error;
-#endif
-
- scores = (uint32 *)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2);
- if (!scores) goto error;
-
- ids = (uint32 *)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2);
- if (!ids) goto error;
-
- offsets_by_id = (uint32 *)malloc(
- (dict_info.lemma_count + kUserDictPreAlloc) << 2);
- if (!offsets_by_id) goto error;
-
- err = fseek(fp, 4, SEEK_SET);
- if (err) goto error;
-
- readed = 0;
- while (readed < dict_info.lemma_size && !ferror(fp) && !feof(fp)) {
- readed += fread(lemmas + readed, 1, dict_info.lemma_size - readed, fp);
- }
- if (readed < dict_info.lemma_size)
- goto error;
-
- toread = (dict_info.lemma_count << 2);
- readed = 0;
- while (readed < toread && !ferror(fp) && !feof(fp)) {
- readed += fread((((uint8*)offsets) + readed), 1, toread - readed, fp);
- }
- if (readed < toread)
- goto error;
-
+ syncs = ( uint32 * ) malloc ( ( dict_info.sync_count + kUserDictPreAlloc ) << 2 );
+ if ( !syncs ) { goto error; }
+#endif
+ scores = ( uint32 * ) malloc ( ( dict_info.lemma_count + kUserDictPreAlloc ) << 2 );
+ if ( !scores ) { goto error; }
+ ids = ( uint32 * ) malloc ( ( dict_info.lemma_count + kUserDictPreAlloc ) << 2 );
+ if ( !ids ) { goto error; }
+ offsets_by_id = ( uint32 * ) malloc (
+ ( dict_info.lemma_count + kUserDictPreAlloc ) << 2 );
+ if ( !offsets_by_id ) { goto error; }
+ err = fseek ( fp, 4, SEEK_SET );
+ if ( err ) { goto error; }
+ readed = 0;
+ while ( readed < dict_info.lemma_size && !ferror ( fp ) && !feof ( fp ) ) {
+ readed += fread ( lemmas + readed, 1, dict_info.lemma_size - readed, fp );
+ }
+ if ( readed < dict_info.lemma_size )
+ { goto error; }
+ toread = ( dict_info.lemma_count << 2 );
+ readed = 0;
+ while ( readed < toread && !ferror ( fp ) && !feof ( fp ) ) {
+ readed += fread ( ( ( ( uint8 * ) offsets ) + readed ), 1, toread - readed, fp );
+ }
+ if ( readed < toread )
+ { goto error; }
#ifdef ___PREDICT_ENABLED___
- toread = (dict_info.lemma_count << 2);
- readed = 0;
- while (readed < toread && !ferror(fp) && !feof(fp)) {
- readed += fread((((uint8*)predicts) + readed), 1, toread - readed, fp);
- }
- if (readed < toread)
- goto error;
-#endif
-
- readed = 0;
- while (readed < toread && !ferror(fp) && !feof(fp)) {
- readed += fread((((uint8*)scores) + readed), 1, toread - readed, fp);
- }
- if (readed < toread)
- goto error;
-
+ toread = ( dict_info.lemma_count << 2 );
+ readed = 0;
+ while ( readed < toread && !ferror ( fp ) && !feof ( fp ) ) {
+ readed += fread ( ( ( ( uint8 * ) predicts ) + readed ), 1, toread - readed, fp );
+ }
+ if ( readed < toread )
+ { goto error; }
+#endif
+ readed = 0;
+ while ( readed < toread && !ferror ( fp ) && !feof ( fp ) ) {
+ readed += fread ( ( ( ( uint8 * ) scores ) + readed ), 1, toread - readed, fp );
+ }
+ if ( readed < toread )
+ { goto error; }
#ifdef ___SYNC_ENABLED___
- toread = (dict_info.sync_count << 2);
- readed = 0;
- while (readed < toread && !ferror(fp) && !feof(fp)) {
- readed += fread((((uint8*)syncs) + readed), 1, toread - readed, fp);
- }
- if (readed < toread)
- goto error;
-#endif
-
- for (i = 0; i < dict_info.lemma_count; i++) {
- ids[i] = start_id + i;
- offsets_by_id[i] = offsets[i];
- }
-
- lemmas_ = lemmas;
- offsets_ = offsets;
+ toread = ( dict_info.sync_count << 2 );
+ readed = 0;
+ while ( readed < toread && !ferror ( fp ) && !feof ( fp ) ) {
+ readed += fread ( ( ( ( uint8 * ) syncs ) + readed ), 1, toread - readed, fp );
+ }
+ if ( readed < toread )
+ { goto error; }
+#endif
+ for ( i = 0; i < dict_info.lemma_count; i++ ) {
+ ids[i] = start_id + i;
+ offsets_by_id[i] = offsets[i];
+ }
+ lemmas_ = lemmas;
+ offsets_ = offsets;
#ifdef ___SYNC_ENABLED___
- syncs_ = syncs;
- sync_count_size_ = dict_info.sync_count + kUserDictPreAlloc;
+ syncs_ = syncs;
+ sync_count_size_ = dict_info.sync_count + kUserDictPreAlloc;
#endif
- offsets_by_id_ = offsets_by_id;
- scores_ = scores;
- ids_ = ids;
+ offsets_by_id_ = offsets_by_id;
+ scores_ = scores;
+ ids_ = ids;
#ifdef ___PREDICT_ENABLED___
- predicts_ = predicts;
-#endif
- lemma_count_left_ = kUserDictPreAlloc;
- lemma_size_left_ = kUserDictPreAlloc * (2 + (kUserDictAverageNchar << 2));
- memcpy(&dict_info_, &dict_info, sizeof(dict_info));
- state_ = USER_DICT_SYNC;
-
- fclose(fp);
-
- pthread_mutex_unlock(&g_mutex_);
- return true;
-
- error:
- if (lemmas) free(lemmas);
- if (offsets) free(offsets);
+ predicts_ = predicts;
+#endif
+ lemma_count_left_ = kUserDictPreAlloc;
+ lemma_size_left_ = kUserDictPreAlloc * ( 2 + ( kUserDictAverageNchar << 2 ) );
+ memcpy ( &dict_info_, &dict_info, sizeof ( dict_info ) );
+ state_ = USER_DICT_SYNC;
+ fclose ( fp );
+ pthread_mutex_unlock ( &g_mutex_ );
+ return true;
+ error:
+ if ( lemmas ) { free ( lemmas ); }
+ if ( offsets ) { free ( offsets ); }
#ifdef ___SYNC_ENABLED___
- if (syncs) free(syncs);
+ if ( syncs ) { free ( syncs ); }
#endif
- if (scores) free(scores);
- if (ids) free(ids);
- if (offsets_by_id) free(offsets_by_id);
+ if ( scores ) { free ( scores ); }
+ if ( ids ) { free ( ids ); }
+ if ( offsets_by_id ) { free ( offsets_by_id ); }
#ifdef ___PREDICT_ENABLED___
- if (predicts) free(predicts);
+ if ( predicts ) { free ( predicts ); }
#endif
- fclose(fp);
- pthread_mutex_unlock(&g_mutex_);
- return false;
-}
+ fclose ( fp );
+ pthread_mutex_unlock ( &g_mutex_ );
+ return false;
+ }
-void UserDict::write_back() {
- // XXX write back is only allowed from close_dict due to thread-safe sake
- if (state_ == USER_DICT_NONE || state_ == USER_DICT_SYNC)
- return;
- int fd = open(dict_file_, O_WRONLY);
- if (fd == -1)
- return;
- switch (state_) {
- case USER_DICT_DEFRAGMENTED:
- write_back_all(fd);
- break;
- case USER_DICT_LEMMA_DIRTY:
- write_back_lemma(fd);
- break;
- case USER_DICT_OFFSET_DIRTY:
- write_back_offset(fd);
- break;
- case USER_DICT_SCORE_DIRTY:
- write_back_score(fd);
- break;
+ void UserDict::write_back() {
+ // XXX write back is only allowed from close_dict due to thread-safe sake
+ if ( state_ == USER_DICT_NONE || state_ == USER_DICT_SYNC )
+ { return; }
+ int fd = open ( dict_file_, O_WRONLY );
+ if ( fd == -1 )
+ { return; }
+ switch ( state_ ) {
+ case USER_DICT_DEFRAGMENTED:
+ write_back_all ( fd );
+ break;
+ case USER_DICT_LEMMA_DIRTY:
+ write_back_lemma ( fd );
+ break;
+ case USER_DICT_OFFSET_DIRTY:
+ write_back_offset ( fd );
+ break;
+ case USER_DICT_SCORE_DIRTY:
+ write_back_score ( fd );
+ break;
#ifdef ___SYNC_ENABLED___
- case USER_DICT_SYNC_DIRTY:
- write_back_sync(fd);
- break;
-#endif
- default:
- break;
- }
- // It seems truncate is not need on Linux, Windows except Mac
- // I am doing it here anyway for safety.
- off_t cur = lseek(fd, 0, SEEK_CUR);
- ftruncate(fd, cur);
- close(fd);
- state_ = USER_DICT_SYNC;
-}
+ case USER_DICT_SYNC_DIRTY:
+ write_back_sync ( fd );
+ break;
+#endif
+ default:
+ break;
+ }
+ // It seems truncate is not need on Linux, Windows except Mac
+ // I am doing it here anyway for safety.
+ off_t cur = lseek ( fd, 0, SEEK_CUR );
+ ftruncate ( fd, cur );
+ close ( fd );
+ state_ = USER_DICT_SYNC;
+ }
#ifdef ___SYNC_ENABLED___
-void UserDict::write_back_sync(int fd) {
- int err = lseek(fd, 4 + dict_info_.lemma_size
- + (dict_info_.lemma_count << 3)
+ void UserDict::write_back_sync ( int fd ) {
+ int err = lseek ( fd, 4 + dict_info_.lemma_size
+ + ( dict_info_.lemma_count << 3 )
#ifdef ___PREDICT_ENABLED___
- + (dict_info_.lemma_count << 2)
+ + ( dict_info_.lemma_count << 2 )
#endif
- , SEEK_SET);
- if (err == -1)
- return;
- write(fd, syncs_, dict_info_.sync_count << 2);
- write(fd, &dict_info_, sizeof(dict_info_));
-}
+ , SEEK_SET );
+ if ( err == -1 )
+ { return; }
+ write ( fd, syncs_, dict_info_.sync_count << 2 );
+ write ( fd, &dict_info_, sizeof ( dict_info_ ) );
+ }
#endif
-void UserDict::write_back_offset(int fd) {
- int err = lseek(fd, 4 + dict_info_.lemma_size, SEEK_SET);
- if (err == -1)
- return;
- write(fd, offsets_, dict_info_.lemma_count << 2);
+ void UserDict::write_back_offset ( int fd ) {
+ int err = lseek ( fd, 4 + dict_info_.lemma_size, SEEK_SET );
+ if ( err == -1 )
+ { return; }
+ write ( fd, offsets_, dict_info_.lemma_count << 2 );
#ifdef ___PREDICT_ENABLED___
- write(fd, predicts_, dict_info_.lemma_count << 2);
+ write ( fd, predicts_, dict_info_.lemma_count << 2 );
#endif
- write(fd, scores_, dict_info_.lemma_count << 2);
+ write ( fd, scores_, dict_info_.lemma_count << 2 );
#ifdef ___SYNC_ENABLED___
- write(fd, syncs_, dict_info_.sync_count << 2);
+ write ( fd, syncs_, dict_info_.sync_count << 2 );
#endif
- write(fd, &dict_info_, sizeof(dict_info_));
-}
+ write ( fd, &dict_info_, sizeof ( dict_info_ ) );
+ }
-void UserDict::write_back_score(int fd) {
- int err = lseek(fd, 4 + dict_info_.lemma_size
- + (dict_info_.lemma_count << 2)
+ void UserDict::write_back_score ( int fd ) {
+ int err = lseek ( fd, 4 + dict_info_.lemma_size
+ + ( dict_info_.lemma_count << 2 )
#ifdef ___PREDICT_ENABLED___
- + (dict_info_.lemma_count << 2)
+ + ( dict_info_.lemma_count << 2 )
#endif
- , SEEK_SET);
- if (err == -1)
- return;
- write(fd, scores_, dict_info_.lemma_count << 2);
+ , SEEK_SET );
+ if ( err == -1 )
+ { return; }
+ write ( fd, scores_, dict_info_.lemma_count << 2 );
#ifdef ___SYNC_ENABLED___
- write(fd, syncs_, dict_info_.sync_count << 2);
+ write ( fd, syncs_, dict_info_.sync_count << 2 );
#endif
- write(fd, &dict_info_, sizeof(dict_info_));
-}
+ write ( fd, &dict_info_, sizeof ( dict_info_ ) );
+ }
-void UserDict::write_back_lemma(int fd) {
- int err = lseek(fd, 4, SEEK_SET);
- if (err == -1)
- return;
- // New lemmas are always appended, no need to write whole lemma block
- size_t need_write = kUserDictPreAlloc *
- (2 + (kUserDictAverageNchar << 2)) - lemma_size_left_;
- err = lseek(fd, dict_info_.lemma_size - need_write, SEEK_CUR);
- if (err == -1)
- return;
- write(fd, lemmas_ + dict_info_.lemma_size - need_write, need_write);
-
- write(fd, offsets_, dict_info_.lemma_count << 2);
+ void UserDict::write_back_lemma ( int fd ) {
+ int err = lseek ( fd, 4, SEEK_SET );
+ if ( err == -1 )
+ { return; }
+ // New lemmas are always appended, no need to write whole lemma block
+ size_t need_write = kUserDictPreAlloc *
+ ( 2 + ( kUserDictAverageNchar << 2 ) ) - lemma_size_left_;
+ err = lseek ( fd, dict_info_.lemma_size - need_write, SEEK_CUR );
+ if ( err == -1 )
+ { return; }
+ write ( fd, lemmas_ + dict_info_.lemma_size - need_write, need_write );
+ write ( fd, offsets_, dict_info_.lemma_count << 2 );
#ifdef ___PREDICT_ENABLED___
- write(fd, predicts_, dict_info_.lemma_count << 2);
+ write ( fd, predicts_, dict_info_.lemma_count << 2 );
#endif
- write(fd, scores_, dict_info_.lemma_count << 2);
+ write ( fd, scores_, dict_info_.lemma_count << 2 );
#ifdef ___SYNC_ENABLED___
- write(fd, syncs_, dict_info_.sync_count << 2);
+ write ( fd, syncs_, dict_info_.sync_count << 2 );
#endif
- write(fd, &dict_info_, sizeof(dict_info_));
-}
+ write ( fd, &dict_info_, sizeof ( dict_info_ ) );
+ }
-void UserDict::write_back_all(int fd) {
- // XXX lemma_size is handled differently in writeall
- // and writelemma. I update lemma_size and lemma_count in different
- // places for these two cases. Should fix it to make it consistent.
- int err = lseek(fd, 4, SEEK_SET);
- if (err == -1)
- return;
- write(fd, lemmas_, dict_info_.lemma_size);
- write(fd, offsets_, dict_info_.lemma_count << 2);
+ void UserDict::write_back_all ( int fd ) {
+ // XXX lemma_size is handled differently in writeall
+ // and writelemma. I update lemma_size and lemma_count in different
+ // places for these two cases. Should fix it to make it consistent.
+ int err = lseek ( fd, 4, SEEK_SET );
+ if ( err == -1 )
+ { return; }
+ write ( fd, lemmas_, dict_info_.lemma_size );
+ write ( fd, offsets_, dict_info_.lemma_count << 2 );
#ifdef ___PREDICT_ENABLED___
- write(fd, predicts_, dict_info_.lemma_count << 2);
+ write ( fd, predicts_, dict_info_.lemma_count << 2 );
#endif
- write(fd, scores_, dict_info_.lemma_count << 2);
+ write ( fd, scores_, dict_info_.lemma_count << 2 );
#ifdef ___SYNC_ENABLED___
- write(fd, syncs_, dict_info_.sync_count << 2);
+ write ( fd, syncs_, dict_info_.sync_count << 2 );
#endif
- write(fd, &dict_info_, sizeof(dict_info_));
-}
+ write ( fd, &dict_info_, sizeof ( dict_info_ ) );
+ }
#ifdef ___CACHE_ENABLED___
-bool UserDict::load_cache(UserDictSearchable *searchable,
- uint32 *offset, uint32 *length) {
- UserDictCache *cache = &caches_[searchable->splids_len - 1];
- if (cache->head == cache->tail)
- return false;
-
- uint16 j, sig_len = kMaxLemmaSize / 4;
- uint16 i = cache->head;
- while (1) {
- j = 0;
- for (; j < sig_len; j++) {
- if (cache->signatures[i][j] != searchable->signature[j])
- break;
- }
- if (j < sig_len) {
- i++;
- if (i >= kUserDictCacheSize)
- i -= kUserDictCacheSize;
- if (i == cache->tail)
- break;
- continue;
- }
- *offset = cache->offsets[i];
- *length = cache->lengths[i];
- return true;
- }
- return false;
-}
+ bool UserDict::load_cache ( UserDictSearchable *searchable,
+ uint32 *offset, uint32 *length ) {
+ UserDictCache *cache = &caches_[searchable->splids_len - 1];
+ if ( cache->head == cache->tail )
+ { return false; }
+ uint16 j, sig_len = kMaxLemmaSize / 4;
+ uint16 i = cache->head;
+ while ( 1 ) {
+ j = 0;
+ for ( ; j < sig_len; j++ ) {
+ if ( cache->signatures[i][j] != searchable->signature[j] )
+ { break; }
+ }
+ if ( j < sig_len ) {
+ i++;
+ if ( i >= kUserDictCacheSize )
+ { i -= kUserDictCacheSize; }
+ if ( i == cache->tail )
+ { break; }
+ continue;
+ }
+ *offset = cache->offsets[i];
+ *length = cache->lengths[i];
+ return true;
+ }
+ return false;
+ }
-void UserDict::save_cache(UserDictSearchable *searchable,
- uint32 offset, uint32 length) {
- UserDictCache *cache = &caches_[searchable->splids_len - 1];
- uint16 next = cache->tail;
-
- cache->offsets[next] = offset;
- cache->lengths[next] = length;
- uint16 sig_len = kMaxLemmaSize / 4;
- uint16 j = 0;
- for (; j < sig_len; j++) {
- cache->signatures[next][j] = searchable->signature[j];
- }
-
- if (++next >= kUserDictCacheSize) {
- next -= kUserDictCacheSize;
- }
- if (next == cache->head) {
- cache->head++;
- if (cache->head >= kUserDictCacheSize) {
- cache->head -= kUserDictCacheSize;
- }
- }
- cache->tail = next;
-}
+ void UserDict::save_cache ( UserDictSearchable *searchable,
+ uint32 offset, uint32 length ) {
+ UserDictCache *cache = &caches_[searchable->splids_len - 1];
+ uint16 next = cache->tail;
+ cache->offsets[next] = offset;
+ cache->lengths[next] = length;
+ uint16 sig_len = kMaxLemmaSize / 4;
+ uint16 j = 0;
+ for ( ; j < sig_len; j++ ) {
+ cache->signatures[next][j] = searchable->signature[j];
+ }
+ if ( ++next >= kUserDictCacheSize ) {
+ next -= kUserDictCacheSize;
+ }
+ if ( next == cache->head ) {
+ cache->head++;
+ if ( cache->head >= kUserDictCacheSize ) {
+ cache->head -= kUserDictCacheSize;
+ }
+ }
+ cache->tail = next;
+ }
-void UserDict::reset_cache() {
- memset(caches_, 0, sizeof(caches_));
-}
+ void UserDict::reset_cache() {
+ memset ( caches_, 0, sizeof ( caches_ ) );
+ }
-bool UserDict::load_miss_cache(UserDictSearchable *searchable) {
- UserDictMissCache *cache = &miss_caches_[searchable->splids_len - 1];
- if (cache->head == cache->tail)
- return false;
-
- uint16 j, sig_len = kMaxLemmaSize / 4;
- uint16 i = cache->head;
- while (1) {
- j = 0;
- for (; j < sig_len; j++) {
- if (cache->signatures[i][j] != searchable->signature[j])
- break;
- }
- if (j < sig_len) {
- i++;
- if (i >= kUserDictMissCacheSize)
- i -= kUserDictMissCacheSize;
- if (i == cache->tail)
- break;
- continue;
- }
- return true;
- }
- return false;
-}
+ bool UserDict::load_miss_cache ( UserDictSearchable *searchable ) {
+ UserDictMissCache *cache = &miss_caches_[searchable->splids_len - 1];
+ if ( cache->head == cache->tail )
+ { return false; }
+ uint16 j, sig_len = kMaxLemmaSize / 4;
+ uint16 i = cache->head;
+ while ( 1 ) {
+ j = 0;
+ for ( ; j < sig_len; j++ ) {
+ if ( cache->signatures[i][j] != searchable->signature[j] )
+ { break; }
+ }
+ if ( j < sig_len ) {
+ i++;
+ if ( i >= kUserDictMissCacheSize )
+ { i -= kUserDictMissCacheSize; }
+ if ( i == cache->tail )
+ { break; }
+ continue;
+ }
+ return true;
+ }
+ return false;
+ }
-void UserDict::save_miss_cache(UserDictSearchable *searchable) {
- UserDictMissCache *cache = &miss_caches_[searchable->splids_len - 1];
- uint16 next = cache->tail;
-
- uint16 sig_len = kMaxLemmaSize / 4;
- uint16 j = 0;
- for (; j < sig_len; j++) {
- cache->signatures[next][j] = searchable->signature[j];
- }
-
- if (++next >= kUserDictMissCacheSize) {
- next -= kUserDictMissCacheSize;
- }
- if (next == cache->head) {
- cache->head++;
- if (cache->head >= kUserDictMissCacheSize) {
- cache->head -= kUserDictMissCacheSize;
- }
- }
- cache->tail = next;
-}
+ void UserDict::save_miss_cache ( UserDictSearchable *searchable ) {
+ UserDictMissCache *cache = &miss_caches_[searchable->splids_len - 1];
+ uint16 next = cache->tail;
+ uint16 sig_len = kMaxLemmaSize / 4;
+ uint16 j = 0;
+ for ( ; j < sig_len; j++ ) {
+ cache->signatures[next][j] = searchable->signature[j];
+ }
+ if ( ++next >= kUserDictMissCacheSize ) {
+ next -= kUserDictMissCacheSize;
+ }
+ if ( next == cache->head ) {
+ cache->head++;
+ if ( cache->head >= kUserDictMissCacheSize ) {
+ cache->head -= kUserDictMissCacheSize;
+ }
+ }
+ cache->tail = next;
+ }
-void UserDict::reset_miss_cache() {
- memset(miss_caches_, 0, sizeof(miss_caches_));
-}
+ void UserDict::reset_miss_cache() {
+ memset ( miss_caches_, 0, sizeof ( miss_caches_ ) );
+ }
-void UserDict::cache_init() {
- reset_cache();
- reset_miss_cache();
-}
+ void UserDict::cache_init() {
+ reset_cache();
+ reset_miss_cache();
+ }
-bool UserDict::cache_hit(UserDictSearchable *searchable,
- uint32 *offset, uint32 *length) {
- bool hit = load_miss_cache(searchable);
- if (hit) {
- *offset = 0;
- *length = 0;
- return true;
- }
- hit = load_cache(searchable, offset, length);
- if (hit) {
- return true;
- }
- return false;
-}
+ bool UserDict::cache_hit ( UserDictSearchable *searchable,
+ uint32 *offset, uint32 *length ) {
+ bool hit = load_miss_cache ( searchable );
+ if ( hit ) {
+ *offset = 0;
+ *length = 0;
+ return true;
+ }
+ hit = load_cache ( searchable, offset, length );
+ if ( hit ) {
+ return true;
+ }
+ return false;
+ }
-void UserDict::cache_push(UserDictCacheType type,
- UserDictSearchable *searchable,
- uint32 offset, uint32 length) {
- switch (type) {
- case USER_DICT_MISS_CACHE:
- save_miss_cache(searchable);
- break;
- case USER_DICT_CACHE:
- save_cache(searchable, offset, length);
- break;
- default:
- break;
- }
-}
+ void UserDict::cache_push ( UserDictCacheType type,
+ UserDictSearchable *searchable,
+ uint32 offset, uint32 length ) {
+ switch ( type ) {
+ case USER_DICT_MISS_CACHE:
+ save_miss_cache ( searchable );
+ break;
+ case USER_DICT_CACHE:
+ save_cache ( searchable, offset, length );
+ break;
+ default:
+ break;
+ }
+ }
#endif
-void UserDict::defragment(void) {
+ void UserDict::defragment ( void ) {
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_BEGIN;
-#endif
- if (is_valid_state() == false)
- return;
- // Fixup offsets_, set REMOVE flag to lemma's flag if needed
- size_t first_freed = 0;
- size_t first_inuse = 0;
- while (first_freed < dict_info_.lemma_count) {
- // Find first freed offset
- while ((offsets_[first_freed] & kUserDictOffsetFlagRemove) == 0 &&
- first_freed < dict_info_.lemma_count) {
- first_freed++;
- }
- if (first_freed < dict_info_.lemma_count) {
- // Save REMOVE flag to lemma flag
- int off = offsets_[first_freed];
- set_lemma_flag(off, kUserDictLemmaFlagRemove);
- } else {
- break;
- }
- // Find first inuse offse after first_freed
- first_inuse = first_freed + 1;
- while ((offsets_[first_inuse] & kUserDictOffsetFlagRemove) &&
- (first_inuse < dict_info_.lemma_count)) {
- // Save REMOVE flag to lemma flag
- int off = offsets_[first_inuse];
- set_lemma_flag(off, kUserDictLemmaFlagRemove);
- first_inuse++;
- }
- if (first_inuse >= dict_info_.lemma_count) {
- break;
- }
- // Swap offsets_
- int tmp = offsets_[first_inuse];
- offsets_[first_inuse] = offsets_[first_freed];
- offsets_[first_freed] = tmp;
- // Move scores_, no need to swap
- tmp = scores_[first_inuse];
- scores_[first_inuse] = scores_[first_freed];
- scores_[first_freed] = tmp;
- // Swap ids_
- LemmaIdType tmpid = ids_[first_inuse];
- ids_[first_inuse] = ids_[first_freed];
- ids_[first_freed] = tmpid;
- // Go on
- first_freed++;
- }
+ DEBUG_PERF_BEGIN;
+#endif
+ if ( is_valid_state() == false )
+ { return; }
+ // Fixup offsets_, set REMOVE flag to lemma's flag if needed
+ size_t first_freed = 0;
+ size_t first_inuse = 0;
+ while ( first_freed < dict_info_.lemma_count ) {
+ // Find first freed offset
+ while ( ( offsets_[first_freed] & kUserDictOffsetFlagRemove ) == 0 &&
+ first_freed < dict_info_.lemma_count ) {
+ first_freed++;
+ }
+ if ( first_freed < dict_info_.lemma_count ) {
+ // Save REMOVE flag to lemma flag
+ int off = offsets_[first_freed];
+ set_lemma_flag ( off, kUserDictLemmaFlagRemove );
+ } else {
+ break;
+ }
+ // Find first inuse offse after first_freed
+ first_inuse = first_freed + 1;
+ while ( ( offsets_[first_inuse] & kUserDictOffsetFlagRemove ) &&
+ ( first_inuse < dict_info_.lemma_count ) ) {
+ // Save REMOVE flag to lemma flag
+ int off = offsets_[first_inuse];
+ set_lemma_flag ( off, kUserDictLemmaFlagRemove );
+ first_inuse++;
+ }
+ if ( first_inuse >= dict_info_.lemma_count ) {
+ break;
+ }
+ // Swap offsets_
+ int tmp = offsets_[first_inuse];
+ offsets_[first_inuse] = offsets_[first_freed];
+ offsets_[first_freed] = tmp;
+ // Move scores_, no need to swap
+ tmp = scores_[first_inuse];
+ scores_[first_inuse] = scores_[first_freed];
+ scores_[first_freed] = tmp;
+ // Swap ids_
+ LemmaIdType tmpid = ids_[first_inuse];
+ ids_[first_inuse] = ids_[first_freed];
+ ids_[first_freed] = tmpid;
+ // Go on
+ first_freed++;
+ }
#ifdef ___PREDICT_ENABLED___
- // Fixup predicts_
- first_freed = 0;
- first_inuse = 0;
- while (first_freed < dict_info_.lemma_count) {
- // Find first freed offset
- while ((predicts_[first_freed] & kUserDictOffsetFlagRemove) == 0 &&
- first_freed < dict_info_.lemma_count) {
- first_freed++;
- }
- if (first_freed >= dict_info_.lemma_count)
- break;
- // Find first inuse offse after first_freed
- first_inuse = first_freed + 1;
- while ((predicts_[first_inuse] & kUserDictOffsetFlagRemove)
- && (first_inuse < dict_info_.lemma_count)) {
- first_inuse++;
- }
- if (first_inuse >= dict_info_.lemma_count) {
- break;
- }
- // Swap offsets_
- int tmp = predicts_[first_inuse];
- predicts_[first_inuse] = predicts_[first_freed];
- predicts_[first_freed] = tmp;
- // Go on
- first_freed++;
- }
-#endif
- dict_info_.lemma_count = first_freed;
- // Fixup lemmas_
- size_t begin = 0;
- size_t end = 0;
- size_t dst = 0;
- int total_size = dict_info_.lemma_size + lemma_size_left_;
- int total_count = dict_info_.lemma_count + lemma_count_left_;
- size_t real_size = total_size - lemma_size_left_;
- while (dst < real_size) {
- unsigned char flag = get_lemma_flag(dst);
- unsigned char nchr = get_lemma_nchar(dst);
- if ((flag & kUserDictLemmaFlagRemove) == 0) {
- dst += nchr * 4 + 2;
- continue;
- }
- break;
- }
- if (dst >= real_size)
- return;
-
- end = dst;
- while (end < real_size) {
- begin = end + get_lemma_nchar(end) * 4 + 2;
- repeat:
- // not used any more
- if (begin >= real_size)
- break;
- unsigned char flag = get_lemma_flag(begin);
- unsigned char nchr = get_lemma_nchar(begin);
- if (flag & kUserDictLemmaFlagRemove) {
- begin += nchr * 4 + 2;
- goto repeat;
- }
- end = begin + nchr * 4 + 2;
- while (end < real_size) {
- unsigned char eflag = get_lemma_flag(end);
- unsigned char enchr = get_lemma_nchar(end);
- if ((eflag & kUserDictLemmaFlagRemove) == 0) {
- end += enchr * 4 + 2;
- continue;
- }
- break;
- }
- memmove(lemmas_ + dst, lemmas_ + begin, end - begin);
- for (size_t j = 0; j < dict_info_.lemma_count; j++) {
- if (offsets_[j] >= begin && offsets_[j] < end) {
- offsets_[j] -= (begin - dst);
- offsets_by_id_[ids_[j] - start_id_] = offsets_[j];
- }
+ // Fixup predicts_
+ first_freed = 0;
+ first_inuse = 0;
+ while ( first_freed < dict_info_.lemma_count ) {
+ // Find first freed offset
+ while ( ( predicts_[first_freed] & kUserDictOffsetFlagRemove ) == 0 &&
+ first_freed < dict_info_.lemma_count ) {
+ first_freed++;
+ }
+ if ( first_freed >= dict_info_.lemma_count )
+ { break; }
+ // Find first inuse offse after first_freed
+ first_inuse = first_freed + 1;
+ while ( ( predicts_[first_inuse] & kUserDictOffsetFlagRemove )
+ && ( first_inuse < dict_info_.lemma_count ) ) {
+ first_inuse++;
+ }
+ if ( first_inuse >= dict_info_.lemma_count ) {
+ break;
+ }
+ // Swap offsets_
+ int tmp = predicts_[first_inuse];
+ predicts_[first_inuse] = predicts_[first_freed];
+ predicts_[first_freed] = tmp;
+ // Go on
+ first_freed++;
+ }
+#endif
+ dict_info_.lemma_count = first_freed;
+ // Fixup lemmas_
+ size_t begin = 0;
+ size_t end = 0;
+ size_t dst = 0;
+ int total_size = dict_info_.lemma_size + lemma_size_left_;
+ int total_count = dict_info_.lemma_count + lemma_count_left_;
+ size_t real_size = total_size - lemma_size_left_;
+ while ( dst < real_size ) {
+ unsigned char flag = get_lemma_flag ( dst );
+ unsigned char nchr = get_lemma_nchar ( dst );
+ if ( ( flag & kUserDictLemmaFlagRemove ) == 0 ) {
+ dst += nchr * 4 + 2;
+ continue;
+ }
+ break;
+ }
+ if ( dst >= real_size )
+ { return; }
+ end = dst;
+ while ( end < real_size ) {
+ begin = end + get_lemma_nchar ( end ) * 4 + 2;
+ repeat:
+ // not used any more
+ if ( begin >= real_size )
+ { break; }
+ unsigned char flag = get_lemma_flag ( begin );
+ unsigned char nchr = get_lemma_nchar ( begin );
+ if ( flag & kUserDictLemmaFlagRemove ) {
+ begin += nchr * 4 + 2;
+ goto repeat;
+ }
+ end = begin + nchr * 4 + 2;
+ while ( end < real_size ) {
+ unsigned char eflag = get_lemma_flag ( end );
+ unsigned char enchr = get_lemma_nchar ( end );
+ if ( ( eflag & kUserDictLemmaFlagRemove ) == 0 ) {
+ end += enchr * 4 + 2;
+ continue;
+ }
+ break;
+ }
+ memmove ( lemmas_ + dst, lemmas_ + begin, end - begin );
+ for ( size_t j = 0; j < dict_info_.lemma_count; j++ ) {
+ if ( offsets_[j] >= begin && offsets_[j] < end ) {
+ offsets_[j] -= ( begin - dst );
+ offsets_by_id_[ids_[j] - start_id_] = offsets_[j];
+ }
#ifdef ___PREDICT_ENABLED___
- if (predicts_[j] >= begin && predicts_[j] < end) {
- predicts_[j] -= (begin - dst);
- }
+ if ( predicts_[j] >= begin && predicts_[j] < end ) {
+ predicts_[j] -= ( begin - dst );
+ }
#endif
- }
+ }
#ifdef ___SYNC_ENABLED___
- for (size_t j = 0; j < dict_info_.sync_count; j++) {
- if (syncs_[j] >= begin && syncs_[j] < end) {
- syncs_[j] -= (begin - dst);
- }
- }
-#endif
- dst += (end - begin);
- }
-
- dict_info_.free_count = 0;
- dict_info_.free_size = 0;
- dict_info_.lemma_size = dst;
- lemma_size_left_ = total_size - dict_info_.lemma_size;
- lemma_count_left_ = total_count - dict_info_.lemma_count;
-
- // XXX Without following code,
- // offsets_by_id_ is not reordered.
- // That's to say, all removed lemmas' ids are not collected back.
- // There may not be room for addition of new lemmas due to
- // offsests_by_id_ reason, although lemma_size_left_ is fixed.
- // By default, we do want defrag as fast as possible, because
- // during defrag procedure, other peers can not write new lemmas
- // to user dictionary file.
- // XXX If write-back is invoked immediately after
- // this defragment, no need to fix up following in-mem data.
- for (uint32 i = 0; i < dict_info_.lemma_count; i++) {
- ids_[i] = start_id_ + i;
- offsets_by_id_[i] = offsets_[i];
- }
-
- state_ = USER_DICT_DEFRAGMENTED;
-
+ for ( size_t j = 0; j < dict_info_.sync_count; j++ ) {
+ if ( syncs_[j] >= begin && syncs_[j] < end ) {
+ syncs_[j] -= ( begin - dst );
+ }
+ }
+#endif
+ dst += ( end - begin );
+ }
+ dict_info_.free_count = 0;
+ dict_info_.free_size = 0;
+ dict_info_.lemma_size = dst;
+ lemma_size_left_ = total_size - dict_info_.lemma_size;
+ lemma_count_left_ = total_count - dict_info_.lemma_count;
+ // XXX Without following code,
+ // offsets_by_id_ is not reordered.
+ // That's to say, all removed lemmas' ids are not collected back.
+ // There may not be room for addition of new lemmas due to
+ // offsests_by_id_ reason, although lemma_size_left_ is fixed.
+ // By default, we do want defrag as fast as possible, because
+ // during defrag procedure, other peers can not write new lemmas
+ // to user dictionary file.
+ // XXX If write-back is invoked immediately after
+ // this defragment, no need to fix up following in-mem data.
+ for ( uint32 i = 0; i < dict_info_.lemma_count; i++ ) {
+ ids_[i] = start_id_ + i;
+ offsets_by_id_[i] = offsets_[i];
+ }
+ state_ = USER_DICT_DEFRAGMENTED;
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_END;
- LOGD_PERF("defragment");
+ DEBUG_PERF_END;
+ LOGD_PERF ( "defragment" );
#endif
-}
+ }
#ifdef ___SYNC_ENABLED___
-void UserDict::clear_sync_lemmas(unsigned int start, unsigned int end) {
- if (is_valid_state() == false)
- return;
- if (end > dict_info_.sync_count)
- end = dict_info_.sync_count;
- memmove(syncs_ + start, syncs_ + end, (dict_info_.sync_count - end) << 2);
- dict_info_.sync_count -= (end - start);
- if (state_ < USER_DICT_SYNC_DIRTY)
- state_ = USER_DICT_SYNC_DIRTY;
-}
-
-int UserDict::get_sync_count() {
- if (is_valid_state() == false)
- return 0;
- return dict_info_.sync_count;
-}
+ void UserDict::clear_sync_lemmas ( unsigned int start, unsigned int end ) {
+ if ( is_valid_state() == false )
+ { return; }
+ if ( end > dict_info_.sync_count )
+ { end = dict_info_.sync_count; }
+ memmove ( syncs_ + start, syncs_ + end, ( dict_info_.sync_count - end ) << 2 );
+ dict_info_.sync_count -= ( end - start );
+ if ( state_ < USER_DICT_SYNC_DIRTY )
+ { state_ = USER_DICT_SYNC_DIRTY; }
+ }
-LemmaIdType UserDict::put_lemma_no_sync(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count, uint64 lmt) {
- int again = 0;
- begin:
- LemmaIdType id;
- uint32 * syncs_bak = syncs_;
- syncs_ = NULL;
- id = _put_lemma(lemma_str, splids, lemma_len, count, lmt);
- syncs_ = syncs_bak;
- if (id == 0 && again == 0) {
- if ((dict_info_.limit_lemma_count > 0 &&
- dict_info_.lemma_count >= dict_info_.limit_lemma_count)
- || (dict_info_.limit_lemma_size > 0 &&
- dict_info_.lemma_size + (2 + (lemma_len << 2))
- > dict_info_.limit_lemma_size)) {
- // XXX Always reclaim and defrag in sync code path
- // sync thread is background thread and ok with heavy work
- reclaim();
- defragment();
- flush_cache();
- again = 1;
- goto begin;
- }
- }
- return id;
-}
+ int UserDict::get_sync_count() {
+ if ( is_valid_state() == false )
+ { return 0; }
+ return dict_info_.sync_count;
+ }
-int UserDict::put_lemmas_no_sync_from_utf16le_string(char16 * lemmas, int len) {
- int newly_added = 0;
+ LemmaIdType UserDict::put_lemma_no_sync ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count, uint64 lmt ) {
+ int again = 0;
+ begin:
+ LemmaIdType id;
+ uint32 *syncs_bak = syncs_;
+ syncs_ = NULL;
+ id = _put_lemma ( lemma_str, splids, lemma_len, count, lmt );
+ syncs_ = syncs_bak;
+ if ( id == 0 && again == 0 ) {
+ if ( ( dict_info_.limit_lemma_count > 0 &&
+ dict_info_.lemma_count >= dict_info_.limit_lemma_count )
+ || ( dict_info_.limit_lemma_size > 0 &&
+ dict_info_.lemma_size + ( 2 + ( lemma_len << 2 ) )
+ > dict_info_.limit_lemma_size ) ) {
+ // XXX Always reclaim and defrag in sync code path
+ // sync thread is background thread and ok with heavy work
+ reclaim();
+ defragment();
+ flush_cache();
+ again = 1;
+ goto begin;
+ }
+ }
+ return id;
+ }
- SpellingParser * spl_parser = new SpellingParser();
- if (!spl_parser) {
- return 0;
- }
+ int UserDict::put_lemmas_no_sync_from_utf16le_string ( char16 *lemmas, int len ) {
+ int newly_added = 0;
+ SpellingParser *spl_parser = new SpellingParser();
+ if ( !spl_parser ) {
+ return 0;
+ }
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_BEGIN;
-#endif
- char16 *ptr = lemmas;
-
- // Extract pinyin,words,frequence,last_mod_time
- char16 * p = ptr, * py16 = ptr;
- char16 * hz16 = NULL;
- int py16_len = 0;
- uint16 splid[kMaxLemmaSize];
- int splid_len = 0;
- int hz16_len = 0;
- char16 * fr16 = NULL;
- int fr16_len = 0;
-
- while (p - ptr < len) {
- // Pinyin
- py16 = p;
- splid_len = 0;
- while (*p != 0x2c && (p - ptr) < len) {
- if (*p == 0x20)
- splid_len++;
- p++;
- }
- splid_len++;
- if (p - ptr == len)
- break;
- py16_len = p - py16;
- if (kMaxLemmaSize < splid_len) {
- break;
- }
- bool is_pre;
- int splidl = spl_parser->splstr16_to_idxs_f(
- py16, py16_len, splid, NULL, kMaxLemmaSize, is_pre);
- if (splidl != splid_len)
- break;
- // Phrase
- hz16 = ++p;
- while (*p != 0x2c && (p - ptr) < len) {
- p++;
- }
- hz16_len = p - hz16;
- if (hz16_len != splid_len)
- break;
- // Frequency
- fr16 = ++p;
- fr16_len = 0;
- while (*p != 0x2c && (p - ptr) < len) {
- p++;
- }
- fr16_len = p - fr16;
- uint32 intf = (uint32)utf16le_atoll(fr16, fr16_len);
- // Last modified time
- fr16 = ++p;
- fr16_len = 0;
- while (*p != 0x3b && (p - ptr) < len) {
- p++;
- }
- fr16_len = p - fr16;
- uint64 last_mod = utf16le_atoll(fr16, fr16_len);
-
- put_lemma_no_sync(hz16, splid, splid_len, intf, last_mod);
- newly_added++;
-
- p++;
- }
-
+ DEBUG_PERF_BEGIN;
+#endif
+ char16 *ptr = lemmas;
+ // Extract pinyin,words,frequence,last_mod_time
+ char16 *p = ptr, * py16 = ptr;
+ char16 *hz16 = NULL;
+ int py16_len = 0;
+ uint16 splid[kMaxLemmaSize];
+ int splid_len = 0;
+ int hz16_len = 0;
+ char16 *fr16 = NULL;
+ int fr16_len = 0;
+ while ( p - ptr < len ) {
+ // Pinyin
+ py16 = p;
+ splid_len = 0;
+ while ( *p != 0x2c && ( p - ptr ) < len ) {
+ if ( *p == 0x20 )
+ { splid_len++; }
+ p++;
+ }
+ splid_len++;
+ if ( p - ptr == len )
+ { break; }
+ py16_len = p - py16;
+ if ( kMaxLemmaSize < splid_len ) {
+ break;
+ }
+ bool is_pre;
+ int splidl = spl_parser->splstr16_to_idxs_f (
+ py16, py16_len, splid, NULL, kMaxLemmaSize, is_pre );
+ if ( splidl != splid_len )
+ { break; }
+ // Phrase
+ hz16 = ++p;
+ while ( *p != 0x2c && ( p - ptr ) < len ) {
+ p++;
+ }
+ hz16_len = p - hz16;
+ if ( hz16_len != splid_len )
+ { break; }
+ // Frequency
+ fr16 = ++p;
+ fr16_len = 0;
+ while ( *p != 0x2c && ( p - ptr ) < len ) {
+ p++;
+ }
+ fr16_len = p - fr16;
+ uint32 intf = ( uint32 ) utf16le_atoll ( fr16, fr16_len );
+ // Last modified time
+ fr16 = ++p;
+ fr16_len = 0;
+ while ( *p != 0x3b && ( p - ptr ) < len ) {
+ p++;
+ }
+ fr16_len = p - fr16;
+ uint64 last_mod = utf16le_atoll ( fr16, fr16_len );
+ put_lemma_no_sync ( hz16, splid, splid_len, intf, last_mod );
+ newly_added++;
+ p++;
+ }
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_END;
- LOGD_PERF("put_lemmas_no_sync_from_utf16le_string");
+ DEBUG_PERF_END;
+ LOGD_PERF ( "put_lemmas_no_sync_from_utf16le_string" );
#endif
- return newly_added;
-}
+ return newly_added;
+ }
-int UserDict::get_sync_lemmas_in_utf16le_string_from_beginning(
- char16 * str, int size, int * count) {
- int len = 0;
- *count = 0;
-
- int left_len = size;
-
- if (is_valid_state() == false)
- return len;
-
- SpellingTrie * spl_trie = &SpellingTrie::get_instance();
- if (!spl_trie) {
- return 0;
- }
-
- uint32 i;
- for (i = 0; i < dict_info_.sync_count; i++) {
- int offset = syncs_[i];
- uint32 nchar = get_lemma_nchar(offset);
- uint16 *spl = get_lemma_spell_ids(offset);
- uint16 *wrd = get_lemma_word(offset);
- int score = _get_lemma_score(wrd, spl, nchar);
-
- static char score_temp[32], *pscore_temp = score_temp;
- static char16 temp[256], *ptemp = temp;
-
- pscore_temp = score_temp;
- ptemp = temp;
-
- uint32 j;
- // Add pinyin
- for (j = 0; j < nchar; j++) {
- int ret_len = spl_trie->get_spelling_str16(
- spl[j], ptemp, temp + sizeof(temp) - ptemp);
- if (ret_len <= 0)
- break;
- ptemp += ret_len;
- if (ptemp < temp + sizeof(temp) - 1) {
- *(ptemp++) = ' ';
- } else {
- j = 0;
- break;
- }
- }
- if (j < nchar) {
- continue;
- }
- ptemp--;
- if (ptemp < temp + sizeof(temp) - 1) {
- *(ptemp++) = ',';
- } else {
- continue;
- }
- // Add phrase
- for (j = 0; j < nchar; j++) {
- if (ptemp < temp + sizeof(temp) - 1) {
- *(ptemp++) = wrd[j];
- } else {
- break;
- }
- }
- if (j < nchar) {
- continue;
- }
- if (ptemp < temp + sizeof(temp) - 1) {
- *(ptemp++) = ',';
- } else {
- continue;
- }
- // Add frequency
- uint32 intf = extract_score_freq(score);
- int ret_len = utf16le_lltoa(intf, ptemp, temp + sizeof(temp) - ptemp);
- if (ret_len <= 0)
- continue;
- ptemp += ret_len;
- if (ptemp < temp + sizeof(temp) - 1) {
- *(ptemp++) = ',';
- } else {
- continue;
- }
- // Add last modified time
- uint64 last_mod = extract_score_lmt(score);
- ret_len = utf16le_lltoa(last_mod, ptemp, temp + sizeof(temp) - ptemp);
- if (ret_len <= 0)
- continue;
- ptemp += ret_len;
- if (ptemp < temp + sizeof(temp) - 1) {
- *(ptemp++) = ';';
- } else {
- continue;
- }
-
- // Write to string
- int need_len = ptemp - temp;
- if (need_len > left_len)
- break;
- memcpy(str + len, temp, need_len * 2);
- left_len -= need_len;
-
- len += need_len;
- (*count)++;
- }
-
- if (len > 0) {
- if (state_ < USER_DICT_SYNC_DIRTY)
- state_ = USER_DICT_SYNC_DIRTY;
- }
- return len;
-}
+ int UserDict::get_sync_lemmas_in_utf16le_string_from_beginning (
+ char16 *str, int size, int *count ) {
+ int len = 0;
+ *count = 0;
+ int left_len = size;
+ if ( is_valid_state() == false )
+ { return len; }
+ SpellingTrie *spl_trie = &SpellingTrie::get_instance();
+ if ( !spl_trie ) {
+ return 0;
+ }
+ uint32 i;
+ for ( i = 0; i < dict_info_.sync_count; i++ ) {
+ int offset = syncs_[i];
+ uint32 nchar = get_lemma_nchar ( offset );
+ uint16 *spl = get_lemma_spell_ids ( offset );
+ uint16 *wrd = get_lemma_word ( offset );
+ int score = _get_lemma_score ( wrd, spl, nchar );
+ static char score_temp[32], *pscore_temp = score_temp;
+ static char16 temp[256], *ptemp = temp;
+ pscore_temp = score_temp;
+ ptemp = temp;
+ uint32 j;
+ // Add pinyin
+ for ( j = 0; j < nchar; j++ ) {
+ int ret_len = spl_trie->get_spelling_str16 (
+ spl[j], ptemp, temp + sizeof ( temp ) - ptemp );
+ if ( ret_len <= 0 )
+ { break; }
+ ptemp += ret_len;
+ if ( ptemp < temp + sizeof ( temp ) - 1 ) {
+ * ( ptemp++ ) = ' ';
+ } else {
+ j = 0;
+ break;
+ }
+ }
+ if ( j < nchar ) {
+ continue;
+ }
+ ptemp--;
+ if ( ptemp < temp + sizeof ( temp ) - 1 ) {
+ * ( ptemp++ ) = ',';
+ } else {
+ continue;
+ }
+ // Add phrase
+ for ( j = 0; j < nchar; j++ ) {
+ if ( ptemp < temp + sizeof ( temp ) - 1 ) {
+ * ( ptemp++ ) = wrd[j];
+ } else {
+ break;
+ }
+ }
+ if ( j < nchar ) {
+ continue;
+ }
+ if ( ptemp < temp + sizeof ( temp ) - 1 ) {
+ * ( ptemp++ ) = ',';
+ } else {
+ continue;
+ }
+ // Add frequency
+ uint32 intf = extract_score_freq ( score );
+ int ret_len = utf16le_lltoa ( intf, ptemp, temp + sizeof ( temp ) - ptemp );
+ if ( ret_len <= 0 )
+ { continue; }
+ ptemp += ret_len;
+ if ( ptemp < temp + sizeof ( temp ) - 1 ) {
+ * ( ptemp++ ) = ',';
+ } else {
+ continue;
+ }
+ // Add last modified time
+ uint64 last_mod = extract_score_lmt ( score );
+ ret_len = utf16le_lltoa ( last_mod, ptemp, temp + sizeof ( temp ) - ptemp );
+ if ( ret_len <= 0 )
+ { continue; }
+ ptemp += ret_len;
+ if ( ptemp < temp + sizeof ( temp ) - 1 ) {
+ * ( ptemp++ ) = ';';
+ } else {
+ continue;
+ }
+ // Write to string
+ int need_len = ptemp - temp;
+ if ( need_len > left_len )
+ { break; }
+ memcpy ( str + len, temp, need_len * 2 );
+ left_len -= need_len;
+ len += need_len;
+ ( *count ) ++;
+ }
+ if ( len > 0 ) {
+ if ( state_ < USER_DICT_SYNC_DIRTY )
+ { state_ = USER_DICT_SYNC_DIRTY; }
+ }
+ return len;
+ }
#endif
-bool UserDict::state(UserDictStat * stat) {
- if (is_valid_state() == false)
- return false;
- if (!stat)
- return false;
- stat->version = version_;
- stat->file_name = dict_file_;
- stat->load_time.tv_sec = load_time_.tv_sec;
- stat->load_time.tv_usec = load_time_.tv_usec;
- pthread_mutex_lock(&g_mutex_);
- stat->last_update.tv_sec = g_last_update_.tv_sec;
- stat->last_update.tv_usec = g_last_update_.tv_usec;
- pthread_mutex_unlock(&g_mutex_);
- stat->disk_size = get_dict_file_size(&dict_info_);
- stat->lemma_count = dict_info_.lemma_count;
- stat->lemma_size = dict_info_.lemma_size;
- stat->delete_count = dict_info_.free_count;
- stat->delete_size = dict_info_.free_size;
+ bool UserDict::state ( UserDictStat *stat ) {
+ if ( is_valid_state() == false )
+ { return false; }
+ if ( !stat )
+ { return false; }
+ stat->version = version_;
+ stat->file_name = dict_file_;
+ stat->load_time.tv_sec = load_time_.tv_sec;
+ stat->load_time.tv_usec = load_time_.tv_usec;
+ pthread_mutex_lock ( &g_mutex_ );
+ stat->last_update.tv_sec = g_last_update_.tv_sec;
+ stat->last_update.tv_usec = g_last_update_.tv_usec;
+ pthread_mutex_unlock ( &g_mutex_ );
+ stat->disk_size = get_dict_file_size ( &dict_info_ );
+ stat->lemma_count = dict_info_.lemma_count;
+ stat->lemma_size = dict_info_.lemma_size;
+ stat->delete_count = dict_info_.free_count;
+ stat->delete_size = dict_info_.free_size;
#ifdef ___SYNC_ENABLED___
- stat->sync_count = dict_info_.sync_count;
+ stat->sync_count = dict_info_.sync_count;
#endif
- stat->limit_lemma_count = dict_info_.limit_lemma_count;
- stat->limit_lemma_size = dict_info_.limit_lemma_size;
- stat->reclaim_ratio = dict_info_.reclaim_ratio;
- return true;
-}
+ stat->limit_lemma_count = dict_info_.limit_lemma_count;
+ stat->limit_lemma_size = dict_info_.limit_lemma_size;
+ stat->reclaim_ratio = dict_info_.reclaim_ratio;
+ return true;
+ }
-void UserDict::set_limit(uint32 max_lemma_count,
- uint32 max_lemma_size, uint32 reclaim_ratio) {
- dict_info_.limit_lemma_count = max_lemma_count;
- dict_info_.limit_lemma_size = max_lemma_size;
- if (reclaim_ratio > 100)
- reclaim_ratio = 100;
- dict_info_.reclaim_ratio = reclaim_ratio;
-}
+ void UserDict::set_limit ( uint32 max_lemma_count,
+ uint32 max_lemma_size, uint32 reclaim_ratio ) {
+ dict_info_.limit_lemma_count = max_lemma_count;
+ dict_info_.limit_lemma_size = max_lemma_size;
+ if ( reclaim_ratio > 100 )
+ { reclaim_ratio = 100; }
+ dict_info_.reclaim_ratio = reclaim_ratio;
+ }
-void UserDict::reclaim() {
- if (is_valid_state() == false)
- return;
-
- switch (dict_info_.reclaim_ratio) {
- case 0:
- return;
- case 100:
- // TODO: CLEAR to be implemented
- assert(false);
- return;
- default:
- break;
- }
-
- // XXX Reclaim is only based on count, not size
- uint32 count = dict_info_.lemma_count;
- int rc = count * dict_info_.reclaim_ratio / 100;
-
- UserDictScoreOffsetPair * score_offset_pairs = NULL;
- score_offset_pairs = (UserDictScoreOffsetPair *)malloc(
- sizeof(UserDictScoreOffsetPair) * rc);
- if (score_offset_pairs == NULL) {
- return;
- }
-
- for (int i = 0; i < rc; i++) {
- int s = scores_[i];
- score_offset_pairs[i].score = s;
- score_offset_pairs[i].offset_index = i;
- }
-
- for (int i = (rc + 1) / 2; i >= 0; i--)
- shift_down(score_offset_pairs, i, rc);
-
- for (uint32 i = rc; i < dict_info_.lemma_count; i++) {
- int s = scores_[i];
- if (s < score_offset_pairs[0].score) {
- score_offset_pairs[0].score = s;
- score_offset_pairs[0].offset_index = i;
- shift_down(score_offset_pairs, 0, rc);
- }
- }
-
- for (int i = 0; i < rc; i++) {
- int off = score_offset_pairs[i].offset_index;
- remove_lemma_by_offset_index(off);
- }
- if (rc > 0) {
- if (state_ < USER_DICT_OFFSET_DIRTY)
- state_ = USER_DICT_OFFSET_DIRTY;
- }
-
- free(score_offset_pairs);
-}
+ void UserDict::reclaim() {
+ if ( is_valid_state() == false )
+ { return; }
+ switch ( dict_info_.reclaim_ratio ) {
+ case 0:
+ return;
+ case 100:
+ // TODO: CLEAR to be implemented
+ assert ( false );
+ return;
+ default:
+ break;
+ }
+ // XXX Reclaim is only based on count, not size
+ uint32 count = dict_info_.lemma_count;
+ int rc = count * dict_info_.reclaim_ratio / 100;
+ UserDictScoreOffsetPair *score_offset_pairs = NULL;
+ score_offset_pairs = ( UserDictScoreOffsetPair * ) malloc (
+ sizeof ( UserDictScoreOffsetPair ) * rc );
+ if ( score_offset_pairs == NULL ) {
+ return;
+ }
+ for ( int i = 0; i < rc; i++ ) {
+ int s = scores_[i];
+ score_offset_pairs[i].score = s;
+ score_offset_pairs[i].offset_index = i;
+ }
+ for ( int i = ( rc + 1 ) / 2; i >= 0; i-- )
+ { shift_down ( score_offset_pairs, i, rc ); }
+ for ( uint32 i = rc; i < dict_info_.lemma_count; i++ ) {
+ int s = scores_[i];
+ if ( s < score_offset_pairs[0].score ) {
+ score_offset_pairs[0].score = s;
+ score_offset_pairs[0].offset_index = i;
+ shift_down ( score_offset_pairs, 0, rc );
+ }
+ }
+ for ( int i = 0; i < rc; i++ ) {
+ int off = score_offset_pairs[i].offset_index;
+ remove_lemma_by_offset_index ( off );
+ }
+ if ( rc > 0 ) {
+ if ( state_ < USER_DICT_OFFSET_DIRTY )
+ { state_ = USER_DICT_OFFSET_DIRTY; }
+ }
+ free ( score_offset_pairs );
+ }
-inline void UserDict::swap(UserDictScoreOffsetPair * sop, int i, int j) {
- int s = sop[i].score;
- int p = sop[i].offset_index;
- sop[i].score = sop[j].score;
- sop[i].offset_index = sop[j].offset_index;
- sop[j].score = s;
- sop[j].offset_index = p;
-}
+ inline void UserDict::swap ( UserDictScoreOffsetPair *sop, int i, int j ) {
+ int s = sop[i].score;
+ int p = sop[i].offset_index;
+ sop[i].score = sop[j].score;
+ sop[i].offset_index = sop[j].offset_index;
+ sop[j].score = s;
+ sop[j].offset_index = p;
+ }
-void UserDict::shift_down(UserDictScoreOffsetPair * sop, int i, int n) {
- int par = i;
- while (par < n) {
- int left = par * 2 + 1;
- int right = left + 1;
- if (left >= n && right >= n)
- break;
- if (right >= n) {
- if (sop[left].score > sop[par].score) {
- swap(sop, left, par);
- par = left;
- continue;
- }
- } else if (sop[left].score > sop[right].score &&
- sop[left].score > sop[par].score) {
- swap(sop, left, par);
- par = left;
- continue;
- } else if (sop[right].score > sop[left].score &&
- sop[right].score > sop[par].score) {
- swap(sop, right, par);
- par = right;
- continue;
- }
- break;
- }
-}
+ void UserDict::shift_down ( UserDictScoreOffsetPair *sop, int i, int n ) {
+ int par = i;
+ while ( par < n ) {
+ int left = par * 2 + 1;
+ int right = left + 1;
+ if ( left >= n && right >= n )
+ { break; }
+ if ( right >= n ) {
+ if ( sop[left].score > sop[par].score ) {
+ swap ( sop, left, par );
+ par = left;
+ continue;
+ }
+ } else if ( sop[left].score > sop[right].score &&
+ sop[left].score > sop[par].score ) {
+ swap ( sop, left, par );
+ par = left;
+ continue;
+ } else if ( sop[right].score > sop[left].score &&
+ sop[right].score > sop[par].score ) {
+ swap ( sop, right, par );
+ par = right;
+ continue;
+ }
+ break;
+ }
+ }
-LemmaIdType UserDict::put_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count) {
- return _put_lemma(lemma_str, splids, lemma_len, count, time(NULL));
-}
+ LemmaIdType UserDict::put_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count ) {
+ return _put_lemma ( lemma_str, splids, lemma_len, count, time ( NULL ) );
+ }
-LemmaIdType UserDict::_put_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count, uint64 lmt) {
+ LemmaIdType UserDict::_put_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count, uint64 lmt ) {
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_BEGIN;
-#endif
- if (is_valid_state() == false)
- return 0;
- int32 off = locate_in_offsets(lemma_str, splids, lemma_len);
- if (off != -1) {
- int delta_score = count - scores_[off];
- dict_info_.total_nfreq += delta_score;
- scores_[off] = build_score(lmt, count);
- if (state_ < USER_DICT_SCORE_DIRTY)
- state_ = USER_DICT_SCORE_DIRTY;
+ DEBUG_PERF_BEGIN;
+#endif
+ if ( is_valid_state() == false )
+ { return 0; }
+ int32 off = locate_in_offsets ( lemma_str, splids, lemma_len );
+ if ( off != -1 ) {
+ int delta_score = count - scores_[off];
+ dict_info_.total_nfreq += delta_score;
+ scores_[off] = build_score ( lmt, count );
+ if ( state_ < USER_DICT_SCORE_DIRTY )
+ { state_ = USER_DICT_SCORE_DIRTY; }
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_END;
- LOGD_PERF("_put_lemma(update)");
-#endif
- return ids_[off];
- } else {
- if ((dict_info_.limit_lemma_count > 0 &&
- dict_info_.lemma_count >= dict_info_.limit_lemma_count)
- || (dict_info_.limit_lemma_size > 0 &&
- dict_info_.lemma_size + (2 + (lemma_len << 2))
- > dict_info_.limit_lemma_size)) {
- // XXX Don't defragment here, it's too time-consuming.
- return 0;
- }
- int flushed = 0;
- if (lemma_count_left_ == 0 ||
- lemma_size_left_ < (size_t)(2 + (lemma_len << 2))) {
-
- // XXX When there is no space for new lemma, we flush to disk
- // flush_cache() may be called by upper user
- // and better place shoule be found instead of here
- flush_cache();
- flushed = 1;
- // Or simply return and do nothing
- // return 0;
- }
+ DEBUG_PERF_END;
+ LOGD_PERF ( "_put_lemma(update)" );
+#endif
+ return ids_[off];
+ } else {
+ if ( ( dict_info_.limit_lemma_count > 0 &&
+ dict_info_.lemma_count >= dict_info_.limit_lemma_count )
+ || ( dict_info_.limit_lemma_size > 0 &&
+ dict_info_.lemma_size + ( 2 + ( lemma_len << 2 ) )
+ > dict_info_.limit_lemma_size ) ) {
+ // XXX Don't defragment here, it's too time-consuming.
+ return 0;
+ }
+ int flushed = 0;
+ if ( lemma_count_left_ == 0 ||
+ lemma_size_left_ < ( size_t ) ( 2 + ( lemma_len << 2 ) ) ) {
+ // XXX When there is no space for new lemma, we flush to disk
+ // flush_cache() may be called by upper user
+ // and better place shoule be found instead of here
+ flush_cache();
+ flushed = 1;
+ // Or simply return and do nothing
+ // return 0;
+ }
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_END;
- LOGD_PERF(flushed ? "_put_lemma(flush+add)" : "_put_lemma(add)");
+ DEBUG_PERF_END;
+ LOGD_PERF ( flushed ? "_put_lemma(flush+add)" : "_put_lemma(add)" );
#endif
- LemmaIdType id = append_a_lemma(lemma_str, splids, lemma_len, count, lmt);
+ LemmaIdType id = append_a_lemma ( lemma_str, splids, lemma_len, count, lmt );
#ifdef ___SYNC_ENABLED___
- if (syncs_ && id != 0) {
- queue_lemma_for_sync(id);
- }
+ if ( syncs_ && id != 0 ) {
+ queue_lemma_for_sync ( id );
+ }
#endif
- return id;
- }
- return 0;
-}
+ return id;
+ }
+ return 0;
+ }
#ifdef ___SYNC_ENABLED___
-void UserDict::queue_lemma_for_sync(LemmaIdType id) {
- if (dict_info_.sync_count < sync_count_size_) {
- syncs_[dict_info_.sync_count++] = offsets_by_id_[id - start_id_];
- } else {
- uint32 * syncs = (uint32*)realloc(
- syncs_, (sync_count_size_ + kUserDictPreAlloc) << 2);
- if (syncs) {
- sync_count_size_ += kUserDictPreAlloc;
- syncs_ = syncs;
- syncs_[dict_info_.sync_count++] = offsets_by_id_[id - start_id_];
- }
- }
-}
+ void UserDict::queue_lemma_for_sync ( LemmaIdType id ) {
+ if ( dict_info_.sync_count < sync_count_size_ ) {
+ syncs_[dict_info_.sync_count++] = offsets_by_id_[id - start_id_];
+ } else {
+ uint32 *syncs = ( uint32 * ) realloc (
+ syncs_, ( sync_count_size_ + kUserDictPreAlloc ) << 2 );
+ if ( syncs ) {
+ sync_count_size_ += kUserDictPreAlloc;
+ syncs_ = syncs;
+ syncs_[dict_info_.sync_count++] = offsets_by_id_[id - start_id_];
+ }
+ }
+ }
#endif
-LemmaIdType UserDict::update_lemma(LemmaIdType lemma_id, int16 delta_count,
- bool selected) {
+ LemmaIdType UserDict::update_lemma ( LemmaIdType lemma_id, int16 delta_count,
+ bool selected ) {
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_BEGIN;
-#endif
- if (is_valid_state() == false)
- return 0;
- if (is_valid_lemma_id(lemma_id) == false)
- return 0;
- uint32 offset = offsets_by_id_[lemma_id - start_id_];
- uint8 lemma_len = get_lemma_nchar(offset);
- char16 * lemma_str = get_lemma_word(offset);
- uint16 * splids = get_lemma_spell_ids(offset);
-
- int32 off = locate_in_offsets(lemma_str, splids, lemma_len);
- if (off != -1) {
- int score = scores_[off];
- int count = extract_score_freq(score);
- uint64 lmt = extract_score_lmt(score);
- if (count + delta_count > kUserDictMaxFrequency ||
- count + delta_count < count) {
- delta_count = kUserDictMaxFrequency - count;
- }
- count += delta_count;
- dict_info_.total_nfreq += delta_count;
- if (selected) {
- lmt = time(NULL);
- }
- scores_[off] = build_score(lmt, count);
- if (state_ < USER_DICT_SCORE_DIRTY)
- state_ = USER_DICT_SCORE_DIRTY;
+ DEBUG_PERF_BEGIN;
+#endif
+ if ( is_valid_state() == false )
+ { return 0; }
+ if ( is_valid_lemma_id ( lemma_id ) == false )
+ { return 0; }
+ uint32 offset = offsets_by_id_[lemma_id - start_id_];
+ uint8 lemma_len = get_lemma_nchar ( offset );
+ char16 *lemma_str = get_lemma_word ( offset );
+ uint16 *splids = get_lemma_spell_ids ( offset );
+ int32 off = locate_in_offsets ( lemma_str, splids, lemma_len );
+ if ( off != -1 ) {
+ int score = scores_[off];
+ int count = extract_score_freq ( score );
+ uint64 lmt = extract_score_lmt ( score );
+ if ( count + delta_count > kUserDictMaxFrequency ||
+ count + delta_count < count ) {
+ delta_count = kUserDictMaxFrequency - count;
+ }
+ count += delta_count;
+ dict_info_.total_nfreq += delta_count;
+ if ( selected ) {
+ lmt = time ( NULL );
+ }
+ scores_[off] = build_score ( lmt, count );
+ if ( state_ < USER_DICT_SCORE_DIRTY )
+ { state_ = USER_DICT_SCORE_DIRTY; }
#ifdef ___DEBUG_PERF___
- DEBUG_PERF_END;
- LOGD_PERF("update_lemma");
+ DEBUG_PERF_END;
+ LOGD_PERF ( "update_lemma" );
#endif
#ifdef ___SYNC_ENABLED___
- queue_lemma_for_sync(ids_[off]);
+ queue_lemma_for_sync ( ids_[off] );
#endif
- return ids_[off];
- }
- return 0;
-}
+ return ids_[off];
+ }
+ return 0;
+ }
-size_t UserDict::get_total_lemma_count() {
- return dict_info_.total_nfreq;
-}
+ size_t UserDict::get_total_lemma_count() {
+ return dict_info_.total_nfreq;
+ }
-void UserDict::set_total_lemma_count_of_others(size_t count) {
- total_other_nfreq_ = count;
-}
+ void UserDict::set_total_lemma_count_of_others ( size_t count ) {
+ total_other_nfreq_ = count;
+ }
-LemmaIdType UserDict::append_a_lemma(char16 lemma_str[], uint16 splids[],
- uint16 lemma_len, uint16 count, uint64 lmt) {
- LemmaIdType id = get_max_lemma_id() + 1;
- size_t offset = dict_info_.lemma_size;
- if (offset > kUserDictOffsetMask)
- return 0;
-
- lemmas_[offset] = 0;
- lemmas_[offset + 1] = (uint8)lemma_len;
- for (size_t i = 0; i < lemma_len; i++) {
- *((uint16*)&lemmas_[offset + 2 + (i << 1)]) = splids[i];
- *((char16*)&lemmas_[offset + 2 + (lemma_len << 1) + (i << 1)])
- = lemma_str[i];
- }
- uint32 off = dict_info_.lemma_count;
- offsets_[off] = offset;
- scores_[off] = build_score(lmt, count);
- ids_[off] = id;
+ LemmaIdType UserDict::append_a_lemma ( char16 lemma_str[], uint16 splids[],
+ uint16 lemma_len, uint16 count, uint64 lmt ) {
+ LemmaIdType id = get_max_lemma_id() + 1;
+ size_t offset = dict_info_.lemma_size;
+ if ( offset > kUserDictOffsetMask )
+ { return 0; }
+ lemmas_[offset] = 0;
+ lemmas_[offset + 1] = ( uint8 ) lemma_len;
+ for ( size_t i = 0; i < lemma_len; i++ ) {
+ * ( ( uint16 * ) &lemmas_[offset + 2 + ( i << 1 )] ) = splids[i];
+ * ( ( char16 * ) &lemmas_[offset + 2 + ( lemma_len << 1 ) + ( i << 1 )] )
+ = lemma_str[i];
+ }
+ uint32 off = dict_info_.lemma_count;
+ offsets_[off] = offset;
+ scores_[off] = build_score ( lmt, count );
+ ids_[off] = id;
#ifdef ___PREDICT_ENABLED___
- predicts_[off] = offset;
-#endif
-
- offsets_by_id_[id - start_id_] = offset;
-
- dict_info_.lemma_count++;
- dict_info_.lemma_size += (2 + (lemma_len << 2));
- lemma_count_left_--;
- lemma_size_left_ -= (2 + (lemma_len << 2));
-
- // Sort
-
- UserDictSearchable searchable;
- prepare_locate(&searchable, splids, lemma_len);
-
- size_t i = 0;
- while (i < off) {
- offset = offsets_[i];
- uint32 nchar = get_lemma_nchar(offset);
- uint16 * spl = get_lemma_spell_ids(offset);
-
- if (0 <= fuzzy_compare_spell_id(spl, nchar, &searchable))
- break;
- i++;
- }
- if (i != off) {
- uint32 temp = offsets_[off];
- memmove(offsets_ + i + 1, offsets_ + i, (off - i) << 2);
- offsets_[i] = temp;
-
- temp = scores_[off];
- memmove(scores_ + i + 1, scores_ + i, (off - i) << 2);
- scores_[i] = temp;
-
- temp = ids_[off];
- memmove(ids_ + i + 1, ids_ + i, (off - i) << 2);
- ids_[i] = temp;
- }
-
+ predicts_[off] = offset;
+#endif
+ offsets_by_id_[id - start_id_] = offset;
+ dict_info_.lemma_count++;
+ dict_info_.lemma_size += ( 2 + ( lemma_len << 2 ) );
+ lemma_count_left_--;
+ lemma_size_left_ -= ( 2 + ( lemma_len << 2 ) );
+ // Sort
+ UserDictSearchable searchable;
+ prepare_locate ( &searchable, splids, lemma_len );
+ size_t i = 0;
+ while ( i < off ) {
+ offset = offsets_[i];
+ uint32 nchar = get_lemma_nchar ( offset );
+ uint16 *spl = get_lemma_spell_ids ( offset );
+ if ( 0 <= fuzzy_compare_spell_id ( spl, nchar, &searchable ) )
+ { break; }
+ i++;
+ }
+ if ( i != off ) {
+ uint32 temp = offsets_[off];
+ memmove ( offsets_ + i + 1, offsets_ + i, ( off - i ) << 2 );
+ offsets_[i] = temp;
+ temp = scores_[off];
+ memmove ( scores_ + i + 1, scores_ + i, ( off - i ) << 2 );
+ scores_[i] = temp;
+ temp = ids_[off];
+ memmove ( ids_ + i + 1, ids_ + i, ( off - i ) << 2 );
+ ids_[i] = temp;
+ }
#ifdef ___PREDICT_ENABLED___
- uint32 j = 0;
- uint16 * words_new = get_lemma_word(predicts_[off]);
- j = locate_where_to_insert_in_predicts(words_new, lemma_len);
- if (j != off) {
- uint32 temp = predicts_[off];
- memmove(predicts_ + j + 1, predicts_ + j, (off - j) << 2);
- predicts_[j] = temp;
- }
+ uint32 j = 0;
+ uint16 *words_new = get_lemma_word ( predicts_[off] );
+ j = locate_where_to_insert_in_predicts ( words_new, lemma_len );
+ if ( j != off ) {
+ uint32 temp = predicts_[off];
+ memmove ( predicts_ + j + 1, predicts_ + j, ( off - j ) << 2 );
+ predicts_[j] = temp;
+ }
#endif
-
- if (state_ < USER_DICT_LEMMA_DIRTY)
- state_ = USER_DICT_LEMMA_DIRTY;
-
+ if ( state_ < USER_DICT_LEMMA_DIRTY )
+ { state_ = USER_DICT_LEMMA_DIRTY; }
#ifdef ___CACHE_ENABLED___
- cache_init();
+ cache_init();
#endif
-
- dict_info_.total_nfreq += count;
- return id;
-}
+ dict_info_.total_nfreq += count;
+ return id;
+ }
}
diff --git a/jni/share/utf16char.cpp b/jni/share/utf16char.cpp
index fadb6cf..a295a18 100755
--- a/jni/share/utf16char.cpp
+++ b/jni/share/utf16char.cpp
@@ -20,163 +20,138 @@
namespace ime_pinyin {
#ifdef __cplusplus
-extern "C" {
+ extern "C" {
#endif
- char16* utf16_strtok(char16 *utf16_str, size_t *token_size,
- char16 **utf16_str_next) {
- if (NULL == utf16_str || NULL == token_size || NULL == utf16_str_next) {
- return NULL;
- }
-
- // Skip the splitters
- size_t pos = 0;
- while ((char16)' ' == utf16_str[pos] || (char16)'\n' == utf16_str[pos]
- || (char16)'\t' == utf16_str[pos])
- pos++;
-
- utf16_str += pos;
- pos = 0;
-
- while ((char16)'\0' != utf16_str[pos] && (char16)' ' != utf16_str[pos]
- && (char16)'\n' != utf16_str[pos]
- && (char16)'\t' != utf16_str[pos]) {
- pos++;
- }
-
- char16 *ret_val = utf16_str;
- if ((char16)'\0' == utf16_str[pos]) {
- *utf16_str_next = NULL;
- if (0 == pos)
- return NULL;
- } else {
- *utf16_str_next = utf16_str + pos + 1;
- }
-
- utf16_str[pos] = (char16)'\0';
- *token_size = pos;
-
- return ret_val;
- }
-
- int utf16_atoi(const char16 *utf16_str) {
- if (NULL == utf16_str)
- return 0;
-
- int value = 0;
- int sign = 1;
- size_t pos = 0;
-
- if ((char16)'-' == utf16_str[pos]) {
- sign = -1;
- pos++;
- }
-
- while ((char16)'0' <= utf16_str[pos] &&
- (char16)'9' >= utf16_str[pos]) {
- value = value * 10 + static_cast<int>(utf16_str[pos] - (char16)'0');
- pos++;
- }
-
- return value*sign;
- }
-
- float utf16_atof(const char16 *utf16_str) {
- // A temporary implemetation.
- char char8[256];
- if (utf16_strlen(utf16_str) >= 256) return 0;
-
- utf16_strcpy_tochar(char8, utf16_str);
- return atof(char8);
- }
-
- size_t utf16_strlen(const char16 *utf16_str) {
- if (NULL == utf16_str)
- return 0;
-
- size_t size = 0;
- while ((char16)'\0' != utf16_str[size])
- size++;
- return size;
- }
-
- int utf16_strcmp(const char16* str1, const char16* str2) {
- size_t pos = 0;
- while (str1[pos] == str2[pos] && (char16)'\0' != str1[pos])
- pos++;
-
- return static_cast<int>(str1[pos]) - static_cast<int>(str2[pos]);
- }
-
- int utf16_strncmp(const char16 *str1, const char16 *str2, size_t size) {
- size_t pos = 0;
- while (pos < size && str1[pos] == str2[pos] && (char16)'\0' != str1[pos])
- pos++;
-
- if (pos == size)
- return 0;
-
- return static_cast<int>(str1[pos]) - static_cast<int>(str2[pos]);
- }
-
- // we do not consider overlapping
- char16* utf16_strcpy(char16 *dst, const char16 *src) {
- if (NULL == src || NULL == dst)
- return NULL;
-
- char16* cp = dst;
-
- while ((char16)'\0' != *src) {
- *cp = *src;
- cp++;
- src++;
- }
-
- *cp = *src;
-
- return dst;
- }
-
- char16* utf16_strncpy(char16 *dst, const char16 *src, size_t size) {
- if (NULL == src || NULL == dst || 0 == size)
- return NULL;
-
- if (src == dst)
- return dst;
-
- char16* cp = dst;
-
- if (dst < src || (dst > src && dst >= src + size)) {
- while (size-- && (*cp++ = *src++))
- ;
- } else {
- cp += size - 1;
- src += size - 1;
- while (size-- && (*cp-- == *src--))
- ;
- }
- return dst;
- }
-
- // We do not handle complicated cases like overlapping, because in this
- // codebase, it is not necessary.
- char* utf16_strcpy_tochar(char *dst, const char16 *src) {
- if (NULL == src || NULL == dst)
- return NULL;
-
- char* cp = dst;
-
- while ((char16)'\0' != *src) {
- *cp = static_cast<char>(*src);
- cp++;
- src++;
- }
- *cp = *src;
-
- return dst;
- }
+ char16 *utf16_strtok ( char16 *utf16_str, size_t *token_size,
+ char16 **utf16_str_next ) {
+ if ( NULL == utf16_str || NULL == token_size || NULL == utf16_str_next ) {
+ return NULL;
+ }
+ // Skip the splitters
+ size_t pos = 0;
+ while ( ( char16 ) ' ' == utf16_str[pos] || ( char16 ) '\n' == utf16_str[pos]
+ || ( char16 ) '\t' == utf16_str[pos] )
+ { pos++; }
+ utf16_str += pos;
+ pos = 0;
+ while ( ( char16 ) '\0' != utf16_str[pos] && ( char16 ) ' ' != utf16_str[pos]
+ && ( char16 ) '\n' != utf16_str[pos]
+ && ( char16 ) '\t' != utf16_str[pos] ) {
+ pos++;
+ }
+ char16 *ret_val = utf16_str;
+ if ( ( char16 ) '\0' == utf16_str[pos] ) {
+ *utf16_str_next = NULL;
+ if ( 0 == pos )
+ { return NULL; }
+ } else {
+ *utf16_str_next = utf16_str + pos + 1;
+ }
+ utf16_str[pos] = ( char16 ) '\0';
+ *token_size = pos;
+ return ret_val;
+ }
+
+ int utf16_atoi ( const char16 *utf16_str ) {
+ if ( NULL == utf16_str )
+ { return 0; }
+ int value = 0;
+ int sign = 1;
+ size_t pos = 0;
+ if ( ( char16 ) '-' == utf16_str[pos] ) {
+ sign = -1;
+ pos++;
+ }
+ while ( ( char16 ) '0' <= utf16_str[pos] &&
+ ( char16 ) '9' >= utf16_str[pos] ) {
+ value = value * 10 + static_cast<int> ( utf16_str[pos] - ( char16 ) '0' );
+ pos++;
+ }
+ return value * sign;
+ }
+
+ float utf16_atof ( const char16 *utf16_str ) {
+ // A temporary implemetation.
+ char char8[256];
+ if ( utf16_strlen ( utf16_str ) >= 256 ) { return 0; }
+ utf16_strcpy_tochar ( char8, utf16_str );
+ return atof ( char8 );
+ }
+
+ size_t utf16_strlen ( const char16 *utf16_str ) {
+ if ( NULL == utf16_str )
+ { return 0; }
+ size_t size = 0;
+ while ( ( char16 ) '\0' != utf16_str[size] )
+ { size++; }
+ return size;
+ }
+
+ int utf16_strcmp ( const char16 *str1, const char16 *str2 ) {
+ size_t pos = 0;
+ while ( str1[pos] == str2[pos] && ( char16 ) '\0' != str1[pos] )
+ { pos++; }
+ return static_cast<int> ( str1[pos] ) - static_cast<int> ( str2[pos] );
+ }
+
+ int utf16_strncmp ( const char16 *str1, const char16 *str2, size_t size ) {
+ size_t pos = 0;
+ while ( pos < size && str1[pos] == str2[pos] && ( char16 ) '\0' != str1[pos] )
+ { pos++; }
+ if ( pos == size )
+ { return 0; }
+ return static_cast<int> ( str1[pos] ) - static_cast<int> ( str2[pos] );
+ }
+
+ // we do not consider overlapping
+ char16 *utf16_strcpy ( char16 *dst, const char16 *src ) {
+ if ( NULL == src || NULL == dst )
+ { return NULL; }
+ char16 *cp = dst;
+ while ( ( char16 ) '\0' != *src ) {
+ *cp = *src;
+ cp++;
+ src++;
+ }
+ *cp = *src;
+ return dst;
+ }
+
+ char16 *utf16_strncpy ( char16 *dst, const char16 *src, size_t size ) {
+ if ( NULL == src || NULL == dst || 0 == size )
+ { return NULL; }
+ if ( src == dst )
+ { return dst; }
+ char16 *cp = dst;
+ if ( dst < src || ( dst > src && dst >= src + size ) ) {
+ while ( size-- && ( *cp++ = *src++ ) )
+ ;
+ } else {
+ cp += size - 1;
+ src += size - 1;
+ while ( size-- && ( *cp-- == *src-- ) )
+ ;
+ }
+ return dst;
+ }
+
+ // We do not handle complicated cases like overlapping, because in this
+ // codebase, it is not necessary.
+ char *utf16_strcpy_tochar ( char *dst, const char16 *src ) {
+ if ( NULL == src || NULL == dst )
+ { return NULL; }
+ char *cp = dst;
+ while ( ( char16 ) '\0' != *src ) {
+ *cp = static_cast<char> ( *src );
+ cp++;
+ src++;
+ }
+ *cp = *src;
+ return dst;
+ }
#ifdef __cplusplus
-}
+ }
#endif
} // namespace ime_pinyin
diff --git a/jni/share/utf16reader.cpp b/jni/share/utf16reader.cpp
index d8e5de5..3f4e0ca 100755
--- a/jni/share/utf16reader.cpp
+++ b/jni/share/utf16reader.cpp
@@ -21,111 +21,97 @@ namespace ime_pinyin {
#define MIN_BUF_LEN 128
#define MAX_BUF_LEN 65535
-Utf16Reader::Utf16Reader() {
- fp_ = NULL;
- buffer_ = NULL;
- buffer_total_len_ = 0;
- buffer_next_pos_ = 0;
- buffer_valid_len_ = 0;
-}
-
-Utf16Reader::~Utf16Reader() {
- if (NULL != fp_)
- fclose(fp_);
-
- if (NULL != buffer_)
- delete [] buffer_;
-}
-
-
-bool Utf16Reader::open(const char* filename, size_t buffer_len) {
- if (filename == NULL)
- return false;
-
- if (buffer_len < MIN_BUF_LEN)
- buffer_len = MIN_BUF_LEN;
- else if (buffer_len > MAX_BUF_LEN)
- buffer_len = MAX_BUF_LEN;
-
- buffer_total_len_ = buffer_len;
-
- if (NULL != buffer_)
- delete [] buffer_;
- buffer_ = new char16[buffer_total_len_];
- if (NULL == buffer_)
- return false;
-
- if ((fp_ = fopen(filename, "rb")) == NULL)
- return false;
-
- // the UTF16 file header, skip
- char16 header;
- if (fread(&header, sizeof(header), 1, fp_) != 1 || header != 0xfeff) {
- fclose(fp_);
- fp_ = NULL;
- return false;
- }
-
- return true;
-}
-
-char16* Utf16Reader::readline(char16* read_buf, size_t max_len) {
- if (NULL == fp_ || NULL == read_buf || 0 == max_len)
- return NULL;
-
- size_t ret_len = 0;
+ Utf16Reader::Utf16Reader() {
+ fp_ = NULL;
+ buffer_ = NULL;
+ buffer_total_len_ = 0;
+ buffer_next_pos_ = 0;
+ buffer_valid_len_ = 0;
+ }
- do {
- if (buffer_valid_len_ == 0) {
- buffer_next_pos_ = 0;
- buffer_valid_len_ = fread(buffer_, sizeof(char16),
- buffer_total_len_, fp_);
- if (buffer_valid_len_ == 0) {
- if (0 == ret_len)
- return NULL;
- read_buf[ret_len] = (char16)'\0';
- return read_buf;
- }
+ Utf16Reader::~Utf16Reader() {
+ if ( NULL != fp_ )
+ { fclose ( fp_ ); }
+ if ( NULL != buffer_ )
+ { delete [] buffer_; }
}
- for (size_t i = 0; i < buffer_valid_len_; i++) {
- if (i == max_len - 1 ||
- buffer_[buffer_next_pos_ + i] == (char16)'\n') {
- if (ret_len + i > 0 && read_buf[ret_len + i - 1] == (char16)'\r') {
- read_buf[ret_len + i - 1] = (char16)'\0';
- } else {
- read_buf[ret_len + i] = (char16)'\0';
- }
- i++;
- buffer_next_pos_ += i;
- buffer_valid_len_ -= i;
- if (buffer_next_pos_ == buffer_total_len_) {
- buffer_next_pos_ = 0;
- buffer_valid_len_ = 0;
+ bool Utf16Reader::open ( const char *filename, size_t buffer_len ) {
+ if ( filename == NULL )
+ { return false; }
+ if ( buffer_len < MIN_BUF_LEN )
+ { buffer_len = MIN_BUF_LEN; }
+ else if ( buffer_len > MAX_BUF_LEN )
+ { buffer_len = MAX_BUF_LEN; }
+ buffer_total_len_ = buffer_len;
+ if ( NULL != buffer_ )
+ { delete [] buffer_; }
+ buffer_ = new char16[buffer_total_len_];
+ if ( NULL == buffer_ )
+ { return false; }
+ if ( ( fp_ = fopen ( filename, "rb" ) ) == NULL )
+ { return false; }
+ // the UTF16 file header, skip
+ char16 header;
+ if ( fread ( &header, sizeof ( header ), 1, fp_ ) != 1 || header != 0xfeff ) {
+ fclose ( fp_ );
+ fp_ = NULL;
+ return false;
}
- return read_buf;
- } else {
- read_buf[ret_len + i] = buffer_[buffer_next_pos_ + i];
- }
+ return true;
}
- ret_len += buffer_valid_len_;
- buffer_valid_len_ = 0;
- } while (true);
-
- // Never reach here
- return NULL;
-}
-
-bool Utf16Reader::close() {
- if (NULL != fp_)
- fclose(fp_);
- fp_ = NULL;
+ char16 *Utf16Reader::readline ( char16 *read_buf, size_t max_len ) {
+ if ( NULL == fp_ || NULL == read_buf || 0 == max_len )
+ { return NULL; }
+ size_t ret_len = 0;
+ do {
+ if ( buffer_valid_len_ == 0 ) {
+ buffer_next_pos_ = 0;
+ buffer_valid_len_ = fread ( buffer_, sizeof ( char16 ),
+ buffer_total_len_, fp_ );
+ if ( buffer_valid_len_ == 0 ) {
+ if ( 0 == ret_len )
+ { return NULL; }
+ read_buf[ret_len] = ( char16 ) '\0';
+ return read_buf;
+ }
+ }
+ for ( size_t i = 0; i < buffer_valid_len_; i++ ) {
+ if ( i == max_len - 1 ||
+ buffer_[buffer_next_pos_ + i] == ( char16 ) '\n' ) {
+ if ( ret_len + i > 0 && read_buf[ret_len + i - 1] == ( char16 ) '\r' ) {
+ read_buf[ret_len + i - 1] = ( char16 ) '\0';
+ } else {
+ read_buf[ret_len + i] = ( char16 ) '\0';
+ }
+ i++;
+ buffer_next_pos_ += i;
+ buffer_valid_len_ -= i;
+ if ( buffer_next_pos_ == buffer_total_len_ ) {
+ buffer_next_pos_ = 0;
+ buffer_valid_len_ = 0;
+ }
+ return read_buf;
+ } else {
+ read_buf[ret_len + i] = buffer_[buffer_next_pos_ + i];
+ }
+ }
+ ret_len += buffer_valid_len_;
+ buffer_valid_len_ = 0;
+ } while ( true );
+ // Never reach here
+ return NULL;
+ }
- if (NULL != buffer_)
- delete [] buffer_;
- buffer_ = NULL;
- return true;
-}
+ bool Utf16Reader::close() {
+ if ( NULL != fp_ )
+ { fclose ( fp_ ); }
+ fp_ = NULL;
+ if ( NULL != buffer_ )
+ { delete [] buffer_; }
+ buffer_ = NULL;
+ return true;
+ }
} // namespace ime_pinyin
diff --git a/lib/Android.mk b/lib/Android.mk
index 1348ab4..15f2bbc 100755
--- a/lib/Android.mk
+++ b/lib/Android.mk
@@ -3,8 +3,8 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(call all-subdir-java-files) \
- com/amlogic/inputmethod/remote/IPinyinDecoderService.aidl
+ com/droidlogic/inputmethod/remote/IPinyinDecoderService.aidl
-LOCAL_MODULE := com.amlogic.inputmethod.remote.lib
+LOCAL_MODULE := com.droidlogic.inputmethod.remote.lib
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/lib/com/amlogic/inputmethod/remote/IPinyinDecoderService.aidl b/lib/com/droidlogic/inputmethod/remote/IPinyinDecoderService.aidl
index 6e7104f..55a43c3 100755
--- a/lib/com/amlogic/inputmethod/remote/IPinyinDecoderService.aidl
+++ b/lib/com/droidlogic/inputmethod/remote/IPinyinDecoderService.aidl
@@ -15,7 +15,7 @@
*/
-package com.amlogic.inputmethod.remote;
+package com.droidlogic.inputmethod.remote;
interface IPinyinDecoderService {
int getInt();
diff --git a/res/drawable-nodpi/arrow_bg.xml b/res/drawable-nodpi/arrow_bg.xml
index 9125232..bd620eb 100755
--- a/res/drawable-nodpi/arrow_bg.xml
+++ b/res/drawable-nodpi/arrow_bg.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,6 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false"
- android:drawable="@android:color/transparent" />
- <item android:state_pressed="true"
- android:drawable="@drawable/candidate_hl_bg" />
+ <item android:state_pressed="false" android:drawable="@android:color/transparent" />
+ <item android:state_pressed="true" android:drawable="@drawable/candidate_hl_bg" />
</selector>
diff --git a/res/layout/candidates_container.xml b/res/layout/candidates_container.xml
index a461570..667e54e 100755
--- a/res/layout/candidates_container.xml
+++ b/res/layout/candidates_container.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,43 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.amlogic.inputmethod.remote.CandidatesContainer xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/candidates_container"
- android:background="@drawable/cands_container_bg"
- android:orientation="horizontal"
- android:layout_width="0dip"
- android:layout_height="0dip"
- android:focusable="true"
- android:focusableInTouchMode="true">
-
- <ImageButton android:id="@+id/arrow_left_btn"
- android:background="@drawable/arrow_bg"
- android:src="@drawable/arrow_left"
- android:layout_height="match_parent"
- android:layout_width="30dip"
- android:clickable="true"
- android:layout_alignParentLeft="true"/>
-
- <ImageButton android:id="@+id/arrow_right_btn"
- android:background="@drawable/arrow_bg"
- android:src="@drawable/arrow_right"
- android:layout_width="30dip"
- android:layout_height="match_parent"
- android:clickable="true"
- android:layout_alignParentRight="true"/>
-
- <ViewFlipper android:id="@+id/candidate_flipper"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/arrow_right_btn"
- android:layout_toRightOf="@id/arrow_left_btn">
- <view class="com.amlogic.inputmethod.remote.CandidateView"
- android:id="@+id/candidate_view1"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <view class="com.amlogic.inputmethod.remote.CandidateView"
- android:id="@+id/candidate_view2"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+<com.droidlogic.inputmethod.remote.CandidatesContainer xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/candidates_container" android:background="@drawable/cands_container_bg" android:orientation="horizontal" android:layout_width="0dip" android:layout_height="0dip" android:focusable="true" android:focusableInTouchMode="true">
+ <ImageButton android:id="@+id/arrow_left_btn" android:background="@drawable/arrow_bg" android:src="@drawable/arrow_left" android:layout_height="match_parent" android:layout_width="30dip" android:clickable="true" android:layout_alignParentLeft="true" />
+ <ImageButton android:id="@+id/arrow_right_btn" android:background="@drawable/arrow_bg" android:src="@drawable/arrow_right" android:layout_width="30dip" android:layout_height="match_parent" android:clickable="true" android:layout_alignParentRight="true" />
+ <ViewFlipper android:id="@+id/candidate_flipper" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_toLeftOf="@id/arrow_right_btn" android:layout_toRightOf="@id/arrow_left_btn">
+ <view class="com.droidlogic.inputmethod.remote.CandidateView" android:id="@+id/candidate_view1" android:layout_width="match_parent" android:layout_height="match_parent" />
+ <view class="com.droidlogic.inputmethod.remote.CandidateView" android:id="@+id/candidate_view2" android:layout_width="match_parent" android:layout_height="match_parent" />
</ViewFlipper>
-</com.amlogic.inputmethod.remote.CandidatesContainer>
+</com.droidlogic.inputmethod.remote.CandidatesContainer>
diff --git a/res/layout/floating_container.xml b/res/layout/floating_container.xml
index 4c93d97..5de587c 100755
--- a/res/layout/floating_container.xml
+++ b/res/layout/floating_container.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,15 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/floating_container"
- android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <com.amlogic.inputmethod.remote.ComposingView
- android:id="@+id/composing_view"
- android:background="@drawable/composing_area_bg"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/floating_container" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content">
+ <com.droidlogic.inputmethod.remote.ComposingView android:id="@+id/composing_view" android:background="@drawable/composing_area_bg" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
diff --git a/res/layout/skb_container.xml b/res/layout/skb_container.xml
index 1102481..5892166 100755
--- a/res/layout/skb_container.xml
+++ b/res/layout/skb_container.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,27 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.amlogic.inputmethod.remote.SkbContainer xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:background="@drawable/skb_container_bg"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:focusableInTouchMode="true" >
-
- <ViewFlipper
- android:id="@+id/alpha_floatable"
- android:layout_alignParentBottom="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <com.amlogic.inputmethod.remote.SoftKeyboardView
- android:id="@+id/alpha_view1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
- <com.amlogic.inputmethod.remote.SoftKeyboardView
- android:id="@+id/alpha_view2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+<com.droidlogic.inputmethod.remote.SkbContainer xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="@drawable/skb_container_bg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="true" android:focusableInTouchMode="true">
+ <ViewFlipper android:id="@+id/alpha_floatable" android:layout_alignParentBottom="true" android:layout_width="wrap_content" android:layout_height="wrap_content">
+ <com.droidlogic.inputmethod.remote.SoftKeyboardView android:id="@+id/alpha_view1" android:layout_width="wrap_content" android:layout_height="wrap_content" />
+ <com.droidlogic.inputmethod.remote.SoftKeyboardView android:id="@+id/alpha_view2" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</ViewFlipper>
-</com.amlogic.inputmethod.remote.SkbContainer>
+</com.droidlogic.inputmethod.remote.SkbContainer>
diff --git a/res/values-en/bools.xml b/res/values-en/bools.xml
index 3bb0599..e180ce9 100755
--- a/res/values-en/bools.xml
+++ b/res/values-en/bools.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,5 +16,5 @@
<resources>
<bool name="im_is_default">true</bool>
<!-- The default to true for most of board -->
- <bool name="is_enableEnter">true</bool>
+ <bool name="is_enableEnter">true</bool>
</resources>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 3ee7751..64bda22 100755
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,6 +14,6 @@
limitations under the License.
-->
<resources>
- <dimen name="candidate_margin_left_right">10dip</dimen>
- <dimen name="composing_height">16dip</dimen>
+ <dimen name="candidate_margin_left_right">10dip</dimen>
+ <dimen name="composing_height">16dip</dimen>
</resources>
diff --git a/res/values-port/dimens.xml b/res/values-port/dimens.xml
index 47a3a53..f576208 100755
--- a/res/values-port/dimens.xml
+++ b/res/values-port/dimens.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,6 +14,6 @@
limitations under the License.
-->
<resources>
- <dimen name="candidate_margin_left_right">3dip</dimen>
- <dimen name="composing_height">18dip</dimen>
+ <dimen name="candidate_margin_left_right">3dip</dimen>
+ <dimen name="composing_height">18dip</dimen>
</resources>
diff --git a/res/values-zh-rCN/bools.xml b/res/values-zh-rCN/bools.xml
index 3bb0599..e180ce9 100755
--- a/res/values-zh-rCN/bools.xml
+++ b/res/values-zh-rCN/bools.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,5 +16,5 @@
<resources>
<bool name="im_is_default">true</bool>
<!-- The default to true for most of board -->
- <bool name="is_enableEnter">true</bool>
+ <bool name="is_enableEnter">true</bool>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 206ad15..3bad2b0 100755
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,56 +14,50 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ime_name">遥控器输入法</string>
- <string name="ime_settings_activity_name">遥控器输入法设置</string>
- <!-- version = apk(java) + ime engine + sys dict + [hotlist (TBD)] -->
- <string name="version">1.0.0</string>
-
- <!-- Used by the toggle keys in soft keyboards.-->
- <string name="toggle_cn">0</string>
- <string name="toggle_cn_cand">1</string>
- <string name="toggle_en_lower">2</string>
- <string name="toggle_en_upper">3</string>
- <string name="toggle_en_sym1">4</string>
- <string name="toggle_en_sym2">5</string>
- <string name="toggle_smiley">6</string>
- <string name="toggle_enter_go">7</string>
- <string name="toggle_enter_search">8</string>
- <string name="toggle_enter_send">9</string>
- <string name="toggle_enter_next">10</string>
- <string name="toggle_enter_done">11</string>
- <string name="toggle_row_cn">12</string>
- <string name="toggle_row_en">13</string>
- <string name="toggle_row_uri">14</string>
- <string name="toggle_row_emailaddress">15</string>
- <string name="toggle_phone_sym">3</string>
-
- <!-- settings related -->
- <string name="setting_sound_key">setting_sound_key</string>
- <string name="setting_vibrate_key">setting_vibrate_key</string>
- <string name="setting_prediction_key">setting_prediction_key</string>
- <string name="setting_switch_key">setting_switch_key</string>
- <string name="setting_advanced_key">setting_advanced_key</string>
-
- <string name="setting">遥控器输入法设置</string>
- <string name="setting_sound_key_title">按键声音</string>
- <string name="setting_vibrate_title">按键震动</string>
- <string name="setting_prediction_title">联想输入</string>
- <string name="setting_switch_title">中英文切换</string>
- <string name="setting_switch_shift_space_title">Shift-space</string>
-
- <string name="setting_enabled">开启</string>
- <string name="setting_disabled">关闭</string>
-
- <string name="setting_others">其它设置</string>
- <string name="setting_others_summary">词典同步等</string>
-
- <string name="toggle_enter_go_label">去往</string>
- <string name="toggle_enter_send_label">发送</string>
- <string name="toggle_enter_next_label">下一个</string>
- <string name="toggle_enter_done_label">完成</string>
- <string name="toggle_en_label">英 文</string>
- <string name="toggle_cn_label">中 文</string>
- <string name="sym_en_label">英 符</string>
- <string name="sym_cn_label">中 符</string>
+ <string name="ime_name">遥控器输入法</string>
+ <string name="ime_settings_activity_name">遥控器输入法设置</string>
+ <!-- version = apk(java) + ime engine + sys dict + [hotlist (TBD)] -->
+ <string name="version">1.0.0</string>
+ <!-- Used by the toggle keys in soft keyboards.-->
+ <string name="toggle_cn">0</string>
+ <string name="toggle_cn_cand">1</string>
+ <string name="toggle_en_lower">2</string>
+ <string name="toggle_en_upper">3</string>
+ <string name="toggle_en_sym1">4</string>
+ <string name="toggle_en_sym2">5</string>
+ <string name="toggle_smiley">6</string>
+ <string name="toggle_enter_go">7</string>
+ <string name="toggle_enter_search">8</string>
+ <string name="toggle_enter_send">9</string>
+ <string name="toggle_enter_next">10</string>
+ <string name="toggle_enter_done">11</string>
+ <string name="toggle_row_cn">12</string>
+ <string name="toggle_row_en">13</string>
+ <string name="toggle_row_uri">14</string>
+ <string name="toggle_row_emailaddress">15</string>
+ <string name="toggle_phone_sym">3</string>
+ <!-- settings related -->
+ <string name="setting_sound_key">setting_sound_key</string>
+ <string name="setting_vibrate_key">setting_vibrate_key</string>
+ <string name="setting_prediction_key">setting_prediction_key</string>
+ <string name="setting_switch_key">setting_switch_key</string>
+ <string name="setting_advanced_key">setting_advanced_key</string>
+ <string name="setting">遥控器输入法设置</string>
+ <string name="setting_sound_key_title">按键声音</string>
+ <string name="setting_vibrate_title">按键震动</string>
+ <string name="setting_prediction_title">联想输入</string>
+ <string name="setting_switch_title">中英文切换</string>
+ <string name="setting_switch_shift_space_title">Shift-space</string>
+ <string name="setting_enabled">开启</string>
+ <string name="setting_disabled">关闭</string>
+ <string name="setting_others">其它设置</string>
+ <string name="setting_others_summary">词典同步等</string>
+ <string name="toggle_enter_go_label">去往</string>
+ <string name="toggle_enter_send_label">发送</string>
+ <string name="toggle_enter_next_label">下一个</string>
+ <string name="toggle_enter_done_label">完成</string>
+ <string name="toggle_en_label">英 文</string>
+ <string name="toggle_cn_label">中 文</string>
+ <string name="sym_en_label">英 符</string>
+ <string name="sym_cn_label">中 符</string>
</resources>
diff --git a/res/values-zh-rTW/bools.xml b/res/values-zh-rTW/bools.xml
index 3bb0599..e180ce9 100755
--- a/res/values-zh-rTW/bools.xml
+++ b/res/values-zh-rTW/bools.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,5 +16,5 @@
<resources>
<bool name="im_is_default">true</bool>
<!-- The default to true for most of board -->
- <bool name="is_enableEnter">true</bool>
+ <bool name="is_enableEnter">true</bool>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 7c1f32c..f6386c1 100755
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,54 +14,48 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ime_name">遙控器輸入法</string>
- <string name="ime_settings_activity_name">遙控器輸入法設置</string>
- <!-- version = apk(java) + ime engine + sys dict + [hotlist (TBD)] -->
- <string name="version">1.0.0</string>
-
- <!-- Used by the toggle keys in soft keyboards.-->
- <string name="toggle_cn">0</string>
- <string name="toggle_cn_cand">1</string>
- <string name="toggle_en_lower">2</string>
- <string name="toggle_en_upper">3</string>
- <string name="toggle_en_sym1">4</string>
- <string name="toggle_en_sym2">5</string>
- <string name="toggle_smiley">6</string>
- <string name="toggle_enter_go">7</string>
- <string name="toggle_enter_search">8</string>
- <string name="toggle_enter_send">9</string>
- <string name="toggle_enter_next">10</string>
- <string name="toggle_enter_done">11</string>
- <string name="toggle_row_cn">12</string>
- <string name="toggle_row_en">13</string>
- <string name="toggle_row_uri">14</string>
- <string name="toggle_row_emailaddress">15</string>
- <string name="toggle_phone_sym">3</string>
-
- <!-- settings related -->
- <string name="setting_sound_key">setting_sound_key</string>
- <string name="setting_vibrate_key">setting_vibrate_key</string>
- <string name="setting_prediction_key">setting_prediction_key</string>
- <string name="setting_switch_key">setting_switch_key</string>
- <string name="setting_advanced_key">setting_advanced_key</string>
-
- <string name="setting">遙控器輸入法設置</string>
- <string name="setting_sound_key_title">按鍵聲音</string>
- <string name="setting_vibrate_title">按鍵震動</string>
- <string name="setting_prediction_title">聯想輸入</string>
- <string name="setting_switch_title">中英文切換</string>
- <string name="setting_switch_shift_space_title">Shift-space</string>
-
- <string name="setting_enabled">開啟</string>
- <string name="setting_disabled">關閉</string>
-
- <string name="setting_others">其它設置</string>
- <string name="setting_others_summary">詞典同步等</string>
-
- <string name="toggle_enter_go_label">去往</string>
- <string name="toggle_enter_send_label">發送</string>
- <string name="toggle_enter_next_label">下一個</string>
- <string name="toggle_enter_done_label">完成</string>
- <string name="toggle_en_label">英 文</string>
- <string name="toggle_cn_label">中 文</string>
+ <string name="ime_name">遙控器輸入法</string>
+ <string name="ime_settings_activity_name">遙控器輸入法設置</string>
+ <!-- version = apk(java) + ime engine + sys dict + [hotlist (TBD)] -->
+ <string name="version">1.0.0</string>
+ <!-- Used by the toggle keys in soft keyboards.-->
+ <string name="toggle_cn">0</string>
+ <string name="toggle_cn_cand">1</string>
+ <string name="toggle_en_lower">2</string>
+ <string name="toggle_en_upper">3</string>
+ <string name="toggle_en_sym1">4</string>
+ <string name="toggle_en_sym2">5</string>
+ <string name="toggle_smiley">6</string>
+ <string name="toggle_enter_go">7</string>
+ <string name="toggle_enter_search">8</string>
+ <string name="toggle_enter_send">9</string>
+ <string name="toggle_enter_next">10</string>
+ <string name="toggle_enter_done">11</string>
+ <string name="toggle_row_cn">12</string>
+ <string name="toggle_row_en">13</string>
+ <string name="toggle_row_uri">14</string>
+ <string name="toggle_row_emailaddress">15</string>
+ <string name="toggle_phone_sym">3</string>
+ <!-- settings related -->
+ <string name="setting_sound_key">setting_sound_key</string>
+ <string name="setting_vibrate_key">setting_vibrate_key</string>
+ <string name="setting_prediction_key">setting_prediction_key</string>
+ <string name="setting_switch_key">setting_switch_key</string>
+ <string name="setting_advanced_key">setting_advanced_key</string>
+ <string name="setting">遙控器輸入法設置</string>
+ <string name="setting_sound_key_title">按鍵聲音</string>
+ <string name="setting_vibrate_title">按鍵震動</string>
+ <string name="setting_prediction_title">聯想輸入</string>
+ <string name="setting_switch_title">中英文切換</string>
+ <string name="setting_switch_shift_space_title">Shift-space</string>
+ <string name="setting_enabled">開啟</string>
+ <string name="setting_disabled">關閉</string>
+ <string name="setting_others">其它設置</string>
+ <string name="setting_others_summary">詞典同步等</string>
+ <string name="toggle_enter_go_label">去往</string>
+ <string name="toggle_enter_send_label">發送</string>
+ <string name="toggle_enter_next_label">下一個</string>
+ <string name="toggle_enter_done_label">完成</string>
+ <string name="toggle_en_label">英 文</string>
+ <string name="toggle_cn_label">中 文</string>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index e66a1ce..cfe8e9f 100755
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,14 +14,14 @@
limitations under the License.
-->
<resources>
- <color name="label_color">#ffffffff</color>
- <color name="label_color_hl0">#ffffffff</color>
- <color name="balloon_color">#ff000000</color>
- <color name="candidate_color">#ff000000</color>
- <color name="active_candidate_color">#ff000000</color>
- <color name="recommended_candidate_color">#ffe35900</color>
- <color name="footnote_color">#ff343233</color>
- <color name="composing_color">#ff000000</color>
- <color name="composing_color_hl">#ffffffff</color>
- <color name="composing_color_idle">#ff777777</color>
+ <color name="label_color">#ffffffff</color>
+ <color name="label_color_hl0">#ffffffff</color>
+ <color name="balloon_color">#ff000000</color>
+ <color name="candidate_color">#ff000000</color>
+ <color name="active_candidate_color">#ff000000</color>
+ <color name="recommended_candidate_color">#ffe35900</color>
+ <color name="footnote_color">#ff343233</color>
+ <color name="composing_color">#ff000000</color>
+ <color name="composing_color_hl">#ffffffff</color>
+ <color name="composing_color_idle">#ff777777</color>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 5498562..8447ad2 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- The default to true for most of board -->
- <bool name="is_enableEnter">true</bool>
-</resources> \ No newline at end of file
+ <bool name="is_enableEnter">true</bool>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0c8519e..d3383f2 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 65ce279..f1ba213 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,56 +14,50 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ime_name">Remote controller input method</string>
- <string name="ime_settings_activity_name">Remote controller input method settings</string>
- <!-- version = apk(java) + ime engine + sys dict + [hotlist (TBD)] -->
- <string name="version">1.0.0</string>
-
- <!-- Used by the toggle keys in soft keyboards.-->
- <string name="toggle_cn">0</string>
- <string name="toggle_cn_cand">1</string>
- <string name="toggle_en_lower">2</string>
- <string name="toggle_en_upper">3</string>
- <string name="toggle_en_sym1">4</string>
- <string name="toggle_en_sym2">5</string>
- <string name="toggle_smiley">6</string>
- <string name="toggle_enter_go">7</string>
- <string name="toggle_enter_search">8</string>
- <string name="toggle_enter_send">9</string>
- <string name="toggle_enter_next">10</string>
- <string name="toggle_enter_done">11</string>
- <string name="toggle_row_cn">12</string>
- <string name="toggle_row_en">13</string>
- <string name="toggle_row_uri">14</string>
- <string name="toggle_row_emailaddress">15</string>
- <string name="toggle_phone_sym">3</string>
-
- <!-- settings related -->
- <string name="setting_sound_key">setting_sound_key</string>
- <string name="setting_vibrate_key">setting_vibrate_key</string>
- <string name="setting_prediction_key">setting_prediction_key</string>
- <string name="setting_switch_key">setting_switch_key</string>
- <string name="setting_advanced_key">setting_advanced_key</string>
-
- <string name="setting">Remote controller input method settings</string>
- <string name="setting_sound_key_title">Sound feedback</string>
- <string name="setting_vibrate_title">Vibrate when typing</string>
- <string name="setting_prediction_title">Input prediction</string>
- <string name="setting_switch_title">Chinese/English switch</string>
- <string name="setting_switch_shift_space_title">Shift-space</string>
-
- <string name="setting_enabled">Enabled</string>
- <string name="setting_disabled">Disabled</string>
-
- <string name="setting_others">Other settings</string>
- <string name="setting_others_summary">Dictionary synchronization</string>
-
- <string name="toggle_enter_go_label">Go</string>
- <string name="toggle_enter_send_label">Send</string>
- <string name="toggle_enter_next_label">Next</string>
- <string name="toggle_enter_done_label">Done</string>
- <string name="toggle_en_label">English</string>
- <string name="toggle_cn_label">Chinese</string>
- <string name="sym_en_label">English Symbol</string>
- <string name="sym_cn_label">Chinese Symbol</string>
+ <string name="ime_name">Remote controller input method</string>
+ <string name="ime_settings_activity_name">Remote controller input method settings</string>
+ <!-- version = apk(java) + ime engine + sys dict + [hotlist (TBD)] -->
+ <string name="version">1.0.0</string>
+ <!-- Used by the toggle keys in soft keyboards.-->
+ <string name="toggle_cn">0</string>
+ <string name="toggle_cn_cand">1</string>
+ <string name="toggle_en_lower">2</string>
+ <string name="toggle_en_upper">3</string>
+ <string name="toggle_en_sym1">4</string>
+ <string name="toggle_en_sym2">5</string>
+ <string name="toggle_smiley">6</string>
+ <string name="toggle_enter_go">7</string>
+ <string name="toggle_enter_search">8</string>
+ <string name="toggle_enter_send">9</string>
+ <string name="toggle_enter_next">10</string>
+ <string name="toggle_enter_done">11</string>
+ <string name="toggle_row_cn">12</string>
+ <string name="toggle_row_en">13</string>
+ <string name="toggle_row_uri">14</string>
+ <string name="toggle_row_emailaddress">15</string>
+ <string name="toggle_phone_sym">3</string>
+ <!-- settings related -->
+ <string name="setting_sound_key">setting_sound_key</string>
+ <string name="setting_vibrate_key">setting_vibrate_key</string>
+ <string name="setting_prediction_key">setting_prediction_key</string>
+ <string name="setting_switch_key">setting_switch_key</string>
+ <string name="setting_advanced_key">setting_advanced_key</string>
+ <string name="setting">Remote controller input method settings</string>
+ <string name="setting_sound_key_title">Sound feedback</string>
+ <string name="setting_vibrate_title">Vibrate when typing</string>
+ <string name="setting_prediction_title">Input prediction</string>
+ <string name="setting_switch_title">Chinese/English switch</string>
+ <string name="setting_switch_shift_space_title">Shift-space</string>
+ <string name="setting_enabled">Enabled</string>
+ <string name="setting_disabled">Disabled</string>
+ <string name="setting_others">Other settings</string>
+ <string name="setting_others_summary">Dictionary synchronization</string>
+ <string name="toggle_enter_go_label">Go</string>
+ <string name="toggle_enter_send_label">Send</string>
+ <string name="toggle_enter_next_label">Next</string>
+ <string name="toggle_enter_done_label">Done</string>
+ <string name="toggle_en_label">English</string>
+ <string name="toggle_cn_label">Chinese</string>
+ <string name="sym_en_label">English Symbol</string>
+ <string name="sym_cn_label">Chinese Symbol</string>
</resources>
diff --git a/res/xml/method.xml b/res/xml/method.xml
index 442fe9b..469260d 100755
--- a/res/xml/method.xml
+++ b/res/xml/method.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,16 +15,7 @@
-->
<!-- The attributes in this XML file provide configuration information -->
<!-- for the Search Manager. -->
-<input-method xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="com.amlogic.inputmethod.remote.SettingsActivity"
- android:isDefault="@bool/im_is_default"
->
- <subtype android:label="@string/toggle_en_label"
- android:imeSubtypeLocale="en_US"
- android:imeSubtypeMode="keyboard"
- />
- <subtype android:label="@string/toggle_cn_label"
- android:imeSubtypeLocale="zh_CN"
- android:imeSubtypeMode="keyboard"
- />
-</input-method> \ No newline at end of file
+<input-method xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.droidlogic.inputmethod.remote.SettingsActivity" android:isDefault="@bool/im_is_default">
+ <subtype android:label="@string/toggle_en_label" android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" />
+ <subtype android:label="@string/toggle_cn_label" android:imeSubtypeLocale="zh_CN" android:imeSubtypeMode="keyboard" />
+</input-method>
diff --git a/res/xml/settings.xml b/res/xml/settings.xml
index b46e621..31051d8 100755
--- a/res/xml/settings.xml
+++ b/res/xml/settings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,43 +13,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/setting">
-
- <CheckBoxPreference
- android:key="@string/setting_sound_key"
- android:title="@string/setting_sound_key_title"
- android:persistent="true"
- android:summaryOn="@string/setting_enabled"
- android:summaryOff="@string/setting_disabled"/>
-
- <CheckBoxPreference
- android:key="@string/setting_vibrate_key"
- android:title="@string/setting_vibrate_title"
- android:persistent="false"
- android:summaryOn="@string/setting_enabled"
- android:summaryOff="@string/setting_disabled"/>
-
- <CheckBoxPreference
- android:key="@string/setting_prediction_key"
- android:title="@string/setting_prediction_title"
- android:persistent="true"
- android:summaryOn="@string/setting_enabled"
- android:summaryOff="@string/setting_disabled"/>
-
- <!-- Remove following entry to unbundle Google functionality -->
- <PreferenceScreen
- android:title="@string/setting_others"
- android:summary="@string/setting_others_summary"
- android:key="@string/setting_advanced_key">
- <intent android:action="com.android.inputmethod.pinyingoogleservice.SETTINGS" />
- </PreferenceScreen>
-
- <Preference
- android:key="@string/setting_switch_key"
- style="?android:preferenceInformationStyle"
- android:title="@string/setting_switch_title"
- android:persistent="false"
- android:summary="@string/setting_switch_shift_space_title"/>
-
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/setting">
+ <CheckBoxPreference android:key="@string/setting_sound_key" android:title="@string/setting_sound_key_title" android:persistent="true" android:summaryOn="@string/setting_enabled" android:summaryOff="@string/setting_disabled" />
+ <CheckBoxPreference android:key="@string/setting_vibrate_key" android:title="@string/setting_vibrate_title" android:persistent="false" android:summaryOn="@string/setting_enabled" android:summaryOff="@string/setting_disabled" />
+ <CheckBoxPreference android:key="@string/setting_prediction_key" android:title="@string/setting_prediction_title" android:persistent="true" android:summaryOn="@string/setting_enabled" android:summaryOff="@string/setting_disabled" />
+ <!-- Remove following entry to unbundle Google functionality -->
+ <PreferenceScreen android:title="@string/setting_others" android:summary="@string/setting_others_summary" android:key="@string/setting_advanced_key">
+ <intent android:action="com.android.inputmethod.pinyingoogleservice.SETTINGS" />
+ </PreferenceScreen>
+ <Preference android:key="@string/setting_switch_key" style="?android:preferenceInformationStyle" android:title="@string/setting_switch_title" android:persistent="false" android:summary="@string/setting_switch_shift_space_title" />
</PreferenceScreen>
diff --git a/src/com/amlogic/inputmethod/remote/BalloonHint.java b/src/com/amlogic/inputmethod/remote/BalloonHint.java
deleted file mode 100755
index c0abb63..0000000
--- a/src/com/amlogic/inputmethod/remote/BalloonHint.java
+++ b/dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.view.Gravity;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.widget.PopupWindow;
-
-/**
- * Subclass of PopupWindow used as the feedback when user presses on a soft key
- * or a candidate.
- */
-public class BalloonHint extends PopupWindow {
- /**
- * Delayed time to show the balloon hint.
- */
- public static final int TIME_DELAY_SHOW = 0;
-
- /**
- * Delayed time to dismiss the balloon hint.
- */
- public static final int TIME_DELAY_DISMISS = 200;
-
- /**
- * The padding information of the balloon. Because PopupWindow's background
- * can not be changed unless it is dismissed and shown again, we set the
- * real background drawable to the content view, and make the PopupWindow's
- * background transparent. So actually this padding information is for the
- * content view.
- */
- private Rect mPaddingRect = new Rect();
-
- /**
- * The context used to create this balloon hint object.
- */
- private Context mContext;
-
- /**
- * Parent used to show the balloon window.
- */
- private View mParent;
-
- /**
- * The content view of the balloon.
- */
- BalloonView mBalloonView;
-
- /**
- * The measuring specification used to determine its size. Key-press
- * balloons and candidates balloons have different measuring specifications.
- */
- private int mMeasureSpecMode;
-
- /**
- * Used to indicate whether the balloon needs to be dismissed forcibly.
- */
- private boolean mForceDismiss;
-
- /**
- * Timer used to show/dismiss the balloon window with some time delay.
- */
- private BalloonTimer mBalloonTimer;
-
- private int mParentLocationInWindow[] = new int[2];
-
- public BalloonHint(Context context, View parent, int measureSpecMode) {
- super(context);
- mParent = parent;
- mMeasureSpecMode = measureSpecMode;
-
- setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
- setTouchable(false);
- setBackgroundDrawable(new ColorDrawable(0));
-
- mBalloonView = new BalloonView(context);
- mBalloonView.setClickable(false);
- setContentView(mBalloonView);
-
- mBalloonTimer = new BalloonTimer();
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public Rect getPadding() {
- return mPaddingRect;
- }
-
- public void setBalloonBackground(Drawable drawable) {
- // We usually pick up a background from a soft keyboard template,
- // and the object may has been set to this balloon before.
- if (mBalloonView.getBackground() == drawable) return;
- mBalloonView.setBackgroundDrawable(drawable);
-
- if (null != drawable) {
- drawable.getPadding(mPaddingRect);
- } else {
- mPaddingRect.set(0, 0, 0, 0);
- }
- }
-
- /**
- * Set configurations to show text label in this balloon.
- *
- * @param label The text label to show in the balloon.
- * @param textSize The text size used to show label.
- * @param textBold Used to indicate whether the label should be bold.
- * @param textColor The text color used to show label.
- * @param width The desired width of the balloon. The real width is
- * determined by the desired width and balloon's measuring
- * specification.
- * @param height The desired width of the balloon. The real width is
- * determined by the desired width and balloon's measuring
- * specification.
- */
- public void setBalloonConfig(String label, float textSize,
- boolean textBold, int textColor, int width, int height) {
- mBalloonView.setTextConfig(label, textSize, textBold, textColor);
- setBalloonSize(width, height);
- }
-
- /**
- * Set configurations to show text label in this balloon.
- *
- * @param icon The icon used to shown in this balloon.
- * @param width The desired width of the balloon. The real width is
- * determined by the desired width and balloon's measuring
- * specification.
- * @param height The desired width of the balloon. The real width is
- * determined by the desired width and balloon's measuring
- * specification.
- */
- public void setBalloonConfig(Drawable icon, int width, int height) {
- mBalloonView.setIcon(icon);
- setBalloonSize(width, height);
- }
-
-
- public boolean needForceDismiss() {
- return mForceDismiss;
- }
-
- public int getPaddingLeft() {
- return mPaddingRect.left;
- }
-
- public int getPaddingTop() {
- return mPaddingRect.top;
- }
-
- public int getPaddingRight() {
- return mPaddingRect.right;
- }
-
- public int getPaddingBottom() {
- return mPaddingRect.bottom;
- }
-
- public void delayedShow(long delay, int locationInParent[]) {
- if (mBalloonTimer.isPending()) {
- mBalloonTimer.removeTimer();
- }
- if (delay <= 0) {
- mParent.getLocationInWindow(mParentLocationInWindow);
- showAtLocation(mParent, Gravity.LEFT | Gravity.TOP,
- locationInParent[0], locationInParent[1]
- + mParentLocationInWindow[1]);
- } else {
- mBalloonTimer.startTimer(delay, BalloonTimer.ACTION_SHOW,
- locationInParent, -1, -1);
- }
- }
-
- public void delayedUpdate(long delay, int locationInParent[],
- int width, int height) {
- mBalloonView.invalidate();
- if (mBalloonTimer.isPending()) {
- mBalloonTimer.removeTimer();
- }
- if (delay <= 0) {
- mParent.getLocationInWindow(mParentLocationInWindow);
- update(locationInParent[0], locationInParent[1]
- + mParentLocationInWindow[1], width, height);
- } else {
- mBalloonTimer.startTimer(delay, BalloonTimer.ACTION_UPDATE,
- locationInParent, width, height);
- }
- }
-
- public void delayedDismiss(long delay) {
- if (mBalloonTimer.isPending()) {
- mBalloonTimer.removeTimer();
- int pendingAction = mBalloonTimer.getAction();
- if (0 != delay && BalloonTimer.ACTION_HIDE != pendingAction) {
- mBalloonTimer.run();
- }
- }
- if (delay <= 0) {
- dismiss();
- } else {
- mBalloonTimer.startTimer(delay, BalloonTimer.ACTION_HIDE, null, -1,
- -1);
- }
- }
-
- public void removeTimer() {
- if (mBalloonTimer.isPending()) {
- mBalloonTimer.removeTimer();
- }
- }
-
- private void setBalloonSize(int width, int height) {
- int widthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
- mMeasureSpecMode);
- int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
- mMeasureSpecMode);
- mBalloonView.measure(widthMeasureSpec, heightMeasureSpec);
-
- int oldWidth = getWidth();
- int oldHeight = getHeight();
- int newWidth = mBalloonView.getMeasuredWidth() + getPaddingLeft()
- + getPaddingRight();
- int newHeight = mBalloonView.getMeasuredHeight() + getPaddingTop()
- + getPaddingBottom();
- setWidth(newWidth);
- setHeight(newHeight);
-
- // If update() is called to update both size and position, the system
- // will first MOVE the PopupWindow to the new position, and then
- // perform a size-updating operation, so there will be a flash in
- // PopupWindow if user presses a key and moves finger to next one whose
- // size is different.
- // PopupWindow will handle the updating issue in one go in the future,
- // but before that, if we find the size is changed, a mandatory dismiss
- // operation is required. In our UI design, normal QWERTY keys' width
- // can be different in 1-pixel, and we do not dismiss the balloon when
- // user move between QWERTY keys.
- mForceDismiss = false;
- if (isShowing()) {
- mForceDismiss = oldWidth - newWidth > 1 || newWidth - oldWidth > 1;
- }
- }
-
-
- private class BalloonTimer extends Handler implements Runnable {
- public static final int ACTION_SHOW = 1;
- public static final int ACTION_HIDE = 2;
- public static final int ACTION_UPDATE = 3;
-
- /**
- * The pending action.
- */
- private int mAction;
-
- private int mPositionInParent[] = new int[2];
- private int mWidth;
- private int mHeight;
-
- private boolean mTimerPending = false;
-
- public void startTimer(long time, int action, int positionInParent[],
- int width, int height) {
- mAction = action;
- if (ACTION_HIDE != action) {
- mPositionInParent[0] = positionInParent[0];
- mPositionInParent[1] = positionInParent[1];
- }
- mWidth = width;
- mHeight = height;
- postDelayed(this, time);
- mTimerPending = true;
- }
-
- public boolean isPending() {
- return mTimerPending;
- }
-
- public boolean removeTimer() {
- if (mTimerPending) {
- mTimerPending = false;
- removeCallbacks(this);
- return true;
- }
-
- return false;
- }
-
- public int getAction() {
- return mAction;
- }
-
- public void run() {
- switch (mAction) {
- case ACTION_SHOW:
- mParent.getLocationInWindow(mParentLocationInWindow);
- showAtLocation(mParent, Gravity.LEFT | Gravity.TOP,
- mPositionInParent[0], mPositionInParent[1]
- + mParentLocationInWindow[1]);
- break;
- case ACTION_HIDE:
- dismiss();
- break;
- case ACTION_UPDATE:
- mParent.getLocationInWindow(mParentLocationInWindow);
- update(mPositionInParent[0], mPositionInParent[1]
- + mParentLocationInWindow[1], mWidth, mHeight);
- }
- mTimerPending = false;
- }
- }
-
- private class BalloonView extends View {
- /**
- * Suspension points used to display long items.
- */
- private static final String SUSPENSION_POINTS = "...";
-
- /**
- * The icon to be shown. If it is not null, {@link #mLabel} will be
- * ignored.
- */
- private Drawable mIcon;
-
- /**
- * The label to be shown. It is enabled only if {@link #mIcon} is null.
- */
- private String mLabel;
-
- private int mLabeColor = 0xff000000;
- private Paint mPaintLabel;
- private FontMetricsInt mFmi;
-
- /**
- * The width to show suspension points.
- */
- private float mSuspensionPointsWidth;
-
-
- public BalloonView(Context context) {
- super(context);
- mPaintLabel = new Paint();
- mPaintLabel.setColor(mLabeColor);
- mPaintLabel.setAntiAlias(true);
- mPaintLabel.setFakeBoldText(true);
- mFmi = mPaintLabel.getFontMetricsInt();
- }
-
- public void setIcon(Drawable icon) {
- mIcon = icon;
- }
-
- public void setTextConfig(String label, float fontSize,
- boolean textBold, int textColor) {
- // Icon should be cleared so that the label will be enabled.
- mIcon = null;
- mLabel = label;
- mPaintLabel.setTextSize(fontSize);
- mPaintLabel.setFakeBoldText(textBold);
- mPaintLabel.setColor(textColor);
- mFmi = mPaintLabel.getFontMetricsInt();
- mSuspensionPointsWidth = mPaintLabel.measureText(SUSPENSION_POINTS);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthMode == MeasureSpec.EXACTLY) {
- setMeasuredDimension(widthSize, heightSize);
- return;
- }
-
- int measuredWidth = mPaddingLeft + mPaddingRight;
- int measuredHeight = mPaddingTop + mPaddingBottom;
- if (null != mIcon) {
- measuredWidth += mIcon.getIntrinsicWidth();
- measuredHeight += mIcon.getIntrinsicHeight();
- } else if (null != mLabel) {
- measuredWidth += (int) (mPaintLabel.measureText(mLabel));
- measuredHeight += mFmi.bottom - mFmi.top;
- }
- if (widthSize > measuredWidth || widthMode == MeasureSpec.AT_MOST) {
- measuredWidth = widthSize;
- }
-
- if (heightSize > measuredHeight
- || heightMode == MeasureSpec.AT_MOST) {
- measuredHeight = heightSize;
- }
-
- int maxWidth = Environment.getInstance().getScreenWidth() -
- mPaddingLeft - mPaddingRight;
- if (measuredWidth > maxWidth) {
- measuredWidth = maxWidth;
- }
- setMeasuredDimension(measuredWidth, measuredHeight);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- int width = getWidth();
- int height = getHeight();
- if (null != mIcon) {
- int marginLeft = (width - mIcon.getIntrinsicWidth()) / 2;
- int marginRight = width - mIcon.getIntrinsicWidth()
- - marginLeft;
- int marginTop = (height - mIcon.getIntrinsicHeight()) / 2;
- int marginBottom = height - mIcon.getIntrinsicHeight()
- - marginTop;
- mIcon.setBounds(marginLeft, marginTop, width - marginRight,
- height - marginBottom);
- mIcon.draw(canvas);
- } else if (null != mLabel) {
- float labelMeasuredWidth = mPaintLabel.measureText(mLabel);
- float x = mPaddingLeft;
- x += (width - labelMeasuredWidth - mPaddingLeft - mPaddingRight) / 2.0f;
- String labelToDraw = mLabel;
- if (x < mPaddingLeft) {
- x = mPaddingLeft;
- labelToDraw = getLimitedLabelForDrawing(mLabel,
- width - mPaddingLeft - mPaddingRight);
- }
-
- int fontHeight = mFmi.bottom - mFmi.top;
- float marginY = (height - fontHeight) / 2.0f;
- float y = marginY - mFmi.top;
- canvas.drawText(labelToDraw, x, y, mPaintLabel);
- }
- }
-
- private String getLimitedLabelForDrawing(String rawLabel,
- float widthToDraw) {
- int subLen = rawLabel.length();
- if (subLen <= 1) return rawLabel;
- do {
- subLen--;
- float width = mPaintLabel.measureText(rawLabel, 0, subLen);
- if (width + mSuspensionPointsWidth <= widthToDraw || 1 >= subLen) {
- return rawLabel.substring(0, subLen) +
- SUSPENSION_POINTS;
- }
- } while (true);
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/CandidateView.java b/src/com/amlogic/inputmethod/remote/CandidateView.java
deleted file mode 100755
index 7ad21b0..0000000
--- a/src/com/amlogic/inputmethod/remote/CandidateView.java
+++ b/dev/null
@@ -1,760 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import com.amlogic.inputmethod.remote.RemoteIME.DecodingInfo;
-
-import java.util.Vector;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * View to show candidate list. There two candidate view instances which are
- * used to show animation when user navigates between pages.
- */
-public class CandidateView extends View {
- /**
- * The minimum width to show a item.
- */
- private static final float MIN_ITEM_WIDTH = 22;
-
- /**
- * Suspension points used to display long items.
- */
- private static final String SUSPENSION_POINTS = "...";
-
- /**
- * The width to draw candidates.
- */
- private int mContentWidth;
-
- /**
- * The height to draw candidate content.
- */
- private int mContentHeight;
-
- /**
- * Whether footnotes are displayed. Footnote is shown when hardware keyboard
- * is available.
- */
- private boolean mShowFootnote = true;
-
- /**
- * Balloon hint for candidate press/release.
- */
- private BalloonHint mBalloonHint;
-
- /**
- * Desired position of the balloon to the input view.
- */
- private int mHintPositionToInputView[] = new int[2];
-
- /**
- * Decoding result to show.
- */
- private DecodingInfo mDecInfo;
-
- /**
- * Listener used to notify IME that user clicks a candidate, or navigate
- * between them.
- */
- private CandidateViewListener mCvListener;
-
- /**
- * Used to notify the container to update the status of forward/backward
- * arrows.
- */
- private ArrowUpdater mArrowUpdater;
-
- /**
- * If true, update the arrow status when drawing candidates.
- */
- private boolean mUpdateArrowStatusWhenDraw = false;
-
- /**
- * Page number of the page displayed in this view.
- */
- private int mPageNo;
-
- /**
- * Active candidate position in this page.
- */
- private int mActiveCandInPage;
-
- /**
- * Used to decided whether the active candidate should be highlighted or
- * not. If user changes focus to composing view (The view to show Pinyin
- * string), the highlight in candidate view should be removed.
- */
- private boolean mEnableActiveHighlight = true;
-
- /**
- * The page which is just calculated.
- */
- private int mPageNoCalculated = -1;
-
- /**
- * The Drawable used to display as the background of the high-lighted item.
- */
- private Drawable mActiveCellDrawable;
-
- /**
- * The Drawable used to display as separators between candidates.
- */
- private Drawable mSeparatorDrawable;
-
- /**
- * Color to draw normal candidates generated by IME.
- */
- private int mImeCandidateColor;
-
- /**
- * Color to draw normal candidates Recommended by application.
- */
- private int mRecommendedCandidateColor;
-
- /**
- * Color to draw the normal(not highlighted) candidates, it can be one of
- * {@link #mImeCandidateColor} or {@link #mRecommendedCandidateColor}.
- */
- private int mNormalCandidateColor;
-
- /**
- * Color to draw the active(highlighted) candidates, including candidates
- * from IME and candidates from application.
- */
- private int mActiveCandidateColor;
-
- /**
- * Text size to draw candidates generated by IME.
- */
- private int mImeCandidateTextSize;
-
- /**
- * Text size to draw candidates recommended by application.
- */
- private int mRecommendedCandidateTextSize;
-
- /**
- * The current text size to draw candidates. It can be one of
- * {@link #mImeCandidateTextSize} or {@link #mRecommendedCandidateTextSize}.
- */
- private int mCandidateTextSize;
-
- /**
- * Paint used to draw candidates.
- */
- private Paint mCandidatesPaint;
-
- /**
- * Used to draw footnote.
- */
- private Paint mFootnotePaint;
-
- /**
- * The width to show suspension points.
- */
- private float mSuspensionPointsWidth;
-
- /**
- * Rectangle used to draw the active candidate.
- */
- private RectF mActiveCellRect;
-
- /**
- * Left and right margins for a candidate. It is specified in xml, and is
- * the minimum margin for a candidate. The actual gap between two candidates
- * is 2 * {@link #mCandidateMargin} + {@link #mSeparatorDrawable}.
- * getIntrinsicWidth(). Because length of candidate is not fixed, there can
- * be some extra space after the last candidate in the current page. In
- * order to achieve best look-and-feel, this extra space will be divided and
- * allocated to each candidates.
- */
- private float mCandidateMargin;
-
- /**
- * Left and right extra margins for a candidate.
- */
- private float mCandidateMarginExtra;
-
- /**
- * Rectangles for the candidates in this page.
- **/
- private Vector<RectF> mCandRects;
-
- /**
- * FontMetricsInt used to measure the size of candidates.
- */
- private FontMetricsInt mFmiCandidates;
-
- /**
- * FontMetricsInt used to measure the size of footnotes.
- */
- private FontMetricsInt mFmiFootnote;
-
- private PressTimer mTimer = new PressTimer();
-
- private GestureDetector mGestureDetector;
-
- private int mLocationTmp[] = new int[2];
-
- public CandidateView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- Resources r = context.getResources();
-
- Configuration conf = r.getConfiguration();
- if (conf.keyboard == Configuration.KEYBOARD_NOKEYS
- || conf.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
- mShowFootnote = false;
- }
-
- mActiveCellDrawable = r.getDrawable(R.drawable.candidate_hl_bg);
- mSeparatorDrawable = r.getDrawable(R.drawable.candidates_vertical_line);
- mCandidateMargin = r.getDimension(R.dimen.candidate_margin_left_right);
-
- mImeCandidateColor = r.getColor(R.color.candidate_color);
- mRecommendedCandidateColor = r.getColor(R.color.recommended_candidate_color);
- mNormalCandidateColor = mImeCandidateColor;
- mActiveCandidateColor = r.getColor(R.color.active_candidate_color);
-
- mCandidatesPaint = new Paint();
- mCandidatesPaint.setAntiAlias(true);
-
- mFootnotePaint = new Paint();
- mFootnotePaint.setAntiAlias(true);
- mFootnotePaint.setColor(r.getColor(R.color.footnote_color));
- mActiveCellRect = new RectF();
-
- mCandRects = new Vector<RectF>();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int mOldWidth = getMeasuredWidth();
- int mOldHeight = getMeasuredHeight();
-
- setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(),
- widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(),
- heightMeasureSpec));
-
- if (mOldWidth != getMeasuredWidth() || mOldHeight != getMeasuredHeight()) {
- onSizeChanged();
- }
- }
-
- public void initialize(ArrowUpdater arrowUpdater, BalloonHint balloonHint,
- GestureDetector gestureDetector, CandidateViewListener cvListener) {
- mArrowUpdater = arrowUpdater;
- mBalloonHint = balloonHint;
- mGestureDetector = gestureDetector;
- mCvListener = cvListener;
- }
-
- public void setDecodingInfo(DecodingInfo decInfo) {
- if (null == decInfo) return;
- mDecInfo = decInfo;
- mPageNoCalculated = -1;
-
- if (mDecInfo.candidatesFromApp()) {
- mNormalCandidateColor = mRecommendedCandidateColor;
- mCandidateTextSize = mRecommendedCandidateTextSize;
- } else {
- mNormalCandidateColor = mImeCandidateColor;
- mCandidateTextSize = mImeCandidateTextSize;
- }
- if (mCandidatesPaint.getTextSize() != mCandidateTextSize) {
- mCandidatesPaint.setTextSize(mCandidateTextSize);
- mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
- mSuspensionPointsWidth =
- mCandidatesPaint.measureText(SUSPENSION_POINTS);
- }
-
- // Remove any pending timer for the previous list.
- mTimer.removeTimer();
- }
-
- public int getActiveCandiatePosInPage() {
- return mActiveCandInPage;
- }
-
- public int getActiveCandiatePosGlobal() {
- return mDecInfo.mPageStart.get(mPageNo) + mActiveCandInPage;
- }
-
- /**
- * Show a page in the decoding result set previously.
- *
- * @param pageNo Which page to show.
- * @param activeCandInPage Which candidate should be set as active item.
- * @param enableActiveHighlight When false, active item will not be
- * highlighted.
- */
- public void showPage(int pageNo, int activeCandInPage,
- boolean enableActiveHighlight) {
- if (null == mDecInfo) return;
- mPageNo = pageNo;
- mActiveCandInPage = activeCandInPage;
- if (mEnableActiveHighlight != enableActiveHighlight) {
- mEnableActiveHighlight = enableActiveHighlight;
- }
-
- if (!calculatePage(mPageNo)) {
- mUpdateArrowStatusWhenDraw = true;
- } else {
- mUpdateArrowStatusWhenDraw = false;
- }
-
- invalidate();
- }
-
- public void enableActiveHighlight(boolean enableActiveHighlight) {
- if (enableActiveHighlight == mEnableActiveHighlight) return;
-
- mEnableActiveHighlight = enableActiveHighlight;
- invalidate();
- }
-
- public boolean activeCursorForward() {
- if (!mDecInfo.pageReady(mPageNo)) return false;
- int pageSize = mDecInfo.mPageStart.get(mPageNo + 1)
- - mDecInfo.mPageStart.get(mPageNo);
- if (mActiveCandInPage + 1 < pageSize) {
- showPage(mPageNo, mActiveCandInPage + 1, true);
- return true;
- }
- return false;
- }
-
- public boolean activeCurseBackward() {
- if (mActiveCandInPage > 0) {
- showPage(mPageNo, mActiveCandInPage - 1, true);
- return true;
- }
- return false;
- }
-
- private void onSizeChanged() {
- mContentWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
- mContentHeight = (int) ((getMeasuredHeight() - mPaddingTop - mPaddingBottom) * 0.95f);
- /**
- * How to decide the font size if the height for display is given?
- * Now it is implemented in a stupid way.
- */
- int textSize = 1;
- mCandidatesPaint.setTextSize(textSize);
- mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
- while (mFmiCandidates.bottom - mFmiCandidates.top < mContentHeight) {
- textSize++;
- mCandidatesPaint.setTextSize(textSize);
- mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
- }
-
- mImeCandidateTextSize = textSize;
- mRecommendedCandidateTextSize = textSize * 3 / 4;
- if (null == mDecInfo) {
- mCandidateTextSize = mImeCandidateTextSize;
- mCandidatesPaint.setTextSize(mCandidateTextSize);
- mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
- mSuspensionPointsWidth =
- mCandidatesPaint.measureText(SUSPENSION_POINTS);
- } else {
- // Reset the decoding information to update members for painting.
- setDecodingInfo(mDecInfo);
- }
-
- textSize = 1;
- mFootnotePaint.setTextSize(textSize);
- mFmiFootnote = mFootnotePaint.getFontMetricsInt();
- while (mFmiFootnote.bottom - mFmiFootnote.top < mContentHeight / 2) {
- textSize++;
- mFootnotePaint.setTextSize(textSize);
- mFmiFootnote = mFootnotePaint.getFontMetricsInt();
- }
- textSize--;
- mFootnotePaint.setTextSize(textSize);
- mFmiFootnote = mFootnotePaint.getFontMetricsInt();
-
- // When the size is changed, the first page will be displayed.
- // mPageNo = 0;
- // mActiveCandInPage = 0;
- }
-
- private boolean calculatePage(int pageNo) {
- if (pageNo == mPageNoCalculated) return true;
-
- mContentWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
- mContentHeight = (int) ((getMeasuredHeight() - mPaddingTop - mPaddingBottom) * 0.95f);
-
- if (mContentWidth <= 0 || mContentHeight <= 0) return false;
-
- int candSize = mDecInfo.mCandidatesList.size();
-
- // If the size of page exists, only calculate the extra margin.
- boolean onlyExtraMargin = false;
- int fromPage = mDecInfo.mPageStart.size() - 1;
- if (mDecInfo.mPageStart.size() > pageNo + 1) {
- onlyExtraMargin = true;
- fromPage = pageNo;
- }
-
- // If the previous pages have no information, calculate them first.
- for (int p = fromPage; p <= pageNo; p++) {
- int pStart = mDecInfo.mPageStart.get(p);
- int pSize = 0;
- int charNum = 0;
- float lastItemWidth = 0;
-
- float xPos;
- xPos = 0;
- xPos += mSeparatorDrawable.getIntrinsicWidth();
- while (xPos < mContentWidth && pStart + pSize < candSize) {
- int itemPos = pStart + pSize;
- String itemStr = mDecInfo.mCandidatesList.get(itemPos);
- float itemWidth = mCandidatesPaint.measureText(itemStr);
- if (itemWidth < MIN_ITEM_WIDTH) itemWidth = MIN_ITEM_WIDTH;
-
- itemWidth += mCandidateMargin * 2;
- itemWidth += mSeparatorDrawable.getIntrinsicWidth();
- if (xPos + itemWidth < mContentWidth || 0 == pSize) {
- xPos += itemWidth;
- lastItemWidth = itemWidth;
- pSize++;
- charNum += itemStr.length();
- } else {
- break;
- }
- }
- if (!onlyExtraMargin) {
- mDecInfo.mPageStart.add(pStart + pSize);
- mDecInfo.mCnToPage.add(mDecInfo.mCnToPage.get(p) + charNum);
- }
-
- float marginExtra = (mContentWidth - xPos) / pSize / 2;
-
- if (mContentWidth - xPos > lastItemWidth) {
- // Must be the last page, because if there are more items,
- // the next item's width must be less than lastItemWidth.
- // In this case, if the last margin is less than the current
- // one, the last margin can be used, so that the
- // look-and-feeling will be the same as the previous page.
- if (mCandidateMarginExtra <= marginExtra) {
- marginExtra = mCandidateMarginExtra;
- }
- } else if (pSize == 1) {
- marginExtra = 0;
- }
- mCandidateMarginExtra = marginExtra;
- }
- mPageNoCalculated = pageNo;
- return true;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- // The invisible candidate view(the one which is not in foreground) can
- // also be called to drawn, but its decoding result and candidate list
- // may be empty.
- if (null == mDecInfo || mDecInfo.isCandidatesListEmpty()) return;
-
- // Calculate page. If the paging information is ready, the function will
- // return at once.
- calculatePage(mPageNo);
-
- int pStart = mDecInfo.mPageStart.get(mPageNo);
- int pSize = mDecInfo.mPageStart.get(mPageNo + 1) - pStart;
- float candMargin = mCandidateMargin + mCandidateMarginExtra;
- if (mActiveCandInPage > pSize - 1) {
- mActiveCandInPage = pSize - 1;
- }
-
- mCandRects.removeAllElements();
-
- float xPos = mPaddingLeft;
- int yPos = (getMeasuredHeight() -
- (mFmiCandidates.bottom - mFmiCandidates.top)) / 2
- - mFmiCandidates.top;
- xPos += drawVerticalSeparator(canvas, xPos);
- for (int i = 0; i < pSize; i++) {
- float footnoteSize = 0;
- String footnote = null;
- if (mShowFootnote) {
- footnote = Integer.toString(i + 1);
- footnoteSize = mFootnotePaint.measureText(footnote);
- assert (footnoteSize < candMargin);
- }
- String cand = mDecInfo.mCandidatesList.get(pStart + i);
- float candidateWidth = mCandidatesPaint.measureText(cand);
- float centerOffset = 0;
- if (candidateWidth < MIN_ITEM_WIDTH) {
- centerOffset = (MIN_ITEM_WIDTH - candidateWidth) / 2;
- candidateWidth = MIN_ITEM_WIDTH;
- }
-
- float itemTotalWidth = candidateWidth + 2 * candMargin;
-
- if (mActiveCandInPage == i && mEnableActiveHighlight) {
- mActiveCellRect.set(xPos, mPaddingTop + 1, xPos
- + itemTotalWidth, getHeight() - mPaddingBottom - 1);
- mActiveCellDrawable.setBounds((int) mActiveCellRect.left,
- (int) mActiveCellRect.top, (int) mActiveCellRect.right,
- (int) mActiveCellRect.bottom);
- mActiveCellDrawable.draw(canvas);
- }
-
- if (mCandRects.size() < pSize) mCandRects.add(new RectF());
- mCandRects.elementAt(i).set(xPos - 1, yPos + mFmiCandidates.top,
- xPos + itemTotalWidth + 1, yPos + mFmiCandidates.bottom);
-
- // Draw footnote
- if (mShowFootnote) {
- canvas.drawText(footnote, xPos + (candMargin - footnoteSize)
- / 2, yPos, mFootnotePaint);
- }
-
- // Left margin
- xPos += candMargin;
- if (candidateWidth > mContentWidth - xPos - centerOffset) {
- cand = getLimitedCandidateForDrawing(cand,
- mContentWidth - xPos - centerOffset);
- }
- if (mActiveCandInPage == i && mEnableActiveHighlight) {
- mCandidatesPaint.setColor(mActiveCandidateColor);
- } else {
- mCandidatesPaint.setColor(mNormalCandidateColor);
- }
- canvas.drawText(cand, xPos + centerOffset, yPos,
- mCandidatesPaint);
-
- // Candidate and right margin
- xPos += candidateWidth + candMargin;
-
- // Draw the separator between candidates.
- xPos += drawVerticalSeparator(canvas, xPos);
- }
-
- // Update the arrow status of the container.
- if (null != mArrowUpdater && mUpdateArrowStatusWhenDraw) {
- mArrowUpdater.updateArrowStatus();
- mUpdateArrowStatusWhenDraw = false;
- }
- }
-
- private String getLimitedCandidateForDrawing(String rawCandidate,
- float widthToDraw) {
- int subLen = rawCandidate.length();
- if (subLen <= 1) return rawCandidate;
- do {
- subLen--;
- float width = mCandidatesPaint.measureText(rawCandidate, 0, subLen);
- if (width + mSuspensionPointsWidth <= widthToDraw || 1 >= subLen) {
- return rawCandidate.substring(0, subLen) +
- SUSPENSION_POINTS;
- }
- } while (true);
- }
-
- private float drawVerticalSeparator(Canvas canvas, float xPos) {
- mSeparatorDrawable.setBounds((int) xPos, mPaddingTop, (int) xPos
- + mSeparatorDrawable.getIntrinsicWidth(), getMeasuredHeight()
- - mPaddingBottom);
- mSeparatorDrawable.draw(canvas);
- return mSeparatorDrawable.getIntrinsicWidth();
- }
-
- private int mapToItemInPage(int x, int y) {
- // mCandRects.size() == 0 happens when the page is set, but
- // touch events occur before onDraw(). It usually happens with
- // monkey test.
- if (!mDecInfo.pageReady(mPageNo) || mPageNoCalculated != mPageNo
- || mCandRects.size() == 0) {
- return -1;
- }
-
- int pageStart = mDecInfo.mPageStart.get(mPageNo);
- int pageSize = mDecInfo.mPageStart.get(mPageNo + 1) - pageStart;
- if (mCandRects.size() < pageSize) {
- return -1;
- }
-
- // If not found, try to find the nearest one.
- float nearestDis = Float.MAX_VALUE;
- int nearest = -1;
- for (int i = 0; i < pageSize; i++) {
- RectF r = mCandRects.elementAt(i);
- if (r.left < x && r.right > x && r.top < y && r.bottom > y) {
- return i;
- }
- float disx = (r.left + r.right) / 2 - x;
- float disy = (r.top + r.bottom) / 2 - y;
- float dis = disx * disx + disy * disy;
- if (dis < nearestDis) {
- nearestDis = dis;
- nearest = i;
- }
- }
-
- return nearest;
- }
-
- // Because the candidate view under the current focused one may also get
- // touching events. Here we just bypass the event to the container and let
- // it decide which view should handle the event.
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return super.onTouchEvent(event);
- }
-
- public boolean onTouchEventReal(MotionEvent event) {
- // The page in the background can also be touched.
- if (null == mDecInfo || !mDecInfo.pageReady(mPageNo)
- || mPageNoCalculated != mPageNo) return true;
-
- int x, y;
- x = (int) event.getX();
- y = (int) event.getY();
-
- if (mGestureDetector.onTouchEvent(event)) {
- mTimer.removeTimer();
- mBalloonHint.delayedDismiss(0);
- return true;
- }
-
- int clickedItemInPage = -1;
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- clickedItemInPage = mapToItemInPage(x, y);
- if (clickedItemInPage >= 0) {
- invalidate();
- mCvListener.onClickChoice(clickedItemInPage
- + mDecInfo.mPageStart.get(mPageNo));
- }
- mBalloonHint.delayedDismiss(BalloonHint.TIME_DELAY_DISMISS);
- break;
-
- case MotionEvent.ACTION_DOWN:
- clickedItemInPage = mapToItemInPage(x, y);
- if (clickedItemInPage >= 0) {
- showBalloon(clickedItemInPage, true);
- mTimer.startTimer(BalloonHint.TIME_DELAY_SHOW, mPageNo,
- clickedItemInPage);
- }
- break;
-
- case MotionEvent.ACTION_CANCEL:
- break;
-
- case MotionEvent.ACTION_MOVE:
- clickedItemInPage = mapToItemInPage(x, y);
- if (clickedItemInPage >= 0
- && (clickedItemInPage != mTimer.getActiveCandOfPageToShow() || mPageNo != mTimer
- .getPageToShow())) {
- showBalloon(clickedItemInPage, true);
- mTimer.startTimer(BalloonHint.TIME_DELAY_SHOW, mPageNo,
- clickedItemInPage);
- }
- }
- return true;
- }
-
- private void showBalloon(int candPos, boolean delayedShow) {
- mBalloonHint.removeTimer();
-
- RectF r = mCandRects.elementAt(candPos);
- int desired_width = (int) (r.right - r.left);
- int desired_height = (int) (r.bottom - r.top);
- mBalloonHint.setBalloonConfig(mDecInfo.mCandidatesList
- .get(mDecInfo.mPageStart.get(mPageNo) + candPos), 44, true,
- mImeCandidateColor, desired_width, desired_height);
-
- getLocationOnScreen(mLocationTmp);
- mHintPositionToInputView[0] = mLocationTmp[0]
- + (int) (r.left - (mBalloonHint.getWidth() - desired_width) / 2);
- mHintPositionToInputView[1] = -mBalloonHint.getHeight();
-
- long delay = BalloonHint.TIME_DELAY_SHOW;
- if (!delayedShow) delay = 0;
- mBalloonHint.dismiss();
- if (!mBalloonHint.isShowing()) {
- mBalloonHint.delayedShow(delay, mHintPositionToInputView);
- } else {
- mBalloonHint.delayedUpdate(0, mHintPositionToInputView, -1, -1);
- }
- }
-
- private class PressTimer extends Handler implements Runnable {
- private boolean mTimerPending = false;
- private int mPageNoToShow;
- private int mActiveCandOfPage;
-
- public PressTimer() {
- super();
- }
-
- public void startTimer(long afterMillis, int pageNo, int activeInPage) {
- mTimer.removeTimer();
- postDelayed(this, afterMillis);
- mTimerPending = true;
- mPageNoToShow = pageNo;
- mActiveCandOfPage = activeInPage;
- }
-
- public int getPageToShow() {
- return mPageNoToShow;
- }
-
- public int getActiveCandOfPageToShow() {
- return mActiveCandOfPage;
- }
-
- public boolean removeTimer() {
- if (mTimerPending) {
- mTimerPending = false;
- removeCallbacks(this);
- return true;
- }
- return false;
- }
-
- public boolean isPending() {
- return mTimerPending;
- }
-
- public void run() {
- if (mPageNoToShow >= 0 && mActiveCandOfPage >= 0) {
- // Always enable to highlight the clicked one.
- showPage(mPageNoToShow, mActiveCandOfPage, true);
- invalidate();
- }
- mTimerPending = false;
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/CandidatesContainer.java b/src/com/amlogic/inputmethod/remote/CandidatesContainer.java
deleted file mode 100755
index 26fe930..0000000
--- a/src/com/amlogic/inputmethod/remote/CandidatesContainer.java
+++ b/dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import com.amlogic.inputmethod.remote.RemoteIME.DecodingInfo;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.TranslateAnimation;
-import android.view.animation.Animation.AnimationListener;
-import android.widget.ImageButton;
-import android.widget.RelativeLayout;
-import android.widget.ViewFlipper;
-
-interface ArrowUpdater {
- void updateArrowStatus();
-}
-
-
-/**
- * Container used to host the two candidate views. When user drags on candidate
- * view, animation is used to dismiss the current candidate view and show a new
- * one. These two candidate views and their parent are hosted by this container.
- * <p>
- * Besides the candidate views, there are two arrow views to show the page
- * forward/backward arrows.
- * </p>
- */
-public class CandidatesContainer extends RelativeLayout implements
- OnTouchListener, AnimationListener, ArrowUpdater {
- /**
- * Alpha value to show an enabled arrow.
- */
- private static int ARROW_ALPHA_ENABLED = 0xff;
-
- /**
- * Alpha value to show an disabled arrow.
- */
- private static int ARROW_ALPHA_DISABLED = 0x40;
-
- /**
- * Animation time to show a new candidate view and dismiss the old one.
- */
- private static int ANIMATION_TIME = 200;
-
- /**
- * Listener used to notify IME that user clicks a candidate, or navigate
- * between them.
- */
- private CandidateViewListener mCvListener;
-
- /**
- * The left arrow button used to show previous page.
- */
- private ImageButton mLeftArrowBtn;
-
- /**
- * The right arrow button used to show next page.
- */
- private ImageButton mRightArrowBtn;
-
- /**
- * Decoding result to show.
- */
- private DecodingInfo mDecInfo;
-
- /**
- * The animation view used to show candidates. It contains two views.
- * Normally, the candidates are shown one of them. When user navigates to
- * another page, animation effect will be performed.
- */
- private ViewFlipper mFlipper;
-
- /**
- * The x offset of the flipper in this container.
- */
- private int xOffsetForFlipper;
-
- /**
- * Animation used by the incoming view when the user navigates to a left
- * page.
- */
- private Animation mInAnimPushLeft;
-
- /**
- * Animation used by the incoming view when the user navigates to a right
- * page.
- */
- private Animation mInAnimPushRight;
-
- /**
- * Animation used by the incoming view when the user navigates to a page
- * above. If the page navigation is triggered by DOWN key, this animation is
- * used.
- */
- private Animation mInAnimPushUp;
-
- /**
- * Animation used by the incoming view when the user navigates to a page
- * below. If the page navigation is triggered by UP key, this animation is
- * used.
- */
- private Animation mInAnimPushDown;
-
- /**
- * Animation used by the outgoing view when the user navigates to a left
- * page.
- */
- private Animation mOutAnimPushLeft;
-
- /**
- * Animation used by the outgoing view when the user navigates to a right
- * page.
- */
- private Animation mOutAnimPushRight;
-
- /**
- * Animation used by the outgoing view when the user navigates to a page
- * above. If the page navigation is triggered by DOWN key, this animation is
- * used.
- */
- private Animation mOutAnimPushUp;
-
- /**
- * Animation used by the incoming view when the user navigates to a page
- * below. If the page navigation is triggered by UP key, this animation is
- * used.
- */
- private Animation mOutAnimPushDown;
-
- /**
- * Animation object which is used for the incoming view currently.
- */
- private Animation mInAnimInUse;
-
- /**
- * Animation object which is used for the outgoing view currently.
- */
- private Animation mOutAnimInUse;
-
- /**
- * Current page number in display.
- */
- private int mCurrentPage = -1;
-
- public CandidatesContainer(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void initialize(CandidateViewListener cvListener,
- BalloonHint balloonHint, GestureDetector gestureDetector) {
- mCvListener = cvListener;
-
- mLeftArrowBtn = (ImageButton) findViewById(R.id.arrow_left_btn);
- mRightArrowBtn = (ImageButton) findViewById(R.id.arrow_right_btn);
- mLeftArrowBtn.setOnTouchListener(this);
- mRightArrowBtn.setOnTouchListener(this);
-
- mFlipper = (ViewFlipper) findViewById(R.id.candidate_flipper);
- mFlipper.setMeasureAllChildren(true);
-
- invalidate();
- requestLayout();
-
- for (int i = 0; i < mFlipper.getChildCount(); i++) {
- CandidateView cv = (CandidateView) mFlipper.getChildAt(i);
- cv.initialize(this, balloonHint, gestureDetector, mCvListener);
- }
- }
-
- public void showCandidates(RemoteIME.DecodingInfo decInfo,
- boolean enableActiveHighlight) {
- if (null == decInfo) return;
- mDecInfo = decInfo;
- mCurrentPage = 0;
-
- if (decInfo.isCandidatesListEmpty()) {
- showArrow(mLeftArrowBtn, false);
- showArrow(mRightArrowBtn, false);
- } else {
- showArrow(mLeftArrowBtn, true);
- showArrow(mRightArrowBtn, true);
- }
-
- for (int i = 0; i < mFlipper.getChildCount(); i++) {
- CandidateView cv = (CandidateView) mFlipper.getChildAt(i);
- cv.setDecodingInfo(mDecInfo);
- }
- stopAnimation();
-
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
- cv.showPage(mCurrentPage, 0, enableActiveHighlight);
-
- updateArrowStatus();
- invalidate();
- }
-
- public int getCurrentPage() {
- return mCurrentPage;
- }
-
- public void enableActiveHighlight(boolean enableActiveHighlight) {
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
- cv.enableActiveHighlight(enableActiveHighlight);
- invalidate();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- Environment env = Environment.getInstance();
- int measuredWidth = env.getScreenWidth();
- int measuredHeight = getPaddingTop();
- measuredHeight += env.getHeightForCandidates();
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth,
- MeasureSpec.EXACTLY);
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(measuredHeight,
- MeasureSpec.EXACTLY);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (null != mLeftArrowBtn) {
- xOffsetForFlipper = mLeftArrowBtn.getMeasuredWidth();
- }
- }
-
- public boolean activeCurseBackward() {
- if (mFlipper.isFlipping() || null == mDecInfo) {
- return false;
- }
-
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
-
- if (cv.activeCurseBackward()) {
- cv.invalidate();
- return true;
- } else {
- return pageBackward(true, true);
- }
- }
-
- public boolean activeCurseForward() {
- if (mFlipper.isFlipping() || null == mDecInfo) {
- return false;
- }
-
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
-
- if (cv.activeCursorForward()) {
- cv.invalidate();
- return true;
- } else {
- return pageForward(true, true);
- }
- }
-
- public boolean pageBackward(boolean animLeftRight,
- boolean enableActiveHighlight) {
- if (null == mDecInfo) return false;
-
- if (mFlipper.isFlipping() || 0 == mCurrentPage) return false;
-
- int child = mFlipper.getDisplayedChild();
- int childNext = (child + 1) % 2;
- CandidateView cv = (CandidateView) mFlipper.getChildAt(child);
- CandidateView cvNext = (CandidateView) mFlipper.getChildAt(childNext);
-
- mCurrentPage--;
- int activeCandInPage = cv.getActiveCandiatePosInPage();
- if (animLeftRight)
- activeCandInPage = mDecInfo.mPageStart.elementAt(mCurrentPage + 1)
- - mDecInfo.mPageStart.elementAt(mCurrentPage) - 1;
-
- cvNext.showPage(mCurrentPage, activeCandInPage, enableActiveHighlight);
- loadAnimation(animLeftRight, false);
- startAnimation();
-
- updateArrowStatus();
- return true;
- }
-
- public boolean pageForward(boolean animLeftRight,
- boolean enableActiveHighlight) {
- if (null == mDecInfo) return false;
-
- if (mFlipper.isFlipping() || !mDecInfo.preparePage(mCurrentPage + 1)) {
- return false;
- }
-
- int child = mFlipper.getDisplayedChild();
- int childNext = (child + 1) % 2;
- CandidateView cv = (CandidateView) mFlipper.getChildAt(child);
- int activeCandInPage = cv.getActiveCandiatePosInPage();
- cv.enableActiveHighlight(enableActiveHighlight);
-
- CandidateView cvNext = (CandidateView) mFlipper.getChildAt(childNext);
- mCurrentPage++;
- if (animLeftRight) activeCandInPage = 0;
-
- cvNext.showPage(mCurrentPage, activeCandInPage, enableActiveHighlight);
- loadAnimation(animLeftRight, true);
- startAnimation();
-
- updateArrowStatus();
- return true;
- }
-
- public int getActiveCandiatePos() {
- if (null == mDecInfo) return -1;
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
- return cv.getActiveCandiatePosGlobal();
- }
-
- public void updateArrowStatus() {
- if (mCurrentPage < 0) return;
- boolean forwardEnabled = mDecInfo.pageForwardable(mCurrentPage);
- boolean backwardEnabled = mDecInfo.pageBackwardable(mCurrentPage);
-
- if (backwardEnabled) {
- enableArrow(mLeftArrowBtn, true);
- } else {
- enableArrow(mLeftArrowBtn, false);
- }
- if (forwardEnabled) {
- enableArrow(mRightArrowBtn, true);
- } else {
- enableArrow(mRightArrowBtn, false);
- }
- }
-
- private void enableArrow(ImageButton arrowBtn, boolean enabled) {
- arrowBtn.setEnabled(enabled);
- if (enabled)
- arrowBtn.setAlpha(ARROW_ALPHA_ENABLED);
- else
- arrowBtn.setAlpha(ARROW_ALPHA_DISABLED);
- }
-
- private void showArrow(ImageButton arrowBtn, boolean show) {
- if (show)
- arrowBtn.setVisibility(View.VISIBLE);
- else
- arrowBtn.setVisibility(View.INVISIBLE);
- }
-
- public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- if (v == mLeftArrowBtn) {
- mCvListener.onToRightGesture();
- } else if (v == mRightArrowBtn) {
- mCvListener.onToLeftGesture();
- }
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
- cv.enableActiveHighlight(true);
- }
-
- return false;
- }
-
- // The reason why we handle candiate view's touch events here is because
- // that the view under the focused view may get touch events instead of the
- // focused one.
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- event.offsetLocation(-xOffsetForFlipper, 0);
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
- cv.onTouchEventReal(event);
- return true;
- }
-
- public void loadAnimation(boolean animLeftRight, boolean forward) {
- if (animLeftRight) {
- if (forward) {
- if (null == mInAnimPushLeft) {
- mInAnimPushLeft = createAnimation(1.0f, 0, 0, 0, 0, 1.0f,
- ANIMATION_TIME);
- mOutAnimPushLeft = createAnimation(0, -1.0f, 0, 0, 1.0f, 0,
- ANIMATION_TIME);
- }
- mInAnimInUse = mInAnimPushLeft;
- mOutAnimInUse = mOutAnimPushLeft;
- } else {
- if (null == mInAnimPushRight) {
- mInAnimPushRight = createAnimation(-1.0f, 0, 0, 0, 0, 1.0f,
- ANIMATION_TIME);
- mOutAnimPushRight = createAnimation(0, 1.0f, 0, 0, 1.0f, 0,
- ANIMATION_TIME);
- }
- mInAnimInUse = mInAnimPushRight;
- mOutAnimInUse = mOutAnimPushRight;
- }
- } else {
- if (forward) {
- if (null == mInAnimPushUp) {
- mInAnimPushUp = createAnimation(0, 0, 1.0f, 0, 0, 1.0f,
- ANIMATION_TIME);
- mOutAnimPushUp = createAnimation(0, 0, 0, -1.0f, 1.0f, 0,
- ANIMATION_TIME);
- }
- mInAnimInUse = mInAnimPushUp;
- mOutAnimInUse = mOutAnimPushUp;
- } else {
- if (null == mInAnimPushDown) {
- mInAnimPushDown = createAnimation(0, 0, -1.0f, 0, 0, 1.0f,
- ANIMATION_TIME);
- mOutAnimPushDown = createAnimation(0, 0, 0, 1.0f, 1.0f, 0,
- ANIMATION_TIME);
- }
- mInAnimInUse = mInAnimPushDown;
- mOutAnimInUse = mOutAnimPushDown;
- }
- }
-
- mInAnimInUse.setAnimationListener(this);
-
- mFlipper.setInAnimation(mInAnimInUse);
- mFlipper.setOutAnimation(mOutAnimInUse);
- }
-
- private Animation createAnimation(float xFrom, float xTo, float yFrom,
- float yTo, float alphaFrom, float alphaTo, long duration) {
- AnimationSet animSet = new AnimationSet(getContext(), null);
- Animation trans = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
- xFrom, Animation.RELATIVE_TO_SELF, xTo,
- Animation.RELATIVE_TO_SELF, yFrom, Animation.RELATIVE_TO_SELF,
- yTo);
- Animation alpha = new AlphaAnimation(alphaFrom, alphaTo);
- animSet.addAnimation(trans);
- animSet.addAnimation(alpha);
- animSet.setDuration(duration);
- return animSet;
- }
-
- private void startAnimation() {
- mFlipper.showNext();
- }
-
- private void stopAnimation() {
- mFlipper.stopFlipping();
- }
-
- public void onAnimationEnd(Animation animation) {
- if (!mLeftArrowBtn.isPressed() && !mRightArrowBtn.isPressed()) {
- CandidateView cv = (CandidateView) mFlipper.getCurrentView();
- cv.enableActiveHighlight(true);
- }
- }
-
- public void onAnimationRepeat(Animation animation) {
- }
-
- public void onAnimationStart(Animation animation) {
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/ComposingView.java b/src/com/amlogic/inputmethod/remote/ComposingView.java
deleted file mode 100755
index 001f3c5..0000000
--- a/src/com/amlogic/inputmethod/remote/ComposingView.java
+++ b/dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-
-/**
- * View used to show composing string (The Pinyin string for the unselected
- * syllables and the Chinese string for the selected syllables.)
- */
-public class ComposingView extends View {
- /**
- * <p>
- * There are three statuses for the composing view.
- * </p>
- *
- * <p>
- * {@link #SHOW_PINYIN} is used to show the current Pinyin string without
- * highlighted effect. When user inputs Pinyin characters one by one, the
- * Pinyin string will be shown in this mode.
- * </p>
- * <p>
- * {@link #SHOW_STRING_LOWERCASE} is used to show the Pinyin string in
- * lowercase with highlighted effect. When user presses UP key and there is
- * no fixed Chinese characters, composing view will switch from
- * {@link #SHOW_PINYIN} to this mode, and in this mode, user can press
- * confirm key to input the lower-case string, so that user can input
- * English letter in Chinese mode.
- * </p>
- * <p>
- * {@link #EDIT_PINYIN} is used to edit the Pinyin string (shown with
- * highlighted effect). When current status is {@link #SHOW_PINYIN} and user
- * presses UP key, if there are fixed Characters, the input method will
- * switch to {@link #EDIT_PINYIN} thus user can modify some characters in
- * the middle of the Pinyin string. If the current status is
- * {@link #SHOW_STRING_LOWERCASE} and user presses LEFT and RIGHT key, it
- * will also switch to {@link #EDIT_PINYIN}.
- * </p>
- * <p>
- * Whenever user presses down key, the status switches to
- * {@link #SHOW_PINYIN}.
- * </p>
- * <p>
- * When composing view's status is {@link #SHOW_PINYIN}, the IME's status is
- * {@link RemoteIME.ImeState#STATE_INPUT}, otherwise, the IME's status
- * should be {@link RemoteIME.ImeState#STATE_COMPOSING}.
- * </p>
- */
- public enum ComposingStatus {
- SHOW_PINYIN, SHOW_STRING_LOWERCASE, EDIT_PINYIN,
- }
-
- private static final int LEFT_RIGHT_MARGIN = 5;
-
- /**
- * Used to draw composing string. When drawing the active and idle part of
- * the spelling(Pinyin) string, the color may be changed.
- */
- private Paint mPaint;
-
- /**
- * Drawable used to draw highlight effect.
- */
- private Drawable mHlDrawable;
-
- /**
- * Drawable used to draw cursor for editing mode.
- */
- private Drawable mCursor;
-
- /**
- * Used to estimate dimensions to show the string .
- */
- private FontMetricsInt mFmi;
-
- private int mStrColor;
- private int mStrColorHl;
- private int mStrColorIdle;
-
- private int mFontSize;
-
- private ComposingStatus mComposingStatus;
-
- RemoteIME.DecodingInfo mDecInfo;
-
- public ComposingView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- Resources r = context.getResources();
- mHlDrawable = r.getDrawable(R.drawable.composing_hl_bg);
- mCursor = r.getDrawable(R.drawable.composing_area_cursor);
-
- mStrColor = r.getColor(R.color.composing_color);
- mStrColorHl = r.getColor(R.color.composing_color_hl);
- mStrColorIdle = r.getColor(R.color.composing_color_idle);
-
- mFontSize = r.getDimensionPixelSize(R.dimen.composing_height);
-
- mPaint = new Paint();
- mPaint.setColor(mStrColor);
- mPaint.setAntiAlias(true);
- mPaint.setTextSize(mFontSize);
-
- mFmi = mPaint.getFontMetricsInt();
- }
-
- public void reset() {
- mComposingStatus = ComposingStatus.SHOW_PINYIN;
- }
-
- /**
- * Set the composing string to show. If the IME status is
- * {@link RemoteIME.ImeState#STATE_INPUT}, the composing view's status will
- * be set to {@link ComposingStatus#SHOW_PINYIN}, otherwise the composing
- * view will set its status to {@link ComposingStatus#SHOW_STRING_LOWERCASE}
- * or {@link ComposingStatus#EDIT_PINYIN} automatically.
- */
- public void setDecodingInfo(RemoteIME.DecodingInfo decInfo,
- RemoteIME.ImeState imeStatus) {
- mDecInfo = decInfo;
-
- if (RemoteIME.ImeState.STATE_INPUT == imeStatus) {
- mComposingStatus = ComposingStatus.SHOW_PINYIN;
- mDecInfo.moveCursorToEdge(false);
- } else {
- if (decInfo.getFixedLen() != 0
- || ComposingStatus.EDIT_PINYIN == mComposingStatus) {
- mComposingStatus = ComposingStatus.EDIT_PINYIN;
- } else {
- mComposingStatus = ComposingStatus.SHOW_STRING_LOWERCASE;
- }
- mDecInfo.moveCursor(0);
- }
-
- measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- requestLayout();
- invalidate();
- }
-
- public boolean moveCursor(int keyCode) {
- if (keyCode != KeyEvent.KEYCODE_DPAD_LEFT
- && keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) return false;
-
- if (ComposingStatus.EDIT_PINYIN == mComposingStatus) {
- int offset = 0;
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT)
- offset = -1;
- else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) offset = 1;
- mDecInfo.moveCursor(offset);
- } else if (ComposingStatus.SHOW_STRING_LOWERCASE == mComposingStatus) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- mComposingStatus = ComposingStatus.EDIT_PINYIN;
-
- measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- requestLayout();
- }
-
- }
- invalidate();
- return true;
- }
-
- public ComposingStatus getComposingStatus() {
- return mComposingStatus;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- float width;
- int height;
- height = mFmi.bottom - mFmi.top + mPaddingTop + mPaddingBottom;
-
- if (null == mDecInfo) {
- width = 0;
- } else {
- width = mPaddingLeft + mPaddingRight + LEFT_RIGHT_MARGIN * 2;
-
- String str;
- if (ComposingStatus.SHOW_STRING_LOWERCASE == mComposingStatus) {
- str = mDecInfo.getOrigianlSplStr().toString();
- } else {
- str = mDecInfo.getComposingStrForDisplay();
- }
- width += mPaint.measureText(str, 0, str.length());
- }
- setMeasuredDimension((int) (width + 0.5f), height);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (ComposingStatus.EDIT_PINYIN == mComposingStatus
- || ComposingStatus.SHOW_PINYIN == mComposingStatus) {
- drawForPinyin(canvas);
- return;
- }
-
- float x, y;
- x = mPaddingLeft + LEFT_RIGHT_MARGIN;
- y = -mFmi.top + mPaddingTop;
-
- mPaint.setColor(mStrColorHl);
- mHlDrawable.setBounds(mPaddingLeft, mPaddingTop, getWidth()
- - mPaddingRight, getHeight() - mPaddingBottom);
- mHlDrawable.draw(canvas);
-
- String splStr = mDecInfo.getOrigianlSplStr().toString();
- canvas.drawText(splStr, 0, splStr.length(), x, y, mPaint);
- }
-
- private void drawCursor(Canvas canvas, float x) {
- mCursor.setBounds((int) x, mPaddingTop, (int) x
- + mCursor.getIntrinsicWidth(), getHeight() - mPaddingBottom);
- mCursor.draw(canvas);
- }
-
- private void drawForPinyin(Canvas canvas) {
- float x, y;
- x = mPaddingLeft + LEFT_RIGHT_MARGIN;
- y = -mFmi.top + mPaddingTop;
-
- mPaint.setColor(mStrColor);
-
- int cursorPos = mDecInfo.getCursorPosInCmpsDisplay();
- int cmpsPos = cursorPos;
- String cmpsStr = mDecInfo.getComposingStrForDisplay();
- int activeCmpsLen = mDecInfo.getActiveCmpsDisplayLen();
- if (cursorPos > activeCmpsLen) cmpsPos = activeCmpsLen;
- canvas.drawText(cmpsStr, 0, cmpsPos, x, y, mPaint);
- x += mPaint.measureText(cmpsStr, 0, cmpsPos);
- if (cursorPos <= activeCmpsLen) {
- if (ComposingStatus.EDIT_PINYIN == mComposingStatus) {
- drawCursor(canvas, x);
- }
- canvas.drawText(cmpsStr, cmpsPos, activeCmpsLen, x, y, mPaint);
- }
-
- x += mPaint.measureText(cmpsStr, cmpsPos, activeCmpsLen);
-
- if (cmpsStr.length() > activeCmpsLen) {
- mPaint.setColor(mStrColorIdle);
- int oriPos = activeCmpsLen;
- if (cursorPos > activeCmpsLen) {
- if (cursorPos > cmpsStr.length()) cursorPos = cmpsStr.length();
- canvas.drawText(cmpsStr, oriPos, cursorPos, x, y, mPaint);
- x += mPaint.measureText(cmpsStr, oriPos, cursorPos);
-
- if (ComposingStatus.EDIT_PINYIN == mComposingStatus) {
- drawCursor(canvas, x);
- }
-
- oriPos = cursorPos;
- }
- canvas.drawText(cmpsStr, oriPos, cmpsStr.length(), x, y, mPaint);
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/EnglishInputProcessor.java b/src/com/amlogic/inputmethod/remote/EnglishInputProcessor.java
deleted file mode 100755
index 6df71f5..0000000
--- a/src/com/amlogic/inputmethod/remote/EnglishInputProcessor.java
+++ b/dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.view.KeyEvent;
-import android.view.inputmethod.InputConnection;
-
-/**
- * Class to handle English input.
- */
-public class EnglishInputProcessor {
-
- private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- private boolean mShiftTag = false;
- public boolean processKey(InputConnection inputContext, KeyEvent event,
- boolean upperCase, boolean realAction) {
- if (null == inputContext || null == event) return false;
-
- int keyCode = event.getKeyCode();
-
- CharSequence prefix = null;
- prefix = inputContext.getTextBeforeCursor(2, 0);
-
- if (!realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT){
- mShiftTag = true;
- }
- int keyChar;
- keyChar = 0;
- if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) {
- keyChar = keyCode - KeyEvent.KEYCODE_A + 'a';
- if (upperCase) {
- keyChar = keyChar + 'A' - 'a';
- }
- } else if (keyCode >= KeyEvent.KEYCODE_0
- && keyCode <= KeyEvent.KEYCODE_9) {
- keyChar = keyCode - KeyEvent.KEYCODE_0 + '0';
- if (event.isShiftPressed()) {
- return false;
- }
- }
- else if (keyCode == KeyEvent.KEYCODE_COMMA)
- keyChar = ',';
- else if (keyCode == KeyEvent.KEYCODE_PERIOD)
- keyChar = '.';
- else if (keyCode == KeyEvent.KEYCODE_APOSTROPHE)
- keyChar = '\'';
- else if (keyCode == KeyEvent.KEYCODE_AT)
- keyChar = '@';
- else if (keyCode == KeyEvent.KEYCODE_SLASH) keyChar = '/';
-
- if (mShiftTag) {
- keyChar = 0;
- }
- if (0 == keyChar) {
- mLastKeyCode = keyCode;
-
- String insert = null;
- if (KeyEvent.KEYCODE_DEL == keyCode) {
- if (realAction) {
- inputContext.deleteSurroundingText(1, 0);
- }
- } else if (KeyEvent.KEYCODE_ENTER == keyCode) {
- insert = "\n";
- } else if (KeyEvent.KEYCODE_SPACE == keyCode) {
- insert = " ";
- } else {
- if (realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT)
- {
- mShiftTag = false;
- mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- }
- return false;
- }
-
- if (null != insert && realAction)
- inputContext.commitText(insert, insert.length());
-
- return true;
- }
-
- if (!realAction)
- return true;
-
- if (KeyEvent.KEYCODE_SHIFT_LEFT == mLastKeyCode
- || KeyEvent.KEYCODE_SHIFT_LEFT == mLastKeyCode) {
- if (keyChar >= 'a' && keyChar <= 'z')
- keyChar = keyChar - 'a' + 'A';
- } else if (KeyEvent.KEYCODE_ALT_LEFT == mLastKeyCode) {
- }
-
- String result = String.valueOf((char) keyChar);
- inputContext.commitText(result, result.length());
- mLastKeyCode = keyCode;
- return true;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/Environment.java b/src/com/amlogic/inputmethod/remote/Environment.java
deleted file mode 100644
index a428fcc..0000000
--- a/src/com/amlogic/inputmethod/remote/Environment.java
+++ b/dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.view.Display;
-import android.view.WindowManager;
-import com.droidlogic.app.SystemControlManager;
-
-/**
- * Global environment configurations for showing soft keyboard and candidate
- * view. All original dimension values are defined in float, and the real size
- * is calculated from the float values of and screen size. In this way, this
- * input method can work even when screen size is changed.
- */
-public class Environment {
- /**
- * The key height for portrait mode. It is relative to the screen height.
- */
- private static final float KEY_HEIGHT_RATIO_PORTRAIT = 0.105f;
-
- /**
- * The key height for landscape mode. It is relative to the screen height.
- */
- private static final float KEY_HEIGHT_RATIO_LANDSCAPE = 0.063f;
-
- /**
- * The height of the candidates area for portrait mode. It is relative to
- * screen height.
- */
- private static final float CANDIDATES_AREA_HEIGHT_RATIO_PORTRAIT = 0.084f;
-
- /**
- * The height of the candidates area for portrait mode. It is relative to
- * screen height.
- */
- private static final float CANDIDATES_AREA_HEIGHT_RATIO_LANDSCAPE = 0.125f;
-
- /**
- * How much should the balloon width be larger than width of the real key.
- * It is relative to the smaller one of screen width and height.
- */
- private static final float KEY_BALLOON_WIDTH_PLUS_RATIO = 0.08f;
-
- /**
- * How much should the balloon height be larger than that of the real key.
- * It is relative to the smaller one of screen width and height.
- */
- private static final float KEY_BALLOON_HEIGHT_PLUS_RATIO = 0.08f;
-
- /**
- * The text size for normal keys. It is relative to the smaller one of
- * screen width and height.
- */
- private static final float NORMAL_KEY_TEXT_SIZE_RATIO = 0.032f;
-
- /**
- * The text size for function keys. It is relative to the smaller one of
- * screen width and height.
- */
- private static final float FUNCTION_KEY_TEXT_SIZE_RATIO = 0.024f;
-
- /**
- * The text size balloons of normal keys. It is relative to the smaller one
- * of screen width and height.
- */
- private static final float NORMAL_BALLOON_TEXT_SIZE_RATIO = 0.12f;
-
- /**
- * The text size balloons of function keys. It is relative to the smaller
- * one of screen width and height.
- */
- private static final float FUNCTION_BALLOON_TEXT_SIZE_RATIO = 0.085f;
-
- /**
- * The configurations are managed in a singleton.
- */
- private static Environment mInstance;
-
- private int mScreenWidth;
- private int mScreenHeight;
- private int mKeyHeight;
- private int mCandidatesAreaHeight;
- private int mKeyBalloonWidthPlus;
- private int mKeyBalloonHeightPlus;
- private int mNormalKeyTextSize;
- private int mFunctionKeyTextSize;
- private int mNormalBalloonTextSize;
- private int mFunctionBalloonTextSize;
- private Configuration mConfig = new Configuration();
- private boolean mDebug = false;
-
- private Environment() {
- }
-
- public static Environment getInstance() {
- if (null == mInstance) {
- mInstance = new Environment();
- }
- return mInstance;
- }
-
- public void onConfigurationChanged ( Configuration newConfig, Context context ) {
- //density and display-size will be change when switch outputmode between 1080 and 720, need to update configuration
- SystemControlManager sw = new SystemControlManager ( context );
- if ( ( mConfig.orientation != newConfig.orientation ) || ( sw.getPropertyBoolean ( "ro.platform.has.realoutputmode", false ) ) ) {
- WindowManager wm = ( WindowManager ) context.getSystemService ( Context.WINDOW_SERVICE );
- Display d = wm.getDefaultDisplay();
- mScreenWidth = d.getWidth();
- mScreenHeight = d.getHeight();
- int scale;
- if ( mScreenHeight > mScreenWidth ) {
- mKeyHeight = ( int ) ( mScreenHeight * KEY_HEIGHT_RATIO_PORTRAIT );
- mCandidatesAreaHeight = ( int ) ( mScreenHeight * CANDIDATES_AREA_HEIGHT_RATIO_PORTRAIT );
- scale = mScreenWidth;
- } else {
- mKeyHeight = ( int ) ( mScreenHeight * KEY_HEIGHT_RATIO_LANDSCAPE );
- mCandidatesAreaHeight = ( int ) ( mScreenHeight * CANDIDATES_AREA_HEIGHT_RATIO_LANDSCAPE );
- scale = mScreenHeight;
- }
- mNormalKeyTextSize = ( int ) ( scale * NORMAL_KEY_TEXT_SIZE_RATIO );
- mFunctionKeyTextSize = ( int ) ( scale * FUNCTION_KEY_TEXT_SIZE_RATIO );
- mNormalBalloonTextSize = ( int ) ( scale * NORMAL_BALLOON_TEXT_SIZE_RATIO );
- mFunctionBalloonTextSize = ( int ) ( scale * FUNCTION_BALLOON_TEXT_SIZE_RATIO );
- mKeyBalloonWidthPlus = ( int ) ( scale * KEY_BALLOON_WIDTH_PLUS_RATIO );
- mKeyBalloonHeightPlus = ( int ) ( scale * KEY_BALLOON_HEIGHT_PLUS_RATIO );
- }
- mConfig.updateFrom ( newConfig );
- }
-
- public Configuration getConfiguration() {
- return mConfig;
- }
-
- public int getScreenWidth() {
- return mScreenWidth;
- }
-
- public int getScreenHeight() {
- return mScreenHeight;
- }
-
- public int getHeightForCandidates() {
- return mCandidatesAreaHeight;
- }
-
- public float getKeyXMarginFactor() {
- return 1.0f;
- }
-
- public float getKeyYMarginFactor() {
- if (Configuration.ORIENTATION_LANDSCAPE == mConfig.orientation) {
- return 0.7f;
- }
- return 1.0f;
- }
-
- public int getKeyHeight() {
- return mKeyHeight;
- }
-
- public int getKeyBalloonWidthPlus() {
- return mKeyBalloonWidthPlus;
- }
-
- public int getKeyBalloonHeightPlus() {
- return mKeyBalloonHeightPlus;
- }
-
- public int getSkbHeight() {
- if (Configuration.ORIENTATION_PORTRAIT == mConfig.orientation) {
- return mKeyHeight * 4;
- } else if (Configuration.ORIENTATION_LANDSCAPE == mConfig.orientation) {
- return mKeyHeight * 4;
- }
- return 0;
- }
-
- public int getKeyTextSize(boolean isFunctionKey) {
- if (isFunctionKey) {
- return mFunctionKeyTextSize;
- } else {
- return mNormalKeyTextSize;
- }
- }
-
- public int getBalloonTextSize(boolean isFunctionKey) {
- if (isFunctionKey) {
- return mFunctionBalloonTextSize;
- } else {
- return mNormalBalloonTextSize;
- }
- }
-
- public boolean hasHardKeyboard() {
- if (mConfig.keyboard == Configuration.KEYBOARD_NOKEYS
- || mConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
- return false;
- }
- return true;
- }
-
- public boolean needDebug() {
- return mDebug;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/InputModeSwitcher.java b/src/com/amlogic/inputmethod/remote/InputModeSwitcher.java
deleted file mode 100755
index 1ec33d4..0000000
--- a/src/com/amlogic/inputmethod/remote/InputModeSwitcher.java
+++ b/dev/null
@@ -1,836 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import com.amlogic.inputmethod.remote.SoftKeyboard.KeyRow;
-
-import android.content.res.Resources;
-import android.view.inputmethod.EditorInfo;
-
-import java.util.Locale;
-/**
- * Switcher used to switching input mode between Chinese, English, symbol,etc.
- */
-public class InputModeSwitcher {
- /**
- * User defined key code, used by soft keyboard.
- */
- private static final int USERDEF_KEYCODE_SHIFT_1 = -1;
-
- /**
- * User defined key code, used by soft keyboard.
- */
- private static final int USERDEF_KEYCODE_LANG_2 = -2;
-
- /**
- * User defined key code, used by soft keyboard.
- */
- private static final int USERDEF_KEYCODE_SYM_3 = -3;
-
- /**
- * User defined key code, used by soft keyboard.
- */
- public static final int USERDEF_KEYCODE_PHONE_SYM_4 = -4;
-
- /**
- * User defined key code, used by soft keyboard.
- */
- private static final int USERDEF_KEYCODE_MORE_SYM_5 = -5;
-
- /**
- * User defined key code, used by soft keyboard.
- */
- private static final int USERDEF_KEYCODE_SMILEY_6 = -6;
-
-
- /**
- * Bits used to indicate soft keyboard layout. If none bit is set, the
- * current input mode does not require a soft keyboard.
- **/
- private static final int MASK_SKB_LAYOUT = 0xf0000000;
-
- /**
- * A kind of soft keyboard layout. An input mode should be anded with
- * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
- */
- private static final int MASK_SKB_LAYOUT_QWERTY = 0x10000000;
-
- /**
- * A kind of soft keyboard layout. An input mode should be anded with
- * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
- */
- private static final int MASK_SKB_LAYOUT_SYMBOL1 = 0x20000000;
-
- /**
- * A kind of soft keyboard layout. An input mode should be anded with
- * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
- */
- private static final int MASK_SKB_LAYOUT_SYMBOL2 = 0x30000000;
-
- /**
- * A kind of soft keyboard layout. An input mode should be anded with
- * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
- */
- private static final int MASK_SKB_LAYOUT_SMILEY = 0x40000000;
-
- /**
- * A kind of soft keyboard layout. An input mode should be anded with
- * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
- */
- private static final int MASK_SKB_LAYOUT_PHONE = 0x50000000;
-
- /**
- * Used to indicate which language the current input mode is in. If the
- * current input mode works with a none-QWERTY soft keyboard, these bits are
- * also used to get language information. For example, a Chinese symbol soft
- * keyboard and an English one are different in an icon which is used to
- * tell user the language information. BTW, the smiley soft keyboard mode
- * should be set with {@link #MASK_LANGUAGE_CN} because it can only be
- * launched from Chinese QWERTY soft keyboard, and it has Chinese icon on
- * soft keyboard.
- */
- private static final int MASK_LANGUAGE = 0x0f000000;
-
- /**
- * Used to indicate the current language. An input mode should be anded with
- * {@link #MASK_LANGUAGE} to get this information.
- */
- private static final int MASK_LANGUAGE_CN = 0x01000000;
-
- /**
- * Used to indicate the current language. An input mode should be anded with
- * {@link #MASK_LANGUAGE} to get this information.
- */
- private static final int MASK_LANGUAGE_EN = 0x02000000;
-
- /**
- * Used to indicate which case the current input mode is in. For example,
- * English QWERTY has lowercase and uppercase. For the Chinese QWERTY, these
- * bits are ignored. For phone keyboard layout, these bits can be
- * {@link #MASK_CASE_UPPER} to request symbol page for phone soft keyboard.
- */
- private static final int MASK_CASE = 0x00f00000;
-
- /**
- * Used to indicate the current case information. An input mode should be
- * anded with {@link #MASK_CASE} to get this information.
- */
- private static final int MASK_CASE_LOWER = 0x00100000;
-
- /**
- * Used to indicate the current case information. An input mode should be
- * anded with {@link #MASK_CASE} to get this information.
- */
- private static final int MASK_CASE_UPPER = 0x00200000;
-
- /**
- * Mode for inputing English with soft keyboard.
- */
- public static final int MODE_SKB_ENGLISH = (MASK_SKB_LAYOUT_QWERTY | MASK_LANGUAGE_EN);
-
- /**
- * Mode for inputing Chinese with soft keyboard.
- */
- public static final int MODE_SKB_CHINESE = (MASK_SKB_LAYOUT_QWERTY | MASK_LANGUAGE_CN);
-
- /**
- * Mode for inputing basic symbols for Chinese mode with soft keyboard.
- */
- public static final int MODE_SKB_SYMBOL1_CN = (MASK_SKB_LAYOUT_SYMBOL1 | MASK_LANGUAGE_CN);
-
- /**
- * Mode for inputing more symbols for Chinese mode with soft keyboard.
- */
- public static final int MODE_SKB_SYMBOL2_CN = (MASK_SKB_LAYOUT_SYMBOL2 | MASK_LANGUAGE_CN);
-
- /**
- * Mode for inputing English lower characters with soft keyboard.
- */
- public static final int MODE_SKB_ENGLISH_LOWER = (MASK_SKB_LAYOUT_QWERTY
- | MASK_LANGUAGE_EN | MASK_CASE_LOWER);
-
- /**
- * Mode for inputing English upper characters with soft keyboard.
- */
- public static final int MODE_SKB_ENGLISH_UPPER = (MASK_SKB_LAYOUT_QWERTY
- | MASK_LANGUAGE_EN | MASK_CASE_UPPER);
-
- /**
- * Mode for inputing basic symbols for English mode with soft keyboard.
- */
- public static final int MODE_SKB_SYMBOL1_EN = (MASK_SKB_LAYOUT_SYMBOL1 | MASK_LANGUAGE_EN);
-
- /**
- * Mode for inputing more symbols for English mode with soft keyboard.
- */
- public static final int MODE_SKB_SYMBOL2_EN = (MASK_SKB_LAYOUT_SYMBOL2 | MASK_LANGUAGE_EN);
-
- /**
- * Mode for inputing smileys with soft keyboard.
- */
- public static final int MODE_SKB_SMILEY = (MASK_SKB_LAYOUT_SMILEY | MASK_LANGUAGE_CN);
-
- /**
- * Mode for inputing phone numbers.
- */
- public static final int MODE_SKB_PHONE_NUM = (MASK_SKB_LAYOUT_PHONE);
-
- /**
- * Mode for inputing phone numbers.
- */
- public static final int MODE_SKB_PHONE_SYM = (MASK_SKB_LAYOUT_PHONE | MASK_CASE_UPPER);
-
- /**
- * Mode for inputing Chinese with a hardware keyboard.
- */
- public static final int MODE_HKB_CHINESE = (MASK_LANGUAGE_CN);
-
- /**
- * Mode for inputing English with a hardware keyboard
- */
- public static final int MODE_HKB_ENGLISH = (MASK_LANGUAGE_EN);
-
- /**
- * Unset mode.
- */
- public static final int MODE_UNSET = 0;
-
- /**
- * Maximum toggle states for a soft keyboard.
- */
- public static final int MAX_TOGGLE_STATES = 4;
-
- /**
- * The input mode for the current edit box.
- */
- private int mInputMode = MODE_UNSET;
-
- /**
- * Used to remember previous input mode. When user enters an edit field, the
- * previous input mode will be tried. If the previous mode can not be used
- * for the current situation (For example, previous mode is a soft keyboard
- * mode to input symbols, and we have a hardware keyboard for the current
- * situation), {@link #mRecentLauageInputMode} will be tried.
- **/
- private int mPreviousInputMode = MODE_SKB_CHINESE;
-
- /**
- * Used to remember recent mode to input language.
- */
- private int mRecentLauageInputMode = MODE_SKB_CHINESE;
-
- /**
- * Editor information of the current edit box.
- */
- private EditorInfo mEditorInfo;
-
- /**
- * Used to indicate required toggling operations.
- */
- private ToggleStates mToggleStates = new ToggleStates();
-
- /**
- * The current field is a short message field?
- */
- private boolean mShortMessageField;
-
- /**
- * Is return key in normal state?
- */
- private boolean mEnterKeyNormal = true;
-
- /**
- * Current icon. 0 for none icon.
- */
- int mInputIcon = R.drawable.ime_pinyin;
-
- /**
- * IME service.
- */
- private RemoteIME mImeService;
-
- /**
- * Key toggling state for Chinese mode.
- */
- private int mToggleStateCn;
-
- /**
- * Key toggling state for Chinese mode with candidates.
- */
- private int mToggleStateCnCand;
-
- /**
- * Key toggling state for English lowwercase mode.
- */
- private int mToggleStateEnLower;
-
- /**
- * Key toggling state for English upppercase mode.
- */
- private int mToggleStateEnUpper;
-
- /**
- * Key toggling state for English symbol mode for the first page.
- */
- private int mToggleStateEnSym1;
-
- /**
- * Key toggling state for English symbol mode for the second page.
- */
- private int mToggleStateEnSym2;
-
- /**
- * Key toggling state for smiley mode.
- */
- private int mToggleStateSmiley;
-
- /**
- * Key toggling state for phone symbol mode.
- */
- private int mToggleStatePhoneSym;
-
- /**
- * Key toggling state for GO action of ENTER key.
- */
- private int mToggleStateGo;
-
- /**
- * Key toggling state for SEARCH action of ENTER key.
- */
- private int mToggleStateSearch;
-
- /**
- * Key toggling state for SEND action of ENTER key.
- */
- private int mToggleStateSend;
-
- /**
- * Key toggling state for NEXT action of ENTER key.
- */
- private int mToggleStateNext;
-
- /**
- * Key toggling state for SEND action of ENTER key.
- */
- private int mToggleStateDone;
-
- /**
- * QWERTY row toggling state for Chinese input.
- */
- private int mToggleRowCn;
-
- /**
- * QWERTY row toggling state for English input.
- */
- private int mToggleRowEn;
-
- /**
- * QWERTY row toggling state for URI input.
- */
- private int mToggleRowUri;
-
- /**
- * QWERTY row toggling state for email address input.
- */
- private int mToggleRowEmailAddress;
-
- class ToggleStates {
- /**
- * If it is true, this soft keyboard is a QWERTY one.
- */
- boolean mQwerty;
-
- /**
- * If {@link #mQwerty} is true, this variable is used to decide the
- * letter case of the QWERTY keyboard.
- */
- boolean mQwertyUpperCase;
-
- /**
- * The id of enabled row in the soft keyboard. Refer to
- * {@link com.amlogic.inputmethod.remote.SoftKeyboard.KeyRow} for
- * details.
- */
- public int mRowIdToEnable;
-
- /**
- * Used to store all other toggle states for the current input mode.
- */
- public int mKeyStates[] = new int[MAX_TOGGLE_STATES];
-
- /**
- * Number of states to toggle.
- */
- public int mKeyStatesNum;
- }
-
- public InputModeSwitcher(RemoteIME imeService) {
- mImeService = imeService;
- if("zh".equals(Locale.getDefault().getLanguage())){
- mRecentLauageInputMode = MODE_SKB_CHINESE;
- }else{
- mRecentLauageInputMode = MODE_SKB_ENGLISH;
- }
- Resources r = mImeService.getResources();
- mToggleStateCn = Integer.parseInt(r.getString(R.string.toggle_cn));
- mToggleStateCnCand = Integer.parseInt(r
- .getString(R.string.toggle_cn_cand));
- mToggleStateEnLower = Integer.parseInt(r
- .getString(R.string.toggle_en_lower));
- mToggleStateEnUpper = Integer.parseInt(r
- .getString(R.string.toggle_en_upper));
- mToggleStateEnSym1 = Integer.parseInt(r
- .getString(R.string.toggle_en_sym1));
- mToggleStateEnSym2 = Integer.parseInt(r
- .getString(R.string.toggle_en_sym2));
- mToggleStateSmiley = Integer.parseInt(r
- .getString(R.string.toggle_smiley));
- mToggleStatePhoneSym = Integer.parseInt(r
- .getString(R.string.toggle_phone_sym));
-
- mToggleStateGo = Integer
- .parseInt(r.getString(R.string.toggle_enter_go));
- mToggleStateSearch = Integer.parseInt(r
- .getString(R.string.toggle_enter_search));
- mToggleStateSend = Integer.parseInt(r
- .getString(R.string.toggle_enter_send));
- mToggleStateNext = Integer.parseInt(r
- .getString(R.string.toggle_enter_next));
- mToggleStateDone = Integer.parseInt(r
- .getString(R.string.toggle_enter_done));
-
- mToggleRowCn = Integer.parseInt(r.getString(R.string.toggle_row_cn));
- mToggleRowEn = Integer.parseInt(r.getString(R.string.toggle_row_en));
- mToggleRowUri = Integer.parseInt(r.getString(R.string.toggle_row_uri));
- mToggleRowEmailAddress = Integer.parseInt(r
- .getString(R.string.toggle_row_emailaddress));
- }
-
- public int getInputMode() {
- return mInputMode;
- }
-
- public ToggleStates getToggleStates() {
- return mToggleStates;
- }
-
- public int getSkbLayout() {
- int layout = (mInputMode & MASK_SKB_LAYOUT);
-
- switch (layout) {
- case MASK_SKB_LAYOUT_QWERTY:
- return R.xml.skb_qwerty;
- case MASK_SKB_LAYOUT_SYMBOL1:
- return R.xml.skb_sym1;
- case MASK_SKB_LAYOUT_SYMBOL2:
- return R.xml.skb_sym2;
- case MASK_SKB_LAYOUT_SMILEY:
- return R.xml.skb_smiley;
- case MASK_SKB_LAYOUT_PHONE:
- return R.xml.skb_phone;
- }
- return 0;
- }
-
- // Return the icon to update.
- public int switchLanguageWithHkb() {
- int newInputMode = MODE_HKB_CHINESE;
- mInputIcon = R.drawable.ime_pinyin;
-
- if (MODE_HKB_CHINESE == mInputMode) {
- newInputMode = MODE_HKB_ENGLISH;
- mInputIcon = R.drawable.ime_en;
- }
-
- saveInputMode(newInputMode);
- return mInputIcon;
- }
-
- // Return the icon to update.
- public int switchModeForUserKey(int userKey) {
- int newInputMode = MODE_UNSET;
-
- if (USERDEF_KEYCODE_LANG_2 == userKey) {
- if (MODE_SKB_CHINESE == mInputMode) {
- newInputMode = MODE_SKB_ENGLISH_LOWER;
- } else if (MODE_SKB_ENGLISH_LOWER == mInputMode
- || MODE_SKB_ENGLISH_UPPER == mInputMode) {
- newInputMode = MODE_SKB_CHINESE;
- } else if (MODE_SKB_SYMBOL1_CN == mInputMode) {
- newInputMode = MODE_SKB_SYMBOL1_EN;
- } else if (MODE_SKB_SYMBOL1_EN == mInputMode) {
- newInputMode = MODE_SKB_SYMBOL1_CN;
- } else if (MODE_SKB_SYMBOL2_CN == mInputMode) {
- newInputMode = MODE_SKB_SYMBOL2_EN;
- } else if (MODE_SKB_SYMBOL2_EN == mInputMode) {
- newInputMode = MODE_SKB_SYMBOL2_CN;
- } else if (MODE_SKB_SMILEY == mInputMode) {
- newInputMode = MODE_SKB_CHINESE;
- }
- } else if (USERDEF_KEYCODE_SYM_3 == userKey) {
- if (MODE_SKB_CHINESE == mInputMode) {
- newInputMode = MODE_SKB_SYMBOL1_CN;
- } else if (MODE_SKB_ENGLISH_UPPER == mInputMode
- || MODE_SKB_ENGLISH_LOWER == mInputMode) {
- newInputMode = MODE_SKB_SYMBOL1_EN;
- } else if (MODE_SKB_SYMBOL1_EN == mInputMode
- || MODE_SKB_SYMBOL2_EN == mInputMode) {
- newInputMode = MODE_SKB_ENGLISH_LOWER;
- } else if (MODE_SKB_SYMBOL1_CN == mInputMode
- || MODE_SKB_SYMBOL2_CN == mInputMode) {
- newInputMode = MODE_SKB_CHINESE;
- } else if (MODE_SKB_SMILEY == mInputMode) {
- newInputMode = MODE_SKB_SYMBOL1_CN;
- }
- } else if (USERDEF_KEYCODE_SHIFT_1 == userKey) {
- if (MODE_SKB_ENGLISH_LOWER == mInputMode) {
- newInputMode = MODE_SKB_ENGLISH_UPPER;
- } else if (MODE_SKB_ENGLISH_UPPER == mInputMode) {
- newInputMode = MODE_SKB_ENGLISH_LOWER;
- }
- } else if (USERDEF_KEYCODE_MORE_SYM_5 == userKey) {
- int sym = (MASK_SKB_LAYOUT & mInputMode);
- if (MASK_SKB_LAYOUT_SYMBOL1 == sym) {
- sym = MASK_SKB_LAYOUT_SYMBOL2;
- } else {
- sym = MASK_SKB_LAYOUT_SYMBOL1;
- }
- newInputMode = ((mInputMode & (~MASK_SKB_LAYOUT)) | sym);
- } else if (USERDEF_KEYCODE_SMILEY_6 == userKey) {
- if (MODE_SKB_CHINESE == mInputMode) {
- newInputMode = MODE_SKB_SMILEY;
- } else {
- newInputMode = MODE_SKB_CHINESE;
- }
- } else if (USERDEF_KEYCODE_PHONE_SYM_4 == userKey) {
- if (MODE_SKB_PHONE_NUM == mInputMode) {
- newInputMode = MODE_SKB_PHONE_SYM;
- } else {
- newInputMode = MODE_SKB_PHONE_NUM;
- }
- }
-
- if (newInputMode == mInputMode || MODE_UNSET == newInputMode) {
- return mInputIcon;
- }
-
- saveInputMode(newInputMode);
- prepareToggleStates(true);
- return mInputIcon;
- }
-
- // Return the icon to update.
- public int requestInputWithHkb(EditorInfo editorInfo) {
- mShortMessageField = false;
- boolean english = false;
- int newInputMode = MODE_HKB_CHINESE;
-
- switch (editorInfo.inputType & EditorInfo.TYPE_MASK_CLASS) {
- case EditorInfo.TYPE_CLASS_NUMBER:
- case EditorInfo.TYPE_CLASS_PHONE:
- case EditorInfo.TYPE_CLASS_DATETIME:
- english = true;
- break;
- case EditorInfo.TYPE_CLASS_TEXT:
- int v = editorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
- if (v == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
- || v == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
- || v == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
- || v == EditorInfo.TYPE_TEXT_VARIATION_URI) {
- english = true;
- } else if (v == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
- mShortMessageField = true;
- }
- break;
- default:
- }
-
- if (english) {
- // If the application request English mode, we switch to it.
- newInputMode = MODE_HKB_ENGLISH;
- } else {
- // If the application do not request English mode, we will
- // try to keep the previous mode to input language text.
- // Because there is not soft keyboard, we need discard all
- // soft keyboard related information from the previous language
- // mode.
- if ((mRecentLauageInputMode & MASK_LANGUAGE) == MASK_LANGUAGE_CN) {
- newInputMode = MODE_HKB_CHINESE;
- } else {
- newInputMode = MODE_HKB_ENGLISH;
- }
- }
- mEditorInfo = editorInfo;
- saveInputMode(newInputMode);
- prepareToggleStates(false);
- return mInputIcon;
- }
-
- // Return the icon to update.
- public int requestInputWithSkb(EditorInfo editorInfo) {
- mShortMessageField = false;
-
- int newInputMode = MODE_SKB_CHINESE;
-
- switch (editorInfo.inputType & EditorInfo.TYPE_MASK_CLASS) {
- case EditorInfo.TYPE_CLASS_NUMBER:
- case EditorInfo.TYPE_CLASS_DATETIME:
- newInputMode = MODE_SKB_SYMBOL1_EN;
- break;
- case EditorInfo.TYPE_CLASS_PHONE:
- newInputMode = MODE_SKB_PHONE_NUM;
- break;
- case EditorInfo.TYPE_CLASS_TEXT:
- int v = editorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
- if (v == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
- || v == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
- || v == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
- || v == EditorInfo.TYPE_TEXT_VARIATION_URI) {
- // If the application request English mode, we switch to it.
- newInputMode = MODE_SKB_ENGLISH_LOWER;
- } else {
- if (v == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
- mShortMessageField = true;
- }
- // If the application do not request English mode, we will
- // try to keep the previous mode.
- int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
- newInputMode = mInputMode;
- if (0 == skbLayout) {
- if ((mInputMode & MASK_LANGUAGE) == MASK_LANGUAGE_CN) {
- newInputMode = MODE_SKB_CHINESE;
- } else {
- newInputMode = MODE_SKB_ENGLISH_LOWER;
- }
- }
- }
- break;
- default:
- // Try to keep the previous mode.
- int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
- newInputMode = mInputMode;
- if (0 == skbLayout) {
- if ((mInputMode & MASK_LANGUAGE) == MASK_LANGUAGE_CN) {
- newInputMode = MODE_SKB_CHINESE;
- } else {
- newInputMode = MODE_SKB_ENGLISH_LOWER;
- }
- }
- break;
- }
-
- mEditorInfo = editorInfo;
- saveInputMode(newInputMode);
- prepareToggleStates(true);
- return mInputIcon;
- }
-
- // Return the icon to update.
- public int requestBackToPreviousSkb() {
- int layout = (mInputMode & MASK_SKB_LAYOUT);
- int lastLayout = (mPreviousInputMode & MASK_SKB_LAYOUT);
- if (0 != layout && 0 != lastLayout) {
- mInputMode = mPreviousInputMode;
- saveInputMode(mInputMode);
- prepareToggleStates(true);
- return mInputIcon;
- }
- return 0;
- }
-
- public int getTooggleStateForCnCand() {
- return mToggleStateCnCand;
- }
-
- public boolean isEnglishWithHkb() {
- return MODE_HKB_ENGLISH == mInputMode;
- }
-
- public boolean isEnglishWithSkb() {
- return MODE_SKB_ENGLISH_LOWER == mInputMode
- || MODE_SKB_ENGLISH_UPPER == mInputMode;
- }
-
- public boolean isEnglishUpperCaseWithSkb() {
- return MODE_SKB_ENGLISH_UPPER == mInputMode;
- }
-
- public boolean isChineseText() {
- int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
- if (MASK_SKB_LAYOUT_QWERTY == skbLayout || 0 == skbLayout) {
- int language = (mInputMode & MASK_LANGUAGE);
- if (MASK_LANGUAGE_CN == language) return true;
- }
- return false;
- }
-
- public boolean isChineseTextWithHkb() {
- int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
- if (0 == skbLayout) {
- int language = (mInputMode & MASK_LANGUAGE);
- if (MASK_LANGUAGE_CN == language) return true;
- }
- return false;
- }
-
- public boolean isChineseTextWithSkb() {
- int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
- if (MASK_SKB_LAYOUT_QWERTY == skbLayout) {
- int language = (mInputMode & MASK_LANGUAGE);
- if (MASK_LANGUAGE_CN == language) return true;
- }
- return false;
- }
-
- public boolean isSymbolWithSkb() {
- int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
- if (MASK_SKB_LAYOUT_SYMBOL1 == skbLayout
- || MASK_SKB_LAYOUT_SYMBOL2 == skbLayout) {
- return true;
- }
- return false;
- }
-
- public boolean isEnterNoramlState() {
- return mEnterKeyNormal;
- }
-
- public boolean tryHandleLongPressSwitch(int keyCode) {
- if (USERDEF_KEYCODE_LANG_2 == keyCode
- || USERDEF_KEYCODE_PHONE_SYM_4 == keyCode) {
- mImeService.showOptionsMenu();
- return true;
- }
- return false;
- }
-
- private void saveInputMode(int newInputMode) {
- mPreviousInputMode = mInputMode;
- mInputMode = newInputMode;
-
- int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
- if (MASK_SKB_LAYOUT_QWERTY == skbLayout || 0 == skbLayout) {
- mRecentLauageInputMode = mInputMode;
- }
-
- mInputIcon = R.drawable.ime_pinyin;
- if (isEnglishWithHkb()) {
- mInputIcon = R.drawable.ime_en;
- } else if (isChineseTextWithHkb()) {
- mInputIcon = R.drawable.ime_pinyin;
- }
-
- if (!Environment.getInstance().hasHardKeyboard()) {
- mInputIcon = 0;
- }
- }
-
- private void prepareToggleStates(boolean needSkb) {
- mEnterKeyNormal = true;
- if (!needSkb) return;
-
- mToggleStates.mQwerty = false;
- mToggleStates.mKeyStatesNum = 0;
-
- int states[] = mToggleStates.mKeyStates;
- int statesNum = 0;
- // Toggle state for language.
- int language = (mInputMode & MASK_LANGUAGE);
- int layout = (mInputMode & MASK_SKB_LAYOUT);
- int charcase = (mInputMode & MASK_CASE);
- int variation = mEditorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
-
- if (MASK_SKB_LAYOUT_PHONE != layout) {
- if (MASK_LANGUAGE_CN == language) {
- // Chinese and Chinese symbol are always the default states,
- // do not add a toggling operation.
- if (MASK_SKB_LAYOUT_QWERTY == layout) {
- mToggleStates.mQwerty = true;
- mToggleStates.mQwertyUpperCase = true;
- if (mShortMessageField) {
- states[statesNum] = mToggleStateSmiley;
- statesNum++;
- }
- }
- } else if (MASK_LANGUAGE_EN == language) {
- if (MASK_SKB_LAYOUT_QWERTY == layout) {
- mToggleStates.mQwerty = true;
- mToggleStates.mQwertyUpperCase = false;
- states[statesNum] = mToggleStateEnLower;
- if (MASK_CASE_UPPER == charcase) {
- mToggleStates.mQwertyUpperCase = true;
- states[statesNum] = mToggleStateEnUpper;
- }
- statesNum++;
- } else if (MASK_SKB_LAYOUT_SYMBOL1 == layout) {
- states[statesNum] = mToggleStateEnSym1;
- statesNum++;
- } else if (MASK_SKB_LAYOUT_SYMBOL2 == layout) {
- states[statesNum] = mToggleStateEnSym2;
- statesNum++;
- }
- }
-
- // Toggle rows for QWERTY.
- mToggleStates.mRowIdToEnable = KeyRow.DEFAULT_ROW_ID;
- if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
- mToggleStates.mRowIdToEnable = mToggleRowEmailAddress;
- } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
- mToggleStates.mRowIdToEnable = mToggleRowUri;
- } else if (MASK_LANGUAGE_CN == language) {
- mToggleStates.mRowIdToEnable = mToggleRowCn;
- } else if (MASK_LANGUAGE_EN == language) {
- mToggleStates.mRowIdToEnable = mToggleRowEn;
- }
- } else {
- if (MASK_CASE_UPPER == charcase) {
- states[statesNum] = mToggleStatePhoneSym;
- statesNum++;
- }
- }
-
- // Toggle state for enter key.
- int action = mEditorInfo.imeOptions
- & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
-
- if (action == EditorInfo.IME_ACTION_GO) {
- states[statesNum] = mToggleStateGo;
- statesNum++;
- mEnterKeyNormal = false;
- } else if (action == EditorInfo.IME_ACTION_SEARCH) {
- states[statesNum] = mToggleStateSearch;
- statesNum++;
- mEnterKeyNormal = false;
- } else if (action == EditorInfo.IME_ACTION_SEND) {
- states[statesNum] = mToggleStateSend;
- statesNum++;
- mEnterKeyNormal = false;
- } else if (action == EditorInfo.IME_ACTION_NEXT) {
- int f = mEditorInfo.inputType & EditorInfo.TYPE_MASK_FLAGS;
- if (f != EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) {
- states[statesNum] = mToggleStateNext;
- statesNum++;
- mEnterKeyNormal = false;
- }
- } else if (action == EditorInfo.IME_ACTION_DONE) {
- states[statesNum] = mToggleStateDone;
- statesNum++;
- mEnterKeyNormal = false;
- }
- mToggleStates.mKeyStatesNum = statesNum;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/KeyMapDream.java b/src/com/amlogic/inputmethod/remote/KeyMapDream.java
deleted file mode 100755
index 194adaf..0000000
--- a/src/com/amlogic/inputmethod/remote/KeyMapDream.java
+++ b/dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.view.KeyEvent;
-
-/**
- * Class used to map the symbols on Dream's hardware keyboard to corresponding
- * Chinese full-width symbols.
- */
-public class KeyMapDream {
- // Number of shift bits to store full-width symbols
- private static final int SHIFT_FWCH = 8;
- private static final int[] mKeyMap = {
- KeyEvent.KEYCODE_UNKNOWN,
- KeyEvent.KEYCODE_SOFT_LEFT,
- KeyEvent.KEYCODE_SOFT_RIGHT,
- KeyEvent.KEYCODE_HOME,
- KeyEvent.KEYCODE_BACK,
- KeyEvent.KEYCODE_CALL,
- KeyEvent.KEYCODE_ENDCALL,
- KeyEvent.KEYCODE_0 | ('\uff09' << SHIFT_FWCH), // )
- KeyEvent.KEYCODE_1 | ('\uff01' << SHIFT_FWCH), // !
- KeyEvent.KEYCODE_2 | ('\uff20' << SHIFT_FWCH), // @
- KeyEvent.KEYCODE_3 | ('\uff03' << SHIFT_FWCH), // #
- KeyEvent.KEYCODE_4 | ('\uffe5' << SHIFT_FWCH), // $ - fullwidth Yuan
- KeyEvent.KEYCODE_5 | ('\uff05' << SHIFT_FWCH), // %
- KeyEvent.KEYCODE_6 | ('\u2026' << SHIFT_FWCH), // ^ - Apostrophe
- KeyEvent.KEYCODE_7 | ('\uff06' << SHIFT_FWCH), // &
- KeyEvent.KEYCODE_8 | ('\uff0a' << SHIFT_FWCH), // *
- KeyEvent.KEYCODE_9 | ('\uff08' << SHIFT_FWCH), // (
- KeyEvent.KEYCODE_STAR,
- KeyEvent.KEYCODE_POUND,
- KeyEvent.KEYCODE_DPAD_UP,
- KeyEvent.KEYCODE_DPAD_DOWN,
- KeyEvent.KEYCODE_DPAD_LEFT,
- KeyEvent.KEYCODE_DPAD_RIGHT,
- KeyEvent.KEYCODE_DPAD_CENTER,
- KeyEvent.KEYCODE_VOLUME_UP,
- KeyEvent.KEYCODE_VOLUME_DOWN,
- KeyEvent.KEYCODE_POWER,
- KeyEvent.KEYCODE_CAMERA,
- KeyEvent.KEYCODE_CLEAR,
- KeyEvent.KEYCODE_A,
- KeyEvent.KEYCODE_B | ('\uff3d' << SHIFT_FWCH), // ]
- KeyEvent.KEYCODE_C | ('\u00a9' << SHIFT_FWCH), // copyright
- KeyEvent.KEYCODE_D | ('\u3001' << SHIFT_FWCH), // \\
- KeyEvent.KEYCODE_E | ('_' << SHIFT_FWCH), // _
- KeyEvent.KEYCODE_F | ('\uff5b' << SHIFT_FWCH), // {
- KeyEvent.KEYCODE_G | ('\uff5d' << SHIFT_FWCH), // }
- KeyEvent.KEYCODE_H | ('\uff1a' << SHIFT_FWCH), // :
- KeyEvent.KEYCODE_I | ('\uff0d' << SHIFT_FWCH), // -
- KeyEvent.KEYCODE_J | ('\uff1b' << SHIFT_FWCH), // ;
- KeyEvent.KEYCODE_K | ('\u201c' << SHIFT_FWCH), // "
- KeyEvent.KEYCODE_L | ('\u2019' << SHIFT_FWCH), // '
- KeyEvent.KEYCODE_M | ('\u300b' << SHIFT_FWCH), // > - French quotes
- KeyEvent.KEYCODE_N | ('\u300a' << SHIFT_FWCH), // < - French quotes
- KeyEvent.KEYCODE_O | ('\uff0b' << SHIFT_FWCH), // +
- KeyEvent.KEYCODE_P | ('\uff1d' << SHIFT_FWCH), // =
- KeyEvent.KEYCODE_Q | ('\t' << SHIFT_FWCH), // \t
- KeyEvent.KEYCODE_R | ('\u00ae' << SHIFT_FWCH), // trademark
- KeyEvent.KEYCODE_S | ('\uff5c' << SHIFT_FWCH), // |
- KeyEvent.KEYCODE_T | ('\u20ac' << SHIFT_FWCH), //
- KeyEvent.KEYCODE_U | ('\u00d7' << SHIFT_FWCH), // multiplier
- KeyEvent.KEYCODE_V | ('\uff3b' << SHIFT_FWCH), // [
- KeyEvent.KEYCODE_W | ('\uff40' << SHIFT_FWCH), // `
- KeyEvent.KEYCODE_X, KeyEvent.KEYCODE_Y | ('\u00f7' << SHIFT_FWCH),
- KeyEvent.KEYCODE_Z,
- KeyEvent.KEYCODE_COMMA | ('\uff1f' << SHIFT_FWCH),
- KeyEvent.KEYCODE_PERIOD | ('\uff0f' << SHIFT_FWCH),
- KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_ALT_RIGHT,
- KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SHIFT_RIGHT,
- KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_SYM,
- KeyEvent.KEYCODE_EXPLORER, KeyEvent.KEYCODE_ENVELOPE,
- KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_DEL,
- KeyEvent.KEYCODE_GRAVE, KeyEvent.KEYCODE_MINUS,
- KeyEvent.KEYCODE_EQUALS, KeyEvent.KEYCODE_LEFT_BRACKET,
- KeyEvent.KEYCODE_RIGHT_BRACKET, KeyEvent.KEYCODE_BACKSLASH,
- KeyEvent.KEYCODE_SEMICOLON, KeyEvent.KEYCODE_APOSTROPHE,
- KeyEvent.KEYCODE_SLASH,
- KeyEvent.KEYCODE_AT | ('\uff5e' << SHIFT_FWCH),
- KeyEvent.KEYCODE_NUM, KeyEvent.KEYCODE_HEADSETHOOK,
- KeyEvent.KEYCODE_FOCUS, KeyEvent.KEYCODE_PLUS,
- KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_NOTIFICATION,
- KeyEvent.KEYCODE_SEARCH,};
-
- static public char getChineseLabel(int keyCode) {
- if (keyCode <= 0 || keyCode >= KeyEvent.getMaxKeyCode()) return 0;
- assert ((mKeyMap[keyCode] & 0x000000ff) == keyCode);
- return (char) (mKeyMap[keyCode] >> SHIFT_FWCH);
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/PinyinDecoderService.java b/src/com/amlogic/inputmethod/remote/PinyinDecoderService.java
deleted file mode 100755
index b70faab..0000000
--- a/src/com/amlogic/inputmethod/remote/PinyinDecoderService.java
+++ b/dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import com.amlogic.inputmethod.remote.IPinyinDecoderService;
-
-import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.List;
-import java.util.Vector;
-
-import android.app.Service;
-import android.content.Intent;
-import android.content.res.AssetFileDescriptor;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * This class is used to separate the input method kernel in an individual
- * service so that both IME and IME-syncer can use it.
- */
-public class PinyinDecoderService extends Service {
- native static boolean nativeImOpenDecoder(byte fn_sys_dict[],
- byte fn_usr_dict[]);
-
- native static boolean nativeImOpenDecoderFd(FileDescriptor fd,
- long startOffset, long length, byte fn_usr_dict[]);
-
- native static void nativeImSetMaxLens(int maxSpsLen, int maxHzsLen);
-
- native static boolean nativeImCloseDecoder();
-
- native static int nativeImSearch(byte pyBuf[], int pyLen);
-
- native static int nativeImDelSearch(int pos, boolean is_pos_in_splid,
- boolean clear_fixed_this_step);
-
- native static void nativeImResetSearch();
-
- native static int nativeImAddLetter(byte ch);
-
- native static String nativeImGetPyStr(boolean decoded);
-
- native static int nativeImGetPyStrLen(boolean decoded);
-
- native static int[] nativeImGetSplStart();
-
- native static String nativeImGetChoice(int choiceId);
-
- native static int nativeImChoose(int choiceId);
-
- native static int nativeImCancelLastChoice();
-
- native static int nativeImGetFixedLen();
-
- native static boolean nativeImCancelInput();
-
- native static boolean nativeImFlushCache();
-
- native static int nativeImGetPredictsNum(String fixedStr);
-
- native static String nativeImGetPredictItem(int predictNo);
-
- // Sync related
- native static String nativeSyncUserDict(byte[] user_dict, String tomerge);
-
- native static boolean nativeSyncBegin(byte[] user_dict);
-
- native static boolean nativeSyncFinish();
-
- native static String nativeSyncGetLemmas();
-
- native static int nativeSyncPutLemmas(String tomerge);
-
- native static int nativeSyncGetLastCount();
-
- native static int nativeSyncGetTotalCount();
-
- native static boolean nativeSyncClearLastGot();
-
- native static int nativeSyncGetCapacity();
-
- private final static int MAX_PATH_FILE_LENGTH = 100;
- private static boolean inited = false;
-
- private String mUsr_dict_file;
-
- static {
- try {
- System.loadLibrary("jni_remoteime");
- } catch (UnsatisfiedLinkError ule) {
- Log.e("PinyinDecoderService",
- "WARNING: Could not load jni_remoteime natives");
- }
- }
-
- // Get file name of the specified dictionary
- private boolean getUsrDictFileName(byte usr_dict[]) {
- if (null == usr_dict) {
- return false;
- }
-
- for (int i = 0; i < mUsr_dict_file.length(); i++)
- usr_dict[i] = (byte) mUsr_dict_file.charAt(i);
- usr_dict[mUsr_dict_file.length()] = 0;
-
- return true;
- }
-
- private void initPinyinEngine() {
- byte usr_dict[];
- usr_dict = new byte[MAX_PATH_FILE_LENGTH];
-
- // Here is how we open a built-in dictionary for access through
- // a file descriptor...
- AssetFileDescriptor afd = getResources().openRawResourceFd(
- R.raw.dict_pinyin);
- if (Environment.getInstance().needDebug()) {
- Log
- .i("foo", "Dict: start=" + afd.getStartOffset()
- + ", length=" + afd.getLength() + ", fd="
- + afd.getParcelFileDescriptor());
- }
- if (getUsrDictFileName(usr_dict)) {
- inited = nativeImOpenDecoderFd(afd.getFileDescriptor(), afd
- .getStartOffset(), afd.getLength(), usr_dict);
- }
- try {
- afd.close();
- } catch (IOException e) {
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- mUsr_dict_file = getFileStreamPath("usr_dict.dat").getPath();
- // This is a hack to make sure our "files" directory has been
- // created.
- try {
- openFileOutput("dummy", 0).close();
- } catch (FileNotFoundException e) {
- } catch (IOException e) {
- }
-
- initPinyinEngine();
- }
-
- @Override
- public void onDestroy() {
- nativeImCloseDecoder();
- inited = false;
- super.onDestroy();
- }
-
- private final IPinyinDecoderService.Stub mBinder = new IPinyinDecoderService.Stub() {
- public int getInt() {
- return 12345;
- }
-
- public void setMaxLens(int maxSpsLen, int maxHzsLen) {
- nativeImSetMaxLens(maxSpsLen, maxHzsLen);
- }
-
- public int imSearch(byte[] pyBuf, int pyLen) {
- return nativeImSearch(pyBuf, pyLen);
- }
-
- public int imDelSearch(int pos, boolean is_pos_in_splid,
- boolean clear_fixed_this_step) {
- return nativeImDelSearch(pos, is_pos_in_splid,
- clear_fixed_this_step);
- }
-
- public void imResetSearch() {
- nativeImResetSearch();
- }
-
- public int imAddLetter(byte ch) {
- return nativeImAddLetter(ch);
- }
-
- public String imGetPyStr(boolean decoded) {
- return nativeImGetPyStr(decoded);
- }
-
- public int imGetPyStrLen(boolean decoded) {
- return nativeImGetPyStrLen(decoded);
- }
-
- public int[] imGetSplStart() {
- return nativeImGetSplStart();
- }
-
- public String imGetChoice(int choiceId) {
- return nativeImGetChoice(choiceId);
- }
-
- public String imGetChoices(int choicesNum) {
- String retStr = null;
- for (int i = 0; i < choicesNum; i++) {
- if (null == retStr)
- retStr = nativeImGetChoice(i);
- else
- retStr += " " + nativeImGetChoice(i);
- }
- return retStr;
- }
-
- public List<String> imGetChoiceList(int choicesStart, int choicesNum,
- int sentFixedLen) {
- Vector<String> choiceList = new Vector<String>();
- for (int i = choicesStart; i < choicesStart + choicesNum; i++) {
- String retStr = nativeImGetChoice(i);
- if (0 == i) retStr = retStr.substring(sentFixedLen);
- choiceList.add(retStr);
- }
- return choiceList;
- }
-
- public int imChoose(int choiceId) {
- return nativeImChoose(choiceId);
- }
-
- public int imCancelLastChoice() {
- return nativeImCancelLastChoice();
- }
-
- public int imGetFixedLen() {
- return nativeImGetFixedLen();
- }
-
- public boolean imCancelInput() {
- return nativeImCancelInput();
- }
-
- public void imFlushCache() {
- nativeImFlushCache();
- }
-
- public int imGetPredictsNum(String fixedStr) {
- return nativeImGetPredictsNum(fixedStr);
- }
-
- public String imGetPredictItem(int predictNo) {
- return nativeImGetPredictItem(predictNo);
- }
-
- public List<String> imGetPredictList(int predictsStart, int predictsNum) {
- Vector<String> predictList = new Vector<String>();
- for (int i = predictsStart; i < predictsStart + predictsNum; i++) {
- predictList.add(nativeImGetPredictItem(i));
- }
- return predictList;
- }
-
- public String syncUserDict(String tomerge) {
- byte usr_dict[];
- usr_dict = new byte[MAX_PATH_FILE_LENGTH];
-
- if (getUsrDictFileName(usr_dict)) {
- return nativeSyncUserDict(usr_dict, tomerge);
- }
- return null;
- }
-
- public boolean syncBegin() {
- byte usr_dict[];
- usr_dict = new byte[MAX_PATH_FILE_LENGTH];
-
- if (getUsrDictFileName(usr_dict)) {
- return nativeSyncBegin(usr_dict);
- }
- return false;
- }
-
- public void syncFinish() {
- nativeSyncFinish();
- }
-
- public int syncPutLemmas(String tomerge) {
- return nativeSyncPutLemmas(tomerge);
- }
-
- public String syncGetLemmas() {
- return nativeSyncGetLemmas();
- }
-
- public int syncGetLastCount() {
- return nativeSyncGetLastCount();
- }
-
- public int syncGetTotalCount() {
- return nativeSyncGetTotalCount();
- }
-
- public void syncClearLastGot() {
- nativeSyncClearLastGot();
- }
-
- public int imSyncGetCapacity() {
- return nativeSyncGetCapacity();
- }
- };
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/RemoteIME.java b/src/com/amlogic/inputmethod/remote/RemoteIME.java
deleted file mode 100644
index 5db6719..0000000
--- a/src/com/amlogic/inputmethod/remote/RemoteIME.java
+++ b/dev/null
@@ -1,2311 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.app.AlertDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.res.Configuration;
-import android.inputmethodservice.InputMethodService;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.View.MeasureSpec;
-import android.view.ViewGroup.LayoutParams;
-import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.LinearLayout;
-import android.widget.PopupWindow;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Vector;
-import com.droidlogic.app.SystemControlManager;
-
-/**
- * Main class of the Pinyin input method.
- */
-public class RemoteIME extends InputMethodService {
- /**
- * TAG for debug.
- */
- static final String TAG = "RemoteIME";
-
- /**
- * If is is true, IME will simulate key events for delete key, and send the
- * events back to the application.
- */
- private static final boolean SIMULATE_KEY_DELETE = true;
-
- /**
- * Necessary environment configurations like screen size for this IME.
- */
- private Environment mEnvironment;
-
- /**
- * Used to switch input mode.
- */
- private InputModeSwitcher mInputModeSwitcher;
-
- /**
- * Soft keyboard container view to host real soft keyboard view.
- */
- private SkbContainer mSkbContainer;
-
- /**
- * The floating container which contains the composing view. If necessary,
- * some other view like candiates container can also be put here.
- */
- private LinearLayout mFloatingContainer;
-
- /**
- * View to show the composing string.
- */
- private ComposingView mComposingView;
-
- /**
- * Window to show the composing string.
- */
- private PopupWindow mFloatingWindow;
-
- /**
- * Used to show the floating window.
- */
- private PopupTimer mFloatingWindowTimer = new PopupTimer();
-
- /**
- * View to show candidates list.
- */
- private CandidatesContainer mCandidatesContainer;
-
- /**
- * Balloon used when user presses a candidate.
- */
- private BalloonHint mCandidatesBalloon;
-
- /**
- * Used to notify the input method when the user touch a candidate.
- */
- private ChoiceNotifier mChoiceNotifier;
-
- /**
- * Used to notify gestures from soft keyboard.
- */
- private OnGestureListener mGestureListenerSkb;
-
- /**
- * Used to notify gestures from candidates view.
- */
- private OnGestureListener mGestureListenerCandidates;
-
- /**
- * The on-screen movement gesture detector for soft keyboard.
- */
- private GestureDetector mGestureDetectorSkb;
-
- /**
- * The on-screen movement gesture detector for candidates view.
- */
- private GestureDetector mGestureDetectorCandidates;
-
- /**
- * Option dialog to choose settings and other IMEs.
- */
- private AlertDialog mOptionsDialog;
-
- /**
- * Connection used to bind the decoding service.
- */
- private PinyinDecoderServiceConnection mPinyinDecoderServiceConnection;
-
- /**
- * The current IME status.
- *
- * @see com.amlogic.inputmethod.remote.RemoteIME.ImeState
- */
- private ImeState mImeState = ImeState.STATE_IDLE;
-
- /**
- * The decoding information, include spelling(Pinyin) string, decoding
- * result, etc.
- */
- private DecodingInfo mDecInfo = new DecodingInfo();
-
- // private TextUpdateReceiver text_receiver;//added by Linyu Bao,2011-03-10
- // private static final String TEXT_UPDATE_BROAD = "com.skyworth.controlservice.updatetext";//added by Linyu Bao,2011-03-10
- // private static final String UPDATE_TEXT = "update_text";//added by Linyu Bao,2011-03-10
-
- /**
- * For English input.
- */
- private EnglishInputProcessor mImEn;
-
- private Boolean mEnterEnabled;
-
- private Boolean mShiftTag = false;
- private SystemControlManager sw = null;
- // receive ringer mode changes
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive ( Context context, Intent intent ) {
- SoundManager.getInstance ( context ).updateRingerMode();
- }
- };
-
- @Override
- public void onCreate() {
- mEnvironment = Environment.getInstance();
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onCreate.");
- }
- super.onCreate();
-
- mEnterEnabled = getBaseContext().getResources().getBoolean(R.bool.is_enableEnter);
-
- startPinyinDecoderService();
- mImEn = new EnglishInputProcessor();
- Settings.getInstance(PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()));
-
- mInputModeSwitcher = new InputModeSwitcher(this);
- mChoiceNotifier = new ChoiceNotifier(this);
- mGestureListenerSkb = new OnGestureListener(false);
- mGestureListenerCandidates = new OnGestureListener(true);
- mGestureDetectorSkb = new GestureDetector(this, mGestureListenerSkb);
- mGestureDetectorCandidates = new GestureDetector(this,
- mGestureListenerCandidates);
-
- mEnvironment.onConfigurationChanged(getResources().getConfiguration(),
- this);
-
- sw = new SystemControlManager ( this );
- }
-
- @Override
- public void onDestroy() {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onDestroy.");
- }
- unbindService(mPinyinDecoderServiceConnection);
- Settings.releaseInstance();
- super.onDestroy();
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- Environment env = Environment.getInstance();
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onConfigurationChanged");
- Log.d(TAG, "--last config: " + env.getConfiguration().toString());
- Log.d(TAG, "---new config: " + newConfig.toString());
- }
- // We need to change the local environment first so that UI components
- // can get the environment instance to handle size issues. When
- // super.onConfigurationChanged() is called, onCreateCandidatesView()
- // and onCreateInputView() will be executed if necessary.
- env.onConfigurationChanged(newConfig, this);
-
- // Clear related UI of the previous configuration.
- if (null != mSkbContainer) {
- mSkbContainer.dismissPopups();
- }
- if (null != mCandidatesBalloon) {
- mCandidatesBalloon.dismiss();
- }
- if (newConfig.diff(env.getConfiguration()) != 0)
- super.onConfigurationChanged(newConfig);
-
- //density and display-size will be change when switch outputmode between 1080 and 720, need to update configuration
- if (sw.getPropertyBoolean("ro.platform.has.realoutputmode", false)) {
- super.onConfigurationChanged(newConfig);
- }
-
- resetToIdleState(false);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (processKey(event, 0 != event.getRepeatCount())) return true;
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (processKey(event, true)) return true;
- return super.onKeyUp(keyCode, event);
- }
-
- private boolean processKey(KeyEvent event, boolean realAction) {
- Log.d(TAG, "keycode: " + event.getKeyCode() + ", realAction: "
- + realAction);
-
- if (ImeState.STATE_BYPASS == mImeState) return false;
-
- int keyCode = event.getKeyCode();
- // SHIFT-SPACE is used to switch between Chinese and English
- // when HKB is on.
- if (KeyEvent.KEYCODE_SPACE == keyCode && event.isShiftPressed()) {
- if (!realAction) return true;
-
- updateIcon(mInputModeSwitcher.switchLanguageWithHkb());
- resetToIdleState(false);
-
- int allMetaState = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON
- | KeyEvent.META_ALT_RIGHT_ON | KeyEvent.META_SHIFT_ON
- | KeyEvent.META_SHIFT_LEFT_ON
- | KeyEvent.META_SHIFT_RIGHT_ON | KeyEvent.META_SYM_ON;
- getCurrentInputConnection().clearMetaKeyStates(allMetaState);
- return true;
- }
-
- // If HKB is on to input English, by-pass the key event so that
- // default key listener will handle it.
- if (mInputModeSwitcher.isEnglishWithHkb()) {
- return false;
- }
-
- if (mInputModeSwitcher.isChineseTextWithHkb()) {
- return false;
- }
-
- if (mSkbContainer!=null && mSkbContainer.hasFocus() && isInputViewShown()) {
- Log.d(TAG, "processKeys: processChooseSoftKeys");
- if (processChooseSoftKeys(keyCode, realAction))
- return true;
- }
-
- if (processFunctionKeys(keyCode, realAction)) {
- return true;
- }
-
- if (!realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT){
- mShiftTag = true;
- }
- int keyChar = 0;
- if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) {
- keyChar = keyCode - KeyEvent.KEYCODE_A + 'a';
- } else if (keyCode >= KeyEvent.KEYCODE_0
- && keyCode <= KeyEvent.KEYCODE_9) {
- keyChar = keyCode - KeyEvent.KEYCODE_0 + '0';
- } else if (keyCode == KeyEvent.KEYCODE_COMMA) {
- keyChar = ',';
- } else if (keyCode == KeyEvent.KEYCODE_PERIOD) {
- keyChar = '.';
- } else if (keyCode == KeyEvent.KEYCODE_SPACE) {
- keyChar = ' ';
- } else if (keyCode == KeyEvent.KEYCODE_APOSTROPHE) {
- keyChar = '\'';
- }
- if (mShiftTag) {
- keyChar = 0;
- }
-
- if (realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT)
- {
- mShiftTag = false;
- }
- if (mInputModeSwitcher.isEnglishWithSkb()) {
- Log.d(TAG, "processKeys: isEnglishWithSkb");
- return mImEn.processKey(getCurrentInputConnection(), event,
- mInputModeSwitcher.isEnglishUpperCaseWithSkb(), realAction);
- } else if (mInputModeSwitcher.isChineseText()) {
- if (mImeState == ImeState.STATE_IDLE ||
- mImeState == ImeState.STATE_APP_COMPLETION) {
- mImeState = ImeState.STATE_IDLE;
- Log.d(TAG, "processKeys: processStateIdle");
- return processStateIdle(keyChar, keyCode, event, realAction);
- } else if (mImeState == ImeState.STATE_INPUT) {
- Log.d(TAG, "processKeys: processStateInput");
- return processStateInput(keyChar, keyCode, event, realAction);
- } else if (mImeState == ImeState.STATE_PREDICT) {
- Log.d(TAG, "processKeys: processStatePredict");
- return processStatePredict(keyChar, keyCode, event, realAction);
- } else if (mImeState == ImeState.STATE_COMPOSING) {
- Log.d(TAG, "processKeys: processStateEditComposing");
- return processStateEditComposing(keyChar, keyCode, event,
- realAction);
- }
- } else {
- if (0 != keyChar) {
- if(realAction)
- commitResultText(String.valueOf((char) keyChar));
- return true;
- }
- }
-
- return false;
- }
-
- private boolean processChooseSoftKeys(int keyCode, boolean realAction) {
- Log.d(TAG, "ChooseSoftKeys: " + keyCode);
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- if (!realAction) return true;
-
- SoftKey key = mSkbContainer.processFunctionKey(keyCode);
- if (key != null) {
- // if(key.getKeyCode()==KeyEvent.KEYCODE_ENTER)
- // return false;
- responseSoftKeyEvent(key);
- return true;
- }
- }
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- if (!realAction) return true;
-
- {
- SoftKey key = mSkbContainer.processFunctionKey(keyCode);
- if (key == null) {
- mSkbContainer.clearKeyFocus();
-
- }
- return true;
- }
- }
- if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- if (!realAction) return true;
- {
- mSkbContainer.processFunctionKey(keyCode);
- return true;
- }
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- if (!realAction)
- return true;
-
- {
- SoftKey key = mSkbContainer.processFunctionKey(keyCode);
- if (key == null) {
- mSkbContainer.clearKeyFocus();
- if (null != mCandidatesContainer && mCandidatesContainer.isShown()
- && !mDecInfo.isCandidatesListEmpty()) {
- boolean ret = mCandidatesContainer.requestFocus();
- Log.d(TAG, "Candidate request focus: "+ret);
- }
- }
- return true;
- }
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- if (!realAction)
- return true;
-
- {
- SoftKey key = mSkbContainer.processFunctionKey(keyCode);
- return true;
- }
- }
-
- return false;
- }
-
- // keyCode can be from both hard key or soft key.
- private boolean processFunctionKeys(int keyCode, boolean realAction) {
- // Back key is used to dismiss all popup UI in a soft keyboard.
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (isInputViewShown()) {
- mSkbContainer.clearKeyFocus();
- if (mSkbContainer.handleBack(realAction)) return true;
- }
- }
-
- // Chinese related input is handle separately.
- if (mInputModeSwitcher.isChineseText()) {
- return false;
- }
-
- if (null != mCandidatesContainer && mCandidatesContainer.isShown()
- && !mDecInfo.isCandidatesListEmpty()) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- if (!realAction) return true;
-
- chooseCandidate(-1);
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- if (!realAction) return true;
- mCandidatesContainer.activeCurseBackward();
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- if (!realAction) return true;
- mCandidatesContainer.activeCurseForward();
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- if (!realAction) return true;
- mCandidatesContainer.pageBackward(false, true);
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- if (!realAction) return true;
- mCandidatesContainer.pageForward(false, true);
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DEL &&
- ImeState.STATE_PREDICT == mImeState) {
- if (!realAction) return true;
- resetToIdleState(false);
- return true;
- }
- } else {
- if (keyCode == KeyEvent.KEYCODE_DEL) {
- if (!realAction) return true;
- if (SIMULATE_KEY_DELETE) {
- simulateKeyEventDownUp(keyCode);
- } else {
- getCurrentInputConnection().deleteSurroundingText(1, 0);
- }
- return true;
- }
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- if (!realAction) return true;
- sendKeyChar('\n');
- return true;
- }
- if (keyCode == KeyEvent.KEYCODE_SPACE) {
- if (!realAction) return true;
- sendKeyChar(' ');
- return true;
- }
- }
-
- return false;
- }
-
- private boolean processStateIdle(int keyChar, int keyCode, KeyEvent event,
- boolean realAction) {
- // In this status, when user presses keys in [a..z], the status will
- // change to input state.
- if (keyChar >= 'a' && keyChar <= 'z' && !event.isAltPressed()) {
- if (!realAction) return true;
- mDecInfo.addSplChar((char) keyChar, true);
- chooseAndUpdate(-1);
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_DEL) {
- if (!realAction) return true;
- if (SIMULATE_KEY_DELETE) {
- simulateKeyEventDownUp(keyCode);
- } else {
- getCurrentInputConnection().deleteSurroundingText(1, 0);
- }
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_ENTER) {
- if (!realAction) return true;
- sendKeyChar('\n');
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_ALT_LEFT
- || keyCode == KeyEvent.KEYCODE_ALT_RIGHT
- || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
- || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
- return true;
- } else if (event.isAltPressed()) {
- char fullwidth_char = KeyMapDream.getChineseLabel(keyCode);
- if (0 != fullwidth_char) {
- if (realAction) {
- String result = String.valueOf(fullwidth_char);
- commitResultText(result);
- }
- return true;
- } else {
- if (keyCode >= KeyEvent.KEYCODE_A
- && keyCode <= KeyEvent.KEYCODE_Z) {
- return true;
- }
- }
- } else if (keyChar != 0 && keyChar != '\t') {
- if (realAction) {
- if (keyChar == ',' || keyChar == '.') {
- inputCommaPeriod("", keyChar, false, ImeState.STATE_IDLE);
- } else {
- if (0 != keyChar) {
- String result = String.valueOf((char) keyChar);
- commitResultText(result);
- }
- }
- }
- return true;
- }
- return false;
- }
-
- private boolean processStateInput(int keyChar, int keyCode, KeyEvent event,
- boolean realAction) {
- // If ALT key is pressed, input alternative key. But if the
- // alternative key is quote key, it will be used for input a splitter
- // in Pinyin string.
- if (event.isAltPressed()) {
- if ('\'' != event.getUnicodeChar(event.getMetaState())) {
- if (realAction) {
- char fullwidth_char = KeyMapDream.getChineseLabel(keyCode);
- if (0 != fullwidth_char) {
- commitResultText(mDecInfo
- .getCurrentFullSent(mCandidatesContainer
- .getActiveCandiatePos()) +
- String.valueOf(fullwidth_char));
- resetToIdleState(false);
- }
- }
- return true;
- } else {
- keyChar = '\'';
- }
- }
-
- if (keyChar >= 'a' && keyChar <= 'z' || keyChar == '\''
- && !mDecInfo.charBeforeCursorIsSeparator()
- || keyCode == KeyEvent.KEYCODE_DEL) {
- if (!realAction) return true;
- return processSurfaceChange(keyChar, keyCode);
- } else if (keyChar == ',' || keyChar == '.') {
- if (!realAction) return true;
- inputCommaPeriod(mDecInfo.getCurrentFullSent(mCandidatesContainer
- .getActiveCandiatePos()), keyChar, true,
- ImeState.STATE_IDLE);
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP
- || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
- || keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- if (!realAction) return true;
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- mCandidatesContainer.activeCurseBackward();
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- mCandidatesContainer.activeCurseForward();
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- // If it has been the first page, a up key will shift
- // the state to edit composing string.
- if (!mCandidatesContainer.pageBackward(false, true)) {
- mCandidatesContainer.enableActiveHighlight(false);
- changeToStateComposing(true);
- updateComposingText(true);
- }
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- // mCandidatesContainer.pageForward(false, true);
- mSkbContainer.requestFocus();
- }
- return true;
- } else if (keyCode >= KeyEvent.KEYCODE_1
- && keyCode <= KeyEvent.KEYCODE_9) {
- if (!realAction) return true;
-
- int activePos = keyCode - KeyEvent.KEYCODE_1;
- int currentPage = mCandidatesContainer.getCurrentPage();
- if (activePos < mDecInfo.getCurrentPageSize(currentPage)) {
- activePos = activePos
- + mDecInfo.getCurrentPageStart(currentPage);
- if (activePos >= 0) {
- chooseAndUpdate(activePos);
- }
- }
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_ENTER) {
- if (!realAction) return true;
- if (mInputModeSwitcher.isEnterNoramlState()) {
- commitResultText(mDecInfo.getOrigianlSplStr().toString());
- resetToIdleState(false);
- } else {
- commitResultText(mDecInfo
- .getCurrentFullSent(mCandidatesContainer
- .getActiveCandiatePos()));
- sendKeyChar('\n');
- resetToIdleState(false);
- }
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_SPACE) {
- if (!realAction) return true;
- chooseCandidate(-1);
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (!realAction) return true;
- resetToIdleState(false);
- requestHideSelf(0);
- return true;
- }
- return false;
- }
-
- private boolean processStatePredict(int keyChar, int keyCode,
- KeyEvent event, boolean realAction) {
- if (KeyEvent.isGamepadButton(keyCode)) return false;
- if (!realAction) return true;
-
- // If ALT key is pressed, input alternative key.
- if (event.isAltPressed()) {
- char fullwidth_char = KeyMapDream.getChineseLabel(keyCode);
- if (0 != fullwidth_char) {
- commitResultText(mDecInfo.getCandidate(mCandidatesContainer
- .getActiveCandiatePos()) +
- String.valueOf(fullwidth_char));
- resetToIdleState(false);
- }
- return true;
- }
-
- // In this status, when user presses keys in [a..z], the status will
- // change to input state.
- if (keyChar >= 'a' && keyChar <= 'z') {
- changeToStateInput(true);
- mDecInfo.addSplChar((char) keyChar, true);
- chooseAndUpdate(-1);
- } else if (keyChar == ',' || keyChar == '.') {
- inputCommaPeriod("", keyChar, true, ImeState.STATE_IDLE);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP
- || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
- || keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- mCandidatesContainer.activeCurseBackward();
- }
- if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- mCandidatesContainer.activeCurseForward();
- }
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- mCandidatesContainer.pageBackward(false, true);
- }
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- // mCandidatesContainer.pageForward(false, true);
- mSkbContainer.requestFocus();
- }
- } else if (keyCode == KeyEvent.KEYCODE_DEL) {
- resetToIdleState(false);
- } else if (keyCode == KeyEvent.KEYCODE_BACK) {
- resetToIdleState(false);
- requestHideSelf(0);
- } else if (keyCode >= KeyEvent.KEYCODE_1
- && keyCode <= KeyEvent.KEYCODE_9) {
- int activePos = keyCode - KeyEvent.KEYCODE_1;
- int currentPage = mCandidatesContainer.getCurrentPage();
- if (activePos < mDecInfo.getCurrentPageSize(currentPage)) {
- activePos = activePos
- + mDecInfo.getCurrentPageStart(currentPage);
- if (activePos >= 0) {
- chooseAndUpdate(activePos);
- }
- }
- } else if (keyCode == KeyEvent.KEYCODE_ENTER) {
- sendKeyChar('\n');
- resetToIdleState(false);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_SPACE) {
- chooseCandidate(-1);
- }
-
- return true;
- }
-
- private boolean processStateEditComposing(int keyChar, int keyCode,
- KeyEvent event, boolean realAction) {
- if (!realAction) return true;
-
- ComposingView.ComposingStatus cmpsvStatus =
- mComposingView.getComposingStatus();
-
- // If ALT key is pressed, input alternative key. But if the
- // alternative key is quote key, it will be used for input a splitter
- // in Pinyin string.
- if (event.isAltPressed()) {
- if ('\'' != event.getUnicodeChar(event.getMetaState())) {
- char fullwidth_char = KeyMapDream.getChineseLabel(keyCode);
- if (0 != fullwidth_char) {
- String retStr;
- if (ComposingView.ComposingStatus.SHOW_STRING_LOWERCASE ==
- cmpsvStatus) {
- retStr = mDecInfo.getOrigianlSplStr().toString();
- } else {
- retStr = mDecInfo.getComposingStr();
- }
- commitResultText(retStr + String.valueOf(fullwidth_char));
- resetToIdleState(false);
- }
- return true;
- } else {
- keyChar = '\'';
- }
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- if (!mDecInfo.selectionFinished()) {
- changeToStateInput(true);
- }
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- mComposingView.moveCursor(keyCode);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_SPACE) {
- if (ComposingView.ComposingStatus.SHOW_STRING_LOWERCASE == cmpsvStatus) {
- String str = mDecInfo.getOrigianlSplStr().toString();
- if (!tryInputRawUnicode(str)) {
- commitResultText(str);
- }
- } else if (ComposingView.ComposingStatus.EDIT_PINYIN == cmpsvStatus) {
- String str = mDecInfo.getComposingStr();
- if (!tryInputRawUnicode(str)) {
- commitResultText(str);
- }
- } else {
- commitResultText(mDecInfo.getComposingStr());
- }
- resetToIdleState(false);
- } else if (keyCode == KeyEvent.KEYCODE_ENTER
- && !mInputModeSwitcher.isEnterNoramlState()) {
- String retStr;
- if (!mDecInfo.isCandidatesListEmpty()) {
- retStr = mDecInfo.getCurrentFullSent(mCandidatesContainer
- .getActiveCandiatePos());
- } else {
- retStr = mDecInfo.getComposingStr();
- }
- commitResultText(retStr);
- sendKeyChar('\n');
- resetToIdleState(false);
- } else if (keyCode == KeyEvent.KEYCODE_BACK) {
- resetToIdleState(false);
- requestHideSelf(0);
- return true;
- } else {
- return processSurfaceChange(keyChar, keyCode);
- }
- return true;
- }
-
- private boolean tryInputRawUnicode(String str) {
- if (str.length() > 7) {
- if (str.substring(0, 7).compareTo("unicode") == 0) {
- try {
- String digitStr = str.substring(7);
- int startPos = 0;
- int radix = 10;
- if (digitStr.length() > 2 && digitStr.charAt(0) == '0'
- && digitStr.charAt(1) == 'x') {
- startPos = 2;
- radix = 16;
- }
- digitStr = digitStr.substring(startPos);
- int unicode = Integer.parseInt(digitStr, radix);
- if (unicode > 0) {
- char low = (char) (unicode & 0x0000ffff);
- char high = (char) ((unicode & 0xffff0000) >> 16);
- commitResultText(String.valueOf(low));
- if (0 != high) {
- commitResultText(String.valueOf(high));
- }
- }
- return true;
- } catch (NumberFormatException e) {
- return false;
- }
- } else if (str.substring(str.length() - 7, str.length()).compareTo(
- "unicode") == 0) {
- String resultStr = "";
- for (int pos = 0; pos < str.length() - 7; pos++) {
- if (pos > 0) {
- resultStr += " ";
- }
-
- resultStr += "0x" + Integer.toHexString(str.charAt(pos));
- }
- commitResultText(String.valueOf(resultStr));
- return true;
- }
- }
- return false;
- }
-
- private boolean processSurfaceChange(int keyChar, int keyCode) {
- if (mDecInfo.isSplStrFull() && KeyEvent.KEYCODE_DEL != keyCode) {
- return true;
- }
-
- if ((keyChar >= 'a' && keyChar <= 'z')
- || (keyChar == '\'' && !mDecInfo.charBeforeCursorIsSeparator())
- || (((keyChar >= '0' && keyChar <= '9') || keyChar == ' ') && ImeState.STATE_COMPOSING == mImeState)) {
- mDecInfo.addSplChar((char) keyChar, false);
- chooseAndUpdate(-1);
- } else if (keyCode == KeyEvent.KEYCODE_DEL) {
- mDecInfo.prepareDeleteBeforeCursor();
- chooseAndUpdate(-1);
- }
- return true;
- }
-
- private void changeToStateComposing(boolean updateUi) {
- mImeState = ImeState.STATE_COMPOSING;
- if (!updateUi) return;
-
- if (null != mSkbContainer && mSkbContainer.isShown()) {
- mSkbContainer.toggleCandidateMode(true);
- }
- }
-
- private void changeToStateInput(boolean updateUi) {
- mImeState = ImeState.STATE_INPUT;
- if (!updateUi) return;
-
- if (null != mSkbContainer && mSkbContainer.isShown()) {
- mSkbContainer.toggleCandidateMode(true);
- }
- showCandidateWindow(true);
- }
-
- private void simulateKeyEventDownUp(int keyCode) {
- InputConnection ic = getCurrentInputConnection();
- if (null == ic) return;
-
- ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
- ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
- }
-
- private void commitResultText(String resultText) {
- InputConnection ic = getCurrentInputConnection();
- if (null != ic) ic.commitText(resultText, 1);
- if (null != mComposingView) {
- mComposingView.setVisibility(View.INVISIBLE);
- mComposingView.invalidate();
- }
- }
-
- private void updateComposingText(boolean visible) {
- if (!visible) {
- mComposingView.setVisibility(View.INVISIBLE);
- } else {
- mComposingView.setDecodingInfo(mDecInfo, mImeState);
- mComposingView.setVisibility(View.VISIBLE);
- }
- mComposingView.invalidate();
- }
-
- private void inputCommaPeriod(String preEdit, int keyChar,
- boolean dismissCandWindow, ImeState nextState) {
- if (keyChar == ',')
- preEdit += '\uff0c';
- else if (keyChar == '.')
- preEdit += '\u3002';
- else
- return;
- commitResultText(preEdit);
- if (dismissCandWindow) resetCandidateWindow();
- mImeState = nextState;
- }
-
- private void resetToIdleState(boolean resetInlineText) {
- if (ImeState.STATE_IDLE == mImeState) return;
-
- mImeState = ImeState.STATE_IDLE;
- mDecInfo.reset();
-
- if (null != mComposingView) mComposingView.reset();
- if (resetInlineText) commitResultText("");
- resetCandidateWindow();
- setCandidatesViewShown(false);
- // boolean ret = mSkbContainer.requestFocus();
- // Log.d(TAG, "reset to idle:" + ret + ", hasFocus:"+mSkbContainer.hasFocus());
- }
-
- private void chooseAndUpdate(int candId) {
- if (!mInputModeSwitcher.isChineseText()) {
- String choice = mDecInfo.getCandidate(candId);
- if (null != choice) {
- commitResultText(choice);
- }
- resetToIdleState(false);
- return;
- }
-
- if (ImeState.STATE_PREDICT != mImeState) {
- // Get result candidate list, if choice_id < 0, do a new decoding.
- // If choice_id >=0, select the candidate, and get the new candidate
- // list.
- mDecInfo.chooseDecodingCandidate(candId);
- } else {
- // Choose a prediction item.
- mDecInfo.choosePredictChoice(candId);
- }
-
- if (mDecInfo.getComposingStr().length() > 0) {
- String resultStr;
- resultStr = mDecInfo.getComposingStrActivePart();
-
- // choiceId >= 0 means user finishes a choice selection.
- if (candId >= 0 && mDecInfo.canDoPrediction()) {
- commitResultText(resultStr);
- mImeState = ImeState.STATE_PREDICT;
- if (null != mSkbContainer && mSkbContainer.isShown()) {
- mSkbContainer.toggleCandidateMode(false);
- }
- // Try to get the prediction list.
- if (Settings.getPrediction()) {
- InputConnection ic = getCurrentInputConnection();
- if (null != ic) {
- CharSequence cs = ic.getTextBeforeCursor(3, 0);
- if (null != cs) {
- mDecInfo.preparePredicts(cs);
- }
- }
- } else {
- mDecInfo.resetCandidates();
- }
-
- if (mDecInfo.mCandidatesList.size() > 0) {
- showCandidateWindow(false);
- } else {
- resetToIdleState(false);
- }
- } else {
- if (ImeState.STATE_IDLE == mImeState) {
- if (mDecInfo.getSplStrDecodedLen() == 0) {
- changeToStateComposing(true);
- } else {
- changeToStateInput(true);
- }
- } else {
- if (mDecInfo.selectionFinished()) {
- changeToStateComposing(true);
- }
- }
- showCandidateWindow(true);
- }
- } else {
- resetToIdleState(false);
- }
- }
-
- // If activeCandNo is less than 0, get the current active candidate number
- // from candidate view, otherwise use activeCandNo.
- private void chooseCandidate(int activeCandNo) {
- if (activeCandNo < 0) {
- activeCandNo = mCandidatesContainer.getActiveCandiatePos();
- }
- if (activeCandNo >= 0) {
- chooseAndUpdate(activeCandNo);
- }
- }
-
- private boolean startPinyinDecoderService() {
- if (null == mDecInfo.mIPinyinDecoderService) {
- Intent serviceIntent = new Intent();
- serviceIntent.setClass(this, PinyinDecoderService.class);
-
- if (null == mPinyinDecoderServiceConnection) {
- mPinyinDecoderServiceConnection = new PinyinDecoderServiceConnection();
- }
-
- // Bind service
- if (bindService(serviceIntent, mPinyinDecoderServiceConnection,
- Context.BIND_AUTO_CREATE)) {
- return true;
- } else {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public View onCreateCandidatesView() {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onCreateCandidatesView.");
- }
-
- LayoutInflater inflater = getLayoutInflater();
- // Inflate the floating container view
- mFloatingContainer = (LinearLayout) inflater.inflate(
- R.layout.floating_container, null);
-
- // The first child is the composing view.
- mComposingView = (ComposingView) mFloatingContainer.getChildAt(0);
-
- mCandidatesContainer = (CandidatesContainer) inflater.inflate(
- R.layout.candidates_container, null);
-
- // Create balloon hint for candidates view.
- mCandidatesBalloon = new BalloonHint(this, mCandidatesContainer,
- MeasureSpec.UNSPECIFIED);
- mCandidatesBalloon.setBalloonBackground(getResources().getDrawable(
- R.drawable.candidate_balloon_bg));
- mCandidatesContainer.initialize(mChoiceNotifier, mCandidatesBalloon,
- mGestureDetectorCandidates);
-
- // The floating window
- if (null != mFloatingWindow && mFloatingWindow.isShowing()) {
- mFloatingWindowTimer.cancelShowing();
- mFloatingWindow.dismiss();
- }
- mFloatingWindow = new PopupWindow(this);
- mFloatingWindow.setClippingEnabled(false);
- mFloatingWindow.setBackgroundDrawable(null);
- mFloatingWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
- mFloatingWindow.setContentView(mFloatingContainer);
-
- setCandidatesViewShown(true);
- return mCandidatesContainer;
- }
-
-
- @Override
- public boolean onEvaluateFullscreenMode() {
- // TODO Auto-generated method stub
- return false;
- }
-
- public void responseSoftKeyEvent(SoftKey sKey) {
- if (null == sKey) return;
-
- InputConnection ic = getCurrentInputConnection();
- if (ic == null) return;
-
- int keyCode = sKey.getKeyCode();
- // Process some general keys, including KEYCODE_DEL, KEYCODE_SPACE,
- // KEYCODE_ENTER and KEYCODE_DPAD_CENTER.
- if (sKey.isKeyCodeKey()) {
- if (processFunctionKeys(keyCode, true)) return;
- }
-
- if (sKey.isUserDefKey()) {
- updateIcon(mInputModeSwitcher.switchModeForUserKey(keyCode));
- resetToIdleState(false);
- mSkbContainer.updateInputMode(true);
- } else {
- if (sKey.isKeyCodeKey()) {
- KeyEvent eDown = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
- keyCode, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD);
- KeyEvent eUp = new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode,
- 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD);
-
- onKeyDown(keyCode, eDown);
- onKeyUp(keyCode, eUp);
- } else if (sKey.isUniStrKey()) {
- boolean kUsed = false;
- String keyLabel = sKey.getKeyLabel();
- if (mInputModeSwitcher.isChineseTextWithSkb()
- && (ImeState.STATE_INPUT == mImeState || ImeState.STATE_COMPOSING == mImeState)) {
- if (mDecInfo.length() > 0 && keyLabel.length() == 1
- && keyLabel.charAt(0) == '\'') {
- processSurfaceChange('\'', 0);
- kUsed = true;
- }
- }
- if (!kUsed) {
- if (ImeState.STATE_INPUT == mImeState) {
- commitResultText(mDecInfo
- .getCurrentFullSent(mCandidatesContainer
- .getActiveCandiatePos()));
- } else if (ImeState.STATE_COMPOSING == mImeState) {
- commitResultText(mDecInfo.getComposingStr());
- }
- commitResultText(keyLabel);
- resetToIdleState(false);
- }
- }
-
- // If the current soft keyboard is not sticky, IME needs to go
- // back to the previous soft keyboard automatically.
- if (!mSkbContainer.isCurrentSkbSticky()) {
- updateIcon(mInputModeSwitcher.requestBackToPreviousSkb());
- resetToIdleState(false);
- mSkbContainer.updateInputMode();
- }
- }
- }
-
- private void showCandidateWindow(boolean showComposingView) {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "Candidates window is shown. Parent = "
- + mCandidatesContainer);
- }
-
- setCandidatesViewShown(true);
-
- if (null != mSkbContainer) mSkbContainer.requestLayout();
-
- if (null == mCandidatesContainer) {
- resetToIdleState(false);
- return;
- }
-
- updateComposingText(showComposingView);
- mCandidatesContainer.showCandidates(mDecInfo,
- ImeState.STATE_COMPOSING != mImeState);
- mFloatingWindowTimer.postShowFloatingWindow();
- }
-
- private void dismissCandidateWindow() {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "Candidates window is to be dismissed");
- }
- if (null == mCandidatesContainer) return;
- try {
- mFloatingWindowTimer.cancelShowing();
- mFloatingWindow.dismiss();
- } catch (Exception e) {
- Log.e(TAG, "Fail to show the PopupWindow.");
- }
- setCandidatesViewShown(false);
-
- if (null != mSkbContainer && mSkbContainer.isShown()) {
- mSkbContainer.toggleCandidateMode(false);
- }
- }
-
- private void resetCandidateWindow() {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "Candidates window is to be reset");
- }
- if (null == mCandidatesContainer) return;
- try {
- mFloatingWindowTimer.cancelShowing();
- mFloatingWindow.dismiss();
- } catch (Exception e) {
- Log.e(TAG, "Fail to show the PopupWindow.");
- }
-
- if (null != mSkbContainer && mSkbContainer.isShown()) {
- mSkbContainer.toggleCandidateMode(false);
- }
-
- mDecInfo.resetCandidates();
-
- if (null != mCandidatesContainer && mCandidatesContainer.isShown()) {
- showCandidateWindow(false);
- }
- }
-
- private void updateIcon(int iconId) {
- if (iconId > 0) {
- showStatusIcon(iconId);
- } else {
- hideStatusIcon();
- }
- }
-
- @Override
- public View onCreateInputView() {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onCreateInputView.");
- }
- LayoutInflater inflater = getLayoutInflater();
- mSkbContainer = (SkbContainer) inflater.inflate(R.layout.skb_container,
- null);
- mSkbContainer.setService(this);
- mSkbContainer.setInputModeSwitcher(mInputModeSwitcher);
- mSkbContainer.setGestureDetector(mGestureDetectorSkb);
- return mSkbContainer;
- }
-
- @Override
- public void onStartInput(EditorInfo editorInfo, boolean restarting) {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onStartInput " + " ccontentType: "
- + String.valueOf(editorInfo.inputType) + " Restarting:"
- + String.valueOf(restarting));
- }
- updateIcon(mInputModeSwitcher.requestInputWithHkb(editorInfo));
- resetToIdleState(false);
- }
-
- @Override
- public void onStartInputView(EditorInfo editorInfo, boolean restarting) {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onStartInputView " + " contentType: "
- + String.valueOf(editorInfo.inputType) + " Restarting:"
- + String.valueOf(restarting));
- }
- updateIcon(mInputModeSwitcher.requestInputWithSkb(editorInfo));
- resetToIdleState(false);
- mSkbContainer.updateInputMode(true);
- setCandidatesViewShown(false);
- mSkbContainer.requestFocus();
- mSkbContainer.clearKeyFocus();
- }
-
- @Override
- public void onFinishInputView(boolean finishingInput) {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onFinishInputView.");
- }
- resetToIdleState(false);
- super.onFinishInputView(finishingInput);
- }
-
- @Override
- public void onFinishInput() {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onFinishInput.");
- }
- resetToIdleState(false);
- super.onFinishInput();
- }
-
- @Override
- public void onFinishCandidatesView(boolean finishingInput) {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "onFinishCandidateView.");
- }
- resetToIdleState(false);
- super.onFinishCandidatesView(finishingInput);
- }
-
- @Override public void onDisplayCompletions(CompletionInfo[] completions) {
- if (!isFullscreenMode()) return;
- if (null == completions || completions.length <= 0) return;
- if (null == mSkbContainer || !mSkbContainer.isShown()) return;
-
- if (!mInputModeSwitcher.isChineseText() ||
- ImeState.STATE_IDLE == mImeState ||
- ImeState.STATE_PREDICT == mImeState) {
- mImeState = ImeState.STATE_APP_COMPLETION;
- mDecInfo.prepareAppCompletions(completions);
- showCandidateWindow(false);
- }
- }
-
- private void onChoiceTouched(int activeCandNo) {
- if (mImeState == ImeState.STATE_COMPOSING) {
- changeToStateInput(true);
- } else if (mImeState == ImeState.STATE_INPUT
- || mImeState == ImeState.STATE_PREDICT) {
- chooseCandidate(activeCandNo);
- } else if (mImeState == ImeState.STATE_APP_COMPLETION) {
- if (null != mDecInfo.mAppCompletions && activeCandNo >= 0 &&
- activeCandNo < mDecInfo.mAppCompletions.length) {
- CompletionInfo ci = mDecInfo.mAppCompletions[activeCandNo];
- if (null != ci) {
- InputConnection ic = getCurrentInputConnection();
- ic.commitCompletion(ci);
- }
- }
- resetToIdleState(false);
- }
- }
-
- @Override
- public void requestHideSelf(int flags) {
- if (mEnvironment.needDebug()) {
- Log.d(TAG, "DimissSoftInput.");
- }
- dismissCandidateWindow();
- if (null != mSkbContainer && mSkbContainer.isShown()) {
- mSkbContainer.dismissPopups();
- }
- super.requestHideSelf(flags);
- }
-
- public void showOptionsMenu() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setCancelable(true);
- builder.setIcon(R.drawable.app_icon);
- builder.setNegativeButton(android.R.string.cancel, null);
- CharSequence itemSettings = getString(R.string.ime_settings_activity_name);
- CharSequence itemInputMethod = getString(com.android.internal.R.string.inputMethod);
- builder.setItems(new CharSequence[] {itemSettings, itemInputMethod},
- new DialogInterface.OnClickListener() {
-
- public void onClick(DialogInterface di, int position) {
- di.dismiss();
- switch (position) {
- case 0:
- launchSettings();
- break;
- case 1:
- //InputMethodManager.getInstance(RemoteIME.this)
- // .showInputMethodPicker();
- InputMethodManager.getInstance()
- .showInputMethodPicker();
- break;
- }
- }
- });
- builder.setTitle(getString(R.string.ime_name));
- mOptionsDialog = builder.create();
- Window window = mOptionsDialog.getWindow();
- WindowManager.LayoutParams lp = window.getAttributes();
- lp.token = mSkbContainer.getWindowToken();
- lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
- window.setAttributes(lp);
- window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
- mOptionsDialog.show();
- }
-
- private void launchSettings() {
- Intent intent = new Intent();
- intent.setClass(RemoteIME.this, SettingsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- }
-
- private class PopupTimer extends Handler implements Runnable {
- private int mParentLocation[] = new int[2];
-
- void postShowFloatingWindow() {
- mFloatingContainer.measure(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- mFloatingWindow.setWidth(mFloatingContainer.getMeasuredWidth());
- mFloatingWindow.setHeight(mFloatingContainer.getMeasuredHeight());
- post(this);
- }
-
- void cancelShowing() {
- if (mFloatingWindow.isShowing()) {
- mFloatingWindow.dismiss();
- }
- removeCallbacks(this);
- }
-
- public void run() {
- mCandidatesContainer.getLocationInWindow(mParentLocation);
-
- if (!mFloatingWindow.isShowing()) {
- mFloatingWindow.showAtLocation(mCandidatesContainer,
- Gravity.LEFT | Gravity.TOP, mParentLocation[0],
- mParentLocation[1] -mFloatingWindow.getHeight());
- } else {
- mFloatingWindow
- .update(mParentLocation[0],
- mParentLocation[1] - mFloatingWindow.getHeight(),
- mFloatingWindow.getWidth(),
- mFloatingWindow.getHeight());
- }
- }
- }
-
- /**
- * Used to notify IME that the user selects a candidate or performs an
- * gesture.
- */
- public class ChoiceNotifier extends Handler implements
- CandidateViewListener {
- RemoteIME mIme;
-
- ChoiceNotifier(RemoteIME ime) {
- mIme = ime;
- }
-
- public void onClickChoice(int choiceId) {
- if (choiceId >= 0) {
- mIme.onChoiceTouched(choiceId);
- }
- }
-
- public void onToLeftGesture() {
- if (ImeState.STATE_COMPOSING == mImeState) {
- changeToStateInput(true);
- }
- mCandidatesContainer.pageForward(true, false);
- }
-
- public void onToRightGesture() {
- if (ImeState.STATE_COMPOSING == mImeState) {
- changeToStateInput(true);
- }
- mCandidatesContainer.pageBackward(true, false);
- }
-
- public void onToTopGesture() {
- }
-
- public void onToBottomGesture() {
- }
- }
-
- public class OnGestureListener extends
- GestureDetector.SimpleOnGestureListener {
- /**
- * When user presses and drags, the minimum x-distance to make a
- * response to the drag event.
- */
- private static final int MIN_X_FOR_DRAG = 60;
-
- /**
- * When user presses and drags, the minimum y-distance to make a
- * response to the drag event.
- */
- private static final int MIN_Y_FOR_DRAG = 40;
-
- /**
- * Velocity threshold for a screen-move gesture. If the minimum
- * x-velocity is less than it, no gesture.
- */
- static private final float VELOCITY_THRESHOLD_X1 = 0.3f;
-
- /**
- * Velocity threshold for a screen-move gesture. If the maximum
- * x-velocity is less than it, no gesture.
- */
- static private final float VELOCITY_THRESHOLD_X2 = 0.7f;
-
- /**
- * Velocity threshold for a screen-move gesture. If the minimum
- * y-velocity is less than it, no gesture.
- */
- static private final float VELOCITY_THRESHOLD_Y1 = 0.2f;
-
- /**
- * Velocity threshold for a screen-move gesture. If the maximum
- * y-velocity is less than it, no gesture.
- */
- static private final float VELOCITY_THRESHOLD_Y2 = 0.45f;
-
- /** If it false, we will not response detected gestures. */
- private boolean mReponseGestures;
-
- /** The minimum X velocity observed in the gesture. */
- private float mMinVelocityX = Float.MAX_VALUE;
-
- /** The minimum Y velocity observed in the gesture. */
- private float mMinVelocityY = Float.MAX_VALUE;
-
- /** The first down time for the series of touch events for an action. */
- private long mTimeDown;
-
- /** The last time when onScroll() is called. */
- private long mTimeLastOnScroll;
-
- /** This flag used to indicate that this gesture is not a gesture. */
- private boolean mNotGesture;
-
- /** This flag used to indicate that this gesture has been recognized. */
- private boolean mGestureRecognized;
-
- public OnGestureListener(boolean reponseGestures) {
- mReponseGestures = reponseGestures;
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- mMinVelocityX = Integer.MAX_VALUE;
- mMinVelocityY = Integer.MAX_VALUE;
- mTimeDown = e.getEventTime();
- mTimeLastOnScroll = mTimeDown;
- mNotGesture = false;
- mGestureRecognized = false;
- return false;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- if (mNotGesture) return false;
- if (mGestureRecognized) return true;
-
- if (Math.abs(e1.getX() - e2.getX()) < MIN_X_FOR_DRAG
- && Math.abs(e1.getY() - e2.getY()) < MIN_Y_FOR_DRAG)
- return false;
-
- long timeNow = e2.getEventTime();
- long spanTotal = timeNow - mTimeDown;
- long spanThis = timeNow - mTimeLastOnScroll;
- if (0 == spanTotal) spanTotal = 1;
- if (0 == spanThis) spanThis = 1;
-
- float vXTotal = (e2.getX() - e1.getX()) / spanTotal;
- float vYTotal = (e2.getY() - e1.getY()) / spanTotal;
-
- // The distances are from the current point to the previous one.
- float vXThis = -distanceX / spanThis;
- float vYThis = -distanceY / spanThis;
-
- float kX = vXTotal * vXThis;
- float kY = vYTotal * vYThis;
- float k1 = kX + kY;
- float k2 = Math.abs(kX) + Math.abs(kY);
-
- if (k1 / k2 < 0.8) {
- mNotGesture = true;
- return false;
- }
- float absVXTotal = Math.abs(vXTotal);
- float absVYTotal = Math.abs(vYTotal);
- if (absVXTotal < mMinVelocityX) {
- mMinVelocityX = absVXTotal;
- }
- if (absVYTotal < mMinVelocityY) {
- mMinVelocityY = absVYTotal;
- }
-
- if (mMinVelocityX < VELOCITY_THRESHOLD_X1
- && mMinVelocityY < VELOCITY_THRESHOLD_Y1) {
- mNotGesture = true;
- return false;
- }
-
- if (vXTotal > VELOCITY_THRESHOLD_X2
- && absVYTotal < VELOCITY_THRESHOLD_Y2) {
- if (mReponseGestures) onDirectionGesture(Gravity.RIGHT);
- mGestureRecognized = true;
- } else if (vXTotal < -VELOCITY_THRESHOLD_X2
- && absVYTotal < VELOCITY_THRESHOLD_Y2) {
- if (mReponseGestures) onDirectionGesture(Gravity.LEFT);
- mGestureRecognized = true;
- } else if (vYTotal > VELOCITY_THRESHOLD_Y2
- && absVXTotal < VELOCITY_THRESHOLD_X2) {
- if (mReponseGestures) onDirectionGesture(Gravity.BOTTOM);
- mGestureRecognized = true;
- } else if (vYTotal < -VELOCITY_THRESHOLD_Y2
- && absVXTotal < VELOCITY_THRESHOLD_X2) {
- if (mReponseGestures) onDirectionGesture(Gravity.TOP);
- mGestureRecognized = true;
- }
-
- mTimeLastOnScroll = timeNow;
- return mGestureRecognized;
- }
-
- @Override
- public boolean onFling(MotionEvent me1, MotionEvent me2,
- float velocityX, float velocityY) {
- return mGestureRecognized;
- }
-
- public void onDirectionGesture(int gravity) {
- if (Gravity.NO_GRAVITY == gravity) {
- return;
- }
-
- if (Gravity.LEFT == gravity || Gravity.RIGHT == gravity) {
- if (mCandidatesContainer.isShown()) {
- if (Gravity.LEFT == gravity) {
- mCandidatesContainer.pageForward(true, true);
- } else {
- mCandidatesContainer.pageBackward(true, true);
- }
- return;
- }
- }
- }
- }
-
- /**
- * Connection used for binding to the Pinyin decoding service.
- */
- public class PinyinDecoderServiceConnection implements ServiceConnection {
- public void onServiceConnected(ComponentName name, IBinder service) {
- mDecInfo.mIPinyinDecoderService = IPinyinDecoderService.Stub
- .asInterface(service);
- }
-
- public void onServiceDisconnected(ComponentName name) {
- }
- }
-
- public enum ImeState {
- STATE_BYPASS, STATE_IDLE, STATE_INPUT, STATE_COMPOSING, STATE_PREDICT,
- STATE_APP_COMPLETION
- }
-
- public class DecodingInfo {
- /**
- * Maximum length of the Pinyin string
- */
- private static final int PY_STRING_MAX = 28;
-
- /**
- * Maximum number of candidates to display in one page.
- */
- private static final int MAX_PAGE_SIZE_DISPLAY = 10;
-
- /**
- * Spelling (Pinyin) string.
- */
- private StringBuffer mSurface;
-
- /**
- * Byte buffer used as the Pinyin string parameter for native function
- * call.
- */
- private byte mPyBuf[];
-
- /**
- * The length of surface string successfully decoded by engine.
- */
- private int mSurfaceDecodedLen;
-
- /**
- * Composing string.
- */
- private String mComposingStr;
-
- /**
- * Length of the active composing string.
- */
- private int mActiveCmpsLen;
-
- /**
- * Composing string for display, it is copied from mComposingStr, and
- * add spaces between spellings.
- **/
- private String mComposingStrDisplay;
-
- /**
- * Length of the active composing string for display.
- */
- private int mActiveCmpsDisplayLen;
-
- /**
- * The first full sentence choice.
- */
- private String mFullSent;
-
- /**
- * Number of characters which have been fixed.
- */
- private int mFixedLen;
-
- /**
- * If this flag is true, selection is finished.
- */
- private boolean mFinishSelection;
-
- /**
- * The starting position for each spelling. The first one is the number
- * of the real starting position elements.
- */
- private int mSplStart[];
-
- /**
- * Editing cursor in mSurface.
- */
- private int mCursorPos;
-
- /**
- * Remote Pinyin-to-Hanzi decoding engine service.
- */
- private IPinyinDecoderService mIPinyinDecoderService;
-
- /**
- * The complication information suggested by application.
- */
- private CompletionInfo[] mAppCompletions;
-
- /**
- * The total number of choices for display. The list may only contains
- * the first part. If user tries to navigate to next page which is not
- * in the result list, we need to get these items.
- **/
- public int mTotalChoicesNum;
-
- /**
- * Candidate list. The first one is the full-sentence candidate.
- */
- public List<String> mCandidatesList = new Vector<String>();
-
- /**
- * Element i stores the starting position of page i.
- */
- public Vector<Integer> mPageStart = new Vector<Integer>();
-
- /**
- * Element i stores the number of characters to page i.
- */
- public Vector<Integer> mCnToPage = new Vector<Integer>();
-
- /**
- * The position to delete in Pinyin string. If it is less than 0, IME
- * will do an incremental search, otherwise IME will do a deletion
- * operation. if {@link #mIsPosInSpl} is true, IME will delete the whole
- * string for mPosDelSpl-th spelling, otherwise it will only delete
- * mPosDelSpl-th character in the Pinyin string.
- */
- public int mPosDelSpl = -1;
-
- /**
- * If {@link #mPosDelSpl} is big than or equal to 0, this member is used
- * to indicate that whether the postion is counted in spelling id or
- * character.
- */
- public boolean mIsPosInSpl;
-
- public DecodingInfo() {
- mSurface = new StringBuffer();
- mSurfaceDecodedLen = 0;
- }
-
- public void reset() {
- mSurface.delete(0, mSurface.length());
- mSurfaceDecodedLen = 0;
- mCursorPos = 0;
- mFullSent = "";
- mFixedLen = 0;
- mFinishSelection = false;
- mComposingStr = "";
- mComposingStrDisplay = "";
- mActiveCmpsLen = 0;
- mActiveCmpsDisplayLen = 0;
-
- resetCandidates();
- }
-
- public boolean isCandidatesListEmpty() {
- return mCandidatesList.size() == 0;
- }
-
- public boolean isSplStrFull() {
- if (mSurface.length() >= PY_STRING_MAX - 1) return true;
- return false;
- }
-
- public void addSplChar(char ch, boolean reset) {
- if (reset) {
- mSurface.delete(0, mSurface.length());
- mSurfaceDecodedLen = 0;
- mCursorPos = 0;
- try {
- mIPinyinDecoderService.imResetSearch();
- } catch (RemoteException e) {
- }
- }
- mSurface.insert(mCursorPos, ch);
- mCursorPos++;
- }
-
- // Prepare to delete before cursor. We may delete a spelling char if
- // the cursor is in the range of unfixed part, delete a whole spelling
- // if the cursor in inside the range of the fixed part.
- // This function only marks the position used to delete.
- public void prepareDeleteBeforeCursor() {
- if (mCursorPos > 0) {
- int pos;
- for (pos = 0; pos < mFixedLen; pos++) {
- if (mSplStart[pos + 2] >= mCursorPos
- && mSplStart[pos + 1] < mCursorPos) {
- mPosDelSpl = pos;
- mCursorPos = mSplStart[pos + 1];
- mIsPosInSpl = true;
- break;
- }
- }
- if (mPosDelSpl < 0) {
- mPosDelSpl = mCursorPos - 1;
- mCursorPos--;
- mIsPosInSpl = false;
- }
- }
- }
-
- public int length() {
- return mSurface.length();
- }
-
- public char charAt(int index) {
- return mSurface.charAt(index);
- }
-
- public StringBuffer getOrigianlSplStr() {
- return mSurface;
- }
-
- public int getSplStrDecodedLen() {
- return mSurfaceDecodedLen;
- }
-
- public int[] getSplStart() {
- return mSplStart;
- }
-
- public String getComposingStr() {
- return mComposingStr;
- }
-
- public String getComposingStrActivePart() {
- assert (mActiveCmpsLen <= mComposingStr.length());
- return mComposingStr.substring(0, mActiveCmpsLen);
- }
-
- public int getActiveCmpsLen() {
- return mActiveCmpsLen;
- }
-
- public String getComposingStrForDisplay() {
- return mComposingStrDisplay;
- }
-
- public int getActiveCmpsDisplayLen() {
- return mActiveCmpsDisplayLen;
- }
-
- public String getFullSent() {
- return mFullSent;
- }
-
- public String getCurrentFullSent(int activeCandPos) {
- try {
- String retStr = mFullSent.substring(0, mFixedLen);
- retStr += mCandidatesList.get(activeCandPos);
- return retStr;
- } catch (Exception e) {
- return "";
- }
- }
-
- public void resetCandidates() {
- mCandidatesList.clear();
- mTotalChoicesNum = 0;
-
- mPageStart.clear();
- mPageStart.add(0);
- mCnToPage.clear();
- mCnToPage.add(0);
- }
-
- public boolean candidatesFromApp() {
- return ImeState.STATE_APP_COMPLETION == mImeState;
- }
-
- public boolean canDoPrediction() {
- return mComposingStr.length() == mFixedLen;
- }
-
- public boolean selectionFinished() {
- return mFinishSelection;
- }
-
- // After the user chooses a candidate, input method will do a
- // re-decoding and give the new candidate list.
- // If candidate id is less than 0, means user is inputting Pinyin,
- // not selecting any choice.
- private void chooseDecodingCandidate(int candId) {
- if (mImeState != ImeState.STATE_PREDICT) {
- resetCandidates();
- int totalChoicesNum = 0;
- try {
- if (candId < 0) {
- if (length() == 0) {
- totalChoicesNum = 0;
- } else {
- if (mPyBuf == null)
- mPyBuf = new byte[PY_STRING_MAX];
- for (int i = 0; i < length(); i++)
- mPyBuf[i] = (byte) charAt(i);
- mPyBuf[length()] = 0;
-
- if (mPosDelSpl < 0) {
- totalChoicesNum = mIPinyinDecoderService
- .imSearch(mPyBuf, length());
- } else {
- boolean clear_fixed_this_step = true;
- if (ImeState.STATE_COMPOSING == mImeState) {
- clear_fixed_this_step = false;
- }
- totalChoicesNum = mIPinyinDecoderService
- .imDelSearch(mPosDelSpl, mIsPosInSpl,
- clear_fixed_this_step);
- mPosDelSpl = -1;
- }
- }
- } else {
- totalChoicesNum = mIPinyinDecoderService
- .imChoose(candId);
- }
- } catch (RemoteException e) {
- }
- updateDecInfoForSearch(totalChoicesNum);
- }
- }
-
- private void updateDecInfoForSearch(int totalChoicesNum) {
- mTotalChoicesNum = totalChoicesNum;
- if (mTotalChoicesNum < 0) {
- mTotalChoicesNum = 0;
- return;
- }
-
- try {
- String pyStr;
-
- mSplStart = mIPinyinDecoderService.imGetSplStart();
- pyStr = mIPinyinDecoderService.imGetPyStr(false);
- mSurfaceDecodedLen = mIPinyinDecoderService.imGetPyStrLen(true);
- assert (mSurfaceDecodedLen <= pyStr.length());
-
- mFullSent = mIPinyinDecoderService.imGetChoice(0);
- mFixedLen = mIPinyinDecoderService.imGetFixedLen();
-
- // Update the surface string to the one kept by engine.
- mSurface.replace(0, mSurface.length(), pyStr);
-
- if (mCursorPos > mSurface.length())
- mCursorPos = mSurface.length();
- mComposingStr = mFullSent.substring(0, mFixedLen)
- + mSurface.substring(mSplStart[mFixedLen + 1]);
-
- mActiveCmpsLen = mComposingStr.length();
- if (mSurfaceDecodedLen > 0) {
- mActiveCmpsLen = mActiveCmpsLen
- - (mSurface.length() - mSurfaceDecodedLen);
- }
-
- // Prepare the display string.
- if (0 == mSurfaceDecodedLen) {
- mComposingStrDisplay = mComposingStr;
- mActiveCmpsDisplayLen = mComposingStr.length();
- } else {
- mComposingStrDisplay = mFullSent.substring(0, mFixedLen);
- for (int pos = mFixedLen + 1; pos < mSplStart.length - 1; pos++) {
- mComposingStrDisplay += mSurface.substring(
- mSplStart[pos], mSplStart[pos + 1]);
- if (mSplStart[pos + 1] < mSurfaceDecodedLen) {
- mComposingStrDisplay += " ";
- }
- }
- mActiveCmpsDisplayLen = mComposingStrDisplay.length();
- if (mSurfaceDecodedLen < mSurface.length()) {
- mComposingStrDisplay += mSurface
- .substring(mSurfaceDecodedLen);
- }
- }
-
- if (mSplStart.length == mFixedLen + 2) {
- mFinishSelection = true;
- } else {
- mFinishSelection = false;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "PinyinDecoderService died", e);
- } catch (Exception e) {
- mTotalChoicesNum = 0;
- mComposingStr = "";
- }
- // Prepare page 0.
- if (!mFinishSelection) {
- preparePage(0);
- }
- }
-
- private void choosePredictChoice(int choiceId) {
- if (ImeState.STATE_PREDICT != mImeState || choiceId < 0
- || choiceId >= mTotalChoicesNum) {
- return;
- }
-
- String tmp = mCandidatesList.get(choiceId);
-
- resetCandidates();
-
- mCandidatesList.add(tmp);
- mTotalChoicesNum = 1;
-
- mSurface.replace(0, mSurface.length(), "");
- mCursorPos = 0;
- mFullSent = tmp;
- mFixedLen = tmp.length();
- mComposingStr = mFullSent;
- mActiveCmpsLen = mFixedLen;
-
- mFinishSelection = true;
- }
-
- public String getCandidate(int candId) {
- // Only loaded items can be gotten, so we use mCandidatesList.size()
- // instead mTotalChoiceNum.
- if (candId < 0 || candId > mCandidatesList.size()) {
- return null;
- }
- return mCandidatesList.get(candId);
- }
-
- private void getCandiagtesForCache() {
- int fetchStart = mCandidatesList.size();
- int fetchSize = mTotalChoicesNum - fetchStart;
- if (fetchSize > MAX_PAGE_SIZE_DISPLAY) {
- fetchSize = MAX_PAGE_SIZE_DISPLAY;
- }
- try {
- List<String> newList = null;
- if (ImeState.STATE_INPUT == mImeState ||
- ImeState.STATE_IDLE == mImeState ||
- ImeState.STATE_COMPOSING == mImeState){
- newList = mIPinyinDecoderService.imGetChoiceList(
- fetchStart, fetchSize, mFixedLen);
- } else if (ImeState.STATE_PREDICT == mImeState) {
- newList = mIPinyinDecoderService.imGetPredictList(
- fetchStart, fetchSize);
- } else if (ImeState.STATE_APP_COMPLETION == mImeState) {
- newList = new ArrayList<String>();
- if (null != mAppCompletions) {
- for (int pos = fetchStart; pos < fetchSize; pos++) {
- CompletionInfo ci = mAppCompletions[pos];
- if (null != ci) {
- CharSequence s = ci.getText();
- if (null != s) newList.add(s.toString());
- }
- }
- }
- }
- mCandidatesList.addAll(newList);
- } catch (RemoteException e) {
- Log.w(TAG, "PinyinDecoderService died", e);
- }
- }
-
- public boolean pageReady(int pageNo) {
- // If the page number is less than 0, return false
- if (pageNo < 0) return false;
-
- // Page pageNo's ending information is not ready.
- if (mPageStart.size() <= pageNo + 1) {
- return false;
- }
-
- return true;
- }
-
- public boolean preparePage(int pageNo) {
- // If the page number is less than 0, return false
- if (pageNo < 0) return false;
-
- // Make sure the starting information for page pageNo is ready.
- if (mPageStart.size() <= pageNo) {
- return false;
- }
-
- // Page pageNo's ending information is also ready.
- if (mPageStart.size() > pageNo + 1) {
- return true;
- }
-
- // If cached items is enough for page pageNo.
- if (mCandidatesList.size() - mPageStart.elementAt(pageNo) >= MAX_PAGE_SIZE_DISPLAY) {
- return true;
- }
-
- // Try to get more items from engine
- getCandiagtesForCache();
-
- // Try to find if there are available new items to display.
- // If no new item, return false;
- if (mPageStart.elementAt(pageNo) >= mCandidatesList.size()) {
- return false;
- }
-
- // If there are new items, return true;
- return true;
- }
-
- public void preparePredicts(CharSequence history) {
- if (null == history) return;
-
- resetCandidates();
-
- if (Settings.getPrediction()) {
- String preEdit = history.toString();
- int predictNum = 0;
- if (null != preEdit) {
- try {
- mTotalChoicesNum = mIPinyinDecoderService
- .imGetPredictsNum(preEdit);
- } catch (RemoteException e) {
- return;
- }
- }
- }
-
- preparePage(0);
- mFinishSelection = false;
- }
-
- private void prepareAppCompletions(CompletionInfo completions[]) {
- resetCandidates();
- mAppCompletions = completions;
- mTotalChoicesNum = completions.length;
- preparePage(0);
- mFinishSelection = false;
- return;
- }
-
- public int getCurrentPageSize(int currentPage) {
- if (mPageStart.size() <= currentPage + 1) return 0;
- return mPageStart.elementAt(currentPage + 1)
- - mPageStart.elementAt(currentPage);
- }
-
- public int getCurrentPageStart(int currentPage) {
- if (mPageStart.size() < currentPage + 1) return mTotalChoicesNum;
- return mPageStart.elementAt(currentPage);
- }
-
- public boolean pageForwardable(int currentPage) {
- if (mPageStart.size() <= currentPage + 1) return false;
- if (mPageStart.elementAt(currentPage + 1) >= mTotalChoicesNum) {
- return false;
- }
- return true;
- }
-
- public boolean pageBackwardable(int currentPage) {
- if (currentPage > 0) return true;
- return false;
- }
-
- public boolean charBeforeCursorIsSeparator() {
- int len = mSurface.length();
- if (mCursorPos > len) return false;
- if (mCursorPos > 0 && mSurface.charAt(mCursorPos - 1) == '\'') {
- return true;
- }
- return false;
- }
-
- public int getCursorPos() {
- return mCursorPos;
- }
-
- public int getCursorPosInCmps() {
- int cursorPos = mCursorPos;
- int fixedLen = 0;
-
- for (int hzPos = 0; hzPos < mFixedLen; hzPos++) {
- if (mCursorPos >= mSplStart[hzPos + 2]) {
- cursorPos -= mSplStart[hzPos + 2] - mSplStart[hzPos + 1];
- cursorPos += 1;
- }
- }
- return cursorPos;
- }
-
- public int getCursorPosInCmpsDisplay() {
- int cursorPos = getCursorPosInCmps();
- // +2 is because: one for mSplStart[0], which is used for other
- // purpose(The length of the segmentation string), and another
- // for the first spelling which does not need a space before it.
- for (int pos = mFixedLen + 2; pos < mSplStart.length - 1; pos++) {
- if (mCursorPos <= mSplStart[pos]) {
- break;
- } else {
- cursorPos++;
- }
- }
- return cursorPos;
- }
-
- public void moveCursorToEdge(boolean left) {
- if (left)
- mCursorPos = 0;
- else
- mCursorPos = mSurface.length();
- }
-
- // Move cursor. If offset is 0, this function can be used to adjust
- // the cursor into the bounds of the string.
- public void moveCursor(int offset) {
- if (offset > 1 || offset < -1) return;
-
- if (offset != 0) {
- int hzPos = 0;
- for (hzPos = 0; hzPos <= mFixedLen; hzPos++) {
- if (mCursorPos == mSplStart[hzPos + 1]) {
- if (offset < 0) {
- if (hzPos > 0) {
- offset = mSplStart[hzPos]
- - mSplStart[hzPos + 1];
- }
- } else {
- if (hzPos < mFixedLen) {
- offset = mSplStart[hzPos + 2]
- - mSplStart[hzPos + 1];
- }
- }
- break;
- }
- }
- }
- mCursorPos += offset;
- if (mCursorPos < 0) {
- mCursorPos = 0;
- } else if (mCursorPos > mSurface.length()) {
- mCursorPos = mSurface.length();
- }
- }
-
- public int getSplNum() {
- return mSplStart[0];
- }
-
- public int getFixedLen() {
- return mFixedLen;
- }
- }
-
-
- /* private int chineseNumber(String value) {//added by Linyu Bao,2011-03-10
- int number = 0;
- for (int i = 0; i < value.length(); i++) {
- if ((int) value.charAt(i) > 256) {
- number++;
- }
- }
- return number;
- }
-
- private void register_text_broadcast() {//added by Linyu Bao,2011-03-10
- text_receiver = new TextUpdateReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction(TEXT_UPDATE_BROAD);
- this.registerReceiver(text_receiver, filter);
- }
-
- class TextUpdateReceiver extends BroadcastReceiver {//added by Linyu Bao,2011-03-10
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "intent="+intent);
- if(intent==null)
- return;
- String action = intent.getAction();
- Log.d(TAG, "action="+action);
- if (TEXT_UPDATE_BROAD.equals(action)) {
- Bundle bundle = intent.getExtras();
- if (bundle != null) {
- String text = bundle.getString(UPDATE_TEXT);
- Log.d(TAG, "phone str: "+text);
- if (null != text && !text.equals("")) {
- InputConnection ic = getCurrentInputConnection();
- // int number = chineseNumber(text);
- // String textAll = text.substring(0, text.length() - 2
- // * number);
- // ic.setComposingText(textAll, textAll.length());
- ic.setComposingText(text, text.length());
- }
- }
- }
- }
-
- } */
-}
diff --git a/src/com/amlogic/inputmethod/remote/Settings.java b/src/com/amlogic/inputmethod/remote/Settings.java
deleted file mode 100755
index 2fc5694..0000000
--- a/src/com/amlogic/inputmethod/remote/Settings.java
+++ b/dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-
-/**
- * Class used to maintain settings.
- */
-public class Settings {
- private static final String ANDPY_CONFS_KEYSOUND_KEY = "Sound";
- private static final String ANDPY_CONFS_VIBRATE_KEY = "Vibrate";
- private static final String ANDPY_CONFS_PREDICTION_KEY = "Prediction";
-
- private static boolean mKeySound;
- private static boolean mVibrate;
- private static boolean mPrediction;
-
- private static Settings mInstance = null;
-
- private static int mRefCount = 0;
-
- private static SharedPreferences mSharedPref = null;
-
- protected Settings(SharedPreferences pref) {
- mSharedPref = pref;
- initConfs();
- }
-
- public static Settings getInstance(SharedPreferences pref) {
- if (mInstance == null) {
- mInstance = new Settings(pref);
- }
- assert (pref == mSharedPref);
- mRefCount++;
- return mInstance;
- }
-
- public static void writeBack() {
- Editor editor = mSharedPref.edit();
- editor.putBoolean(ANDPY_CONFS_VIBRATE_KEY, mVibrate);
- editor.putBoolean(ANDPY_CONFS_KEYSOUND_KEY, mKeySound);
- editor.putBoolean(ANDPY_CONFS_PREDICTION_KEY, mPrediction);
- editor.commit();
- }
-
- public static void releaseInstance() {
- mRefCount--;
- if (mRefCount == 0) {
- mInstance = null;
- }
- }
-
- private void initConfs() {
- mKeySound = mSharedPref.getBoolean(ANDPY_CONFS_KEYSOUND_KEY, true);
- mVibrate = mSharedPref.getBoolean(ANDPY_CONFS_VIBRATE_KEY, false);
- mPrediction = mSharedPref.getBoolean(ANDPY_CONFS_PREDICTION_KEY, true);
- }
-
- public static boolean getKeySound() {
- return mKeySound;
- }
-
- public static void setKeySound(boolean v) {
- if (mKeySound == v) return;
- mKeySound = v;
- }
-
- public static boolean getVibrate() {
- return mVibrate;
- }
-
- public static void setVibrate(boolean v) {
- if (mVibrate == v) return;
- mVibrate = v;
- }
-
- public static boolean getPrediction() {
- return mPrediction;
- }
-
- public static void setPrediction(boolean v) {
- if (mPrediction == v) return;
- mPrediction = v;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SettingsActivity.java b/src/com/amlogic/inputmethod/remote/SettingsActivity.java
deleted file mode 100755
index 80f918a..0000000
--- a/src/com/amlogic/inputmethod/remote/SettingsActivity.java
+++ b/dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import java.util.List;
-
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
-
-import com.amlogic.inputmethod.remote.Settings;
-
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-
-/**
- * Setting activity of Pinyin IME.
- */
-public class SettingsActivity extends PreferenceActivity implements
- Preference.OnPreferenceChangeListener {
-
- private static String TAG = "SettingsActivity";
-
- private CheckBoxPreference mKeySoundPref;
- private CheckBoxPreference mVibratePref;
- private CheckBoxPreference mPredictionPref;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.settings);
-
- PreferenceScreen prefSet = getPreferenceScreen();
-
- mKeySoundPref = (CheckBoxPreference) prefSet
- .findPreference(getString(R.string.setting_sound_key));
- mVibratePref = (CheckBoxPreference) prefSet
- .findPreference(getString(R.string.setting_vibrate_key));
- mPredictionPref = (CheckBoxPreference) prefSet
- .findPreference(getString(R.string.setting_prediction_key));
-
- prefSet.setOnPreferenceChangeListener(this);
-
- Settings.getInstance(PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()));
-
- updatePreference(prefSet, getString(R.string.setting_advanced_key));
-
- updateWidgets();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- updateWidgets();
- }
-
- @Override
- protected void onDestroy() {
- Settings.releaseInstance();
- super.onDestroy();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- Settings.setKeySound(mKeySoundPref.isChecked());
- Settings.setVibrate(mVibratePref.isChecked());
- Settings.setPrediction(mPredictionPref.isChecked());
-
- Settings.writeBack();
- }
-
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- return true;
- }
-
- private void updateWidgets() {
- mKeySoundPref.setChecked(Settings.getKeySound());
- mVibratePref.setChecked(Settings.getVibrate());
- mPredictionPref.setChecked(Settings.getPrediction());
- }
-
- public void updatePreference(PreferenceGroup parentPref, String prefKey) {
- Preference preference = parentPref.findPreference(prefKey);
- if (preference == null) {
- return;
- }
- Intent intent = preference.getIntent();
- if (intent != null) {
- PackageManager pm = getPackageManager();
- List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- int listSize = list.size();
- if (listSize == 0)
- parentPref.removePreference(preference);
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SkbContainer.java b/src/com/amlogic/inputmethod/remote/SkbContainer.java
deleted file mode 100755
index d4b4b0c..0000000
--- a/src/com/amlogic/inputmethod/remote/SkbContainer.java
+++ b/dev/null
@@ -1,801 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.inputmethodservice.InputMethodService;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.widget.PopupWindow;
-import android.widget.RelativeLayout;
-import android.widget.ViewFlipper;
-
-/**
- * The top container to host soft keyboard view(s).
- */
-public class SkbContainer extends RelativeLayout implements OnTouchListener {
- /**
- * For finger touch, user tends to press the bottom part of the target key,
- * or he/she even presses the area out of it, so it is necessary to make a
- * simple bias correction. If the input method runs on emulator, no bias
- * correction will be used.
- */
- private static final int Y_BIAS_CORRECTION = 5;
-
- /**
- * For finger touch, user tends to press the right part of the target key,
- * or he/she even presses the area out of it, so it is necessary to make a
- * simple bias correction. If the input method runs on emulator, no bias
- * correction will be used.
- */
- private static final int X_BIAS_CORRECTION = 5;
-
- /**
- * Used to skip these move events whose position is too close to the
- * previous touch events.
- */
- private static final int MOVE_TOLERANCE = 6;
-
- /**
- * If this member is true, PopupWindow is used to show on-key highlight
- * effect.
- */
- private static boolean POPUPWINDOW_FOR_PRESSED_UI = false;
-
- /**
- * The current soft keyboard layout.
- *
- * @see com.amlogic.inputmethod.remote.InputModeSwitcher for detailed layout
- * definitions.
- */
- private int mSkbLayout = 0;
-
- /**
- * The input method service.
- */
- private InputMethodService mService;
-
- /**
- * Input mode switcher used to switch between different modes like Chinese,
- * English, etc.
- */
- private InputModeSwitcher mInputModeSwitcher;
-
- /**
- * The gesture detector.
- */
- private GestureDetector mGestureDetector;
-
- private Environment mEnvironment;
-
- private ViewFlipper mSkbFlipper;
-
- /**
- * The popup balloon hint for key press/release.
- */
- private BalloonHint mBalloonPopup;
-
- /**
- * The on-key balloon hint for key press/release.
- */
- private BalloonHint mBalloonOnKey = null;
-
- /** The major sub soft keyboard. */
- private SoftKeyboardView mMajorView;
-
- /**
- * The last parameter when function {@link #toggleCandidateMode(boolean)}
- * was called.
- */
- private boolean mLastCandidatesShowing;
-
- /** Used to indicate whether a popup soft keyboard is shown. */
- private boolean mPopupSkbShow = false;
-
- /**
- * Used to indicate whether a popup soft keyboard is just shown, and waits
- * for the touch event to release. After the release, the popup window can
- * response to touch events.
- **/
- private boolean mPopupSkbNoResponse = false;
-
- /** Popup sub keyboard. */
- private PopupWindow mPopupSkb;
-
- /** The view of the popup sub soft keyboard. */
- private SoftKeyboardView mPopupSkbView;
-
- private int mPopupX;
-
- private int mPopupY;
-
- /**
- * When user presses a key, a timer is started, when it times out, it is
- * necessary to detect whether user still holds the key.
- */
- private volatile boolean mWaitForTouchUp = false;
-
- /**
- * When user drags on the soft keyboard and the distance is enough, this
- * drag will be recognized as a gesture and a gesture-based action will be
- * taken, in this situation, ignore the consequent events.
- */
- private volatile boolean mDiscardEvent = false;
-
- /**
- * For finger touch, user tends to press the bottom part of the target key,
- * or he/she even presses the area out of it, so it is necessary to make a
- * simple bias correction in Y.
- */
- private int mYBiasCorrection = 0;
-
- /**
- * For finger touch, user tends to press the bottom part of the target key,
- * or he/she even presses the area out of it, so it is necessary to make a
- * simple bias correction in x.
- */
- private int mXBiasCorrection = 0;
-
- /**
- * The x coordination of the last touch event.
- */
- private int mXLast;
-
- /**
- * The y coordination of the last touch event.
- */
- private int mYLast;
-
- /**
- * The soft keyboard view.
- */
- private SoftKeyboardView mSkv;
-
- /**
- * The position of the soft keyboard view in the container.
- */
- private int mSkvPosInContainer[] = new int[2];
-
- /**
- * The key pressed by user.
- */
- private SoftKey mSoftKeyDown = null;
-
- /**
- * Add by lyra: The key focused on.
- */
- private SoftKey mSoftKeyFocus = null;
-
- /**
- * Used to timeout a press if user holds the key for a long time.
- */
- private LongPressTimer mLongPressTimer;
-
- /**
- * For temporary use.
- */
- private int mXyPosTmp[] = new int[2];
-
- public SkbContainer(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mEnvironment = Environment.getInstance();
-
- mLongPressTimer = new LongPressTimer(this);
-
- // If it runs on an emulator, no bias correction
- if ("1".equals(SystemProperties.get("ro.kernel.qemu"))) {
- mYBiasCorrection = 0;
- mYBiasCorrection = 0;
- } else {
- mYBiasCorrection = Y_BIAS_CORRECTION;
- mXBiasCorrection = X_BIAS_CORRECTION;
- }
- mBalloonPopup = new BalloonHint(context, this, MeasureSpec.AT_MOST);
- if (POPUPWINDOW_FOR_PRESSED_UI) {
- mBalloonOnKey = new BalloonHint(context, this, MeasureSpec.AT_MOST);
- }
-
- mPopupSkb = new PopupWindow(mContext);
- mPopupSkb.setBackgroundDrawable(null);
- mPopupSkb.setClippingEnabled(false);
- }
-
- public void setService(InputMethodService service) {
- mService = service;
- }
-
- public void setInputModeSwitcher(InputModeSwitcher inputModeSwitcher) {
- mInputModeSwitcher = inputModeSwitcher;
- }
-
- public void setGestureDetector(GestureDetector gestureDetector) {
- mGestureDetector = gestureDetector;
- }
-
- public boolean isCurrentSkbSticky() {
- if (null == mMajorView) return true;
- SoftKeyboard skb = mMajorView.getSoftKeyboard();
- if (null != skb) {
- return skb.getStickyFlag();
- }
- return true;
- }
-
- public void toggleCandidateMode(boolean candidatesShowing) {
- if (null == mMajorView || !mInputModeSwitcher.isChineseText()
- || mLastCandidatesShowing == candidatesShowing) return;
- mLastCandidatesShowing = candidatesShowing;
-
- SoftKeyboard skb = mMajorView.getSoftKeyboard();
- if (null == skb) return;
-
- int state = mInputModeSwitcher.getTooggleStateForCnCand();
- if (!candidatesShowing) {
- skb.disableToggleState(state, false);
- skb.enableToggleStates(mInputModeSwitcher.getToggleStates());
- } else {
- skb.enableToggleState(state, false);
- }
-
- mMajorView.invalidate();
- }
-
- public void updateInputMode(){
- updateInputMode(false);
- }
-
- /*@hide*/
- public void updateInputMode(boolean force) {
- int skbLayout = mInputModeSwitcher.getSkbLayout();
- if (mSkbLayout != skbLayout||force) {
- mSkbLayout = skbLayout;
- updateSkbLayout(force);
- }
-
- mLastCandidatesShowing = false;
-
- if (null == mMajorView) return;
-
- SoftKeyboard skb = mMajorView.getSoftKeyboard();
- if (null == skb) return;
- skb.enableToggleStates(mInputModeSwitcher.getToggleStates());
- invalidate();
- return;
- }
-
- private void updateSkbLayout(boolean force) {
- int screenWidth = mEnvironment.getScreenWidth();
- int keyHeight = mEnvironment.getKeyHeight();
- int skbHeight = mEnvironment.getSkbHeight();
-
- Resources r = mContext.getResources();
- if (null == mSkbFlipper) {
- mSkbFlipper = (ViewFlipper) findViewById(R.id.alpha_floatable);
- }
- mMajorView = (SoftKeyboardView) mSkbFlipper.getChildAt(0);
-
- SoftKeyboard majorSkb = null;
- SkbPool skbPool = SkbPool.getInstance();
-
- switch (mSkbLayout) {
- case R.xml.skb_qwerty:
- majorSkb = skbPool.getSoftKeyboard(R.xml.skb_qwerty,
- R.xml.skb_qwerty, screenWidth, skbHeight, mContext, force);
- break;
-
- case R.xml.skb_sym1:
- majorSkb = skbPool.getSoftKeyboard(R.xml.skb_sym1, R.xml.skb_sym1,
- screenWidth, skbHeight, mContext, force);
- break;
-
- case R.xml.skb_sym2:
- majorSkb = skbPool.getSoftKeyboard(R.xml.skb_sym2, R.xml.skb_sym2,
- screenWidth, skbHeight, mContext, force);
- break;
-
- case R.xml.skb_smiley:
- majorSkb = skbPool.getSoftKeyboard(R.xml.skb_smiley,
- R.xml.skb_smiley, screenWidth, skbHeight, mContext, force);
- break;
-
- case R.xml.skb_phone:
- majorSkb = skbPool.getSoftKeyboard(R.xml.skb_phone,
- R.xml.skb_phone, screenWidth, skbHeight, mContext, force);
- break;
- default:
- }
-
- if (null == majorSkb || !mMajorView.setSoftKeyboard(majorSkb)) {
- return;
- }
- mMajorView.setBalloonHint(mBalloonOnKey, mBalloonPopup, false);
- mMajorView.invalidate();
- }
-
- private void responseKeyEvent(SoftKey sKey) {
- if (null == sKey) return;
- ((RemoteIME) mService).responseSoftKeyEvent(sKey);
- return;
- }
-
- private SoftKeyboardView inKeyboardView(int x, int y,
- int positionInParent[]) {
- if (mPopupSkbShow) {
- if (mPopupX <= x && mPopupX + mPopupSkb.getWidth() > x
- && mPopupY <= y && mPopupY + mPopupSkb.getHeight() > y) {
- positionInParent[0] = mPopupX;
- positionInParent[1] = mPopupY;
- mPopupSkbView.setOffsetToSkbContainer(positionInParent);
- return mPopupSkbView;
- }
- return null;
- }
-
- return mMajorView;
- }
-
- private void popupSymbols() {
- int popupResId = mSoftKeyDown.getPopupResId();
- if (popupResId > 0) {
- int skbContainerWidth = getWidth();
- int skbContainerHeight = getHeight();
- // The paddings of the background are not included.
- int miniSkbWidth = (int) (skbContainerWidth * 0.8);
- int miniSkbHeight = (int) (skbContainerHeight * 0.23);
-
- SkbPool skbPool = SkbPool.getInstance();
- SoftKeyboard skb = skbPool.getSoftKeyboard(popupResId, popupResId,
- miniSkbWidth, miniSkbHeight, mContext);
- if (null == skb) return;
-
- mPopupX = (skbContainerWidth - skb.getSkbTotalWidth()) / 2;
- mPopupY = (skbContainerHeight - skb.getSkbTotalHeight()) / 2;
-
- if (null == mPopupSkbView) {
- mPopupSkbView = new SoftKeyboardView(mContext, null);
- mPopupSkbView.onMeasure(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- }
- mPopupSkbView.setOnTouchListener(this);
- mPopupSkbView.setSoftKeyboard(skb);
- mPopupSkbView.setBalloonHint(mBalloonOnKey, mBalloonPopup, true);
-
- mPopupSkb.setContentView(mPopupSkbView);
- mPopupSkb.setWidth(skb.getSkbCoreWidth()
- + mPopupSkbView.getPaddingLeft()
- + mPopupSkbView.getPaddingRight());
- mPopupSkb.setHeight(skb.getSkbCoreHeight()
- + mPopupSkbView.getPaddingTop()
- + mPopupSkbView.getPaddingBottom());
-
- getLocationInWindow(mXyPosTmp);
- mPopupSkb.showAtLocation(this, Gravity.NO_GRAVITY, mPopupX, mPopupY
- + mXyPosTmp[1]);
- mPopupSkbShow = true;
- mPopupSkbNoResponse = true;
- // Invalidate itself to dim the current soft keyboards.
- dimSoftKeyboard(true);
- resetKeyPress(0);
- }
- }
-
- private void dimSoftKeyboard(boolean dimSkb) {
- mMajorView.dimSoftKeyboard(dimSkb);
- }
-
- private void dismissPopupSkb() {
- mPopupSkb.dismiss();
- mPopupSkbShow = false;
- dimSoftKeyboard(false);
- resetKeyPress(0);
- }
-
- private void resetKeyPress(long delay) {
- mLongPressTimer.removeTimer();
-
- if (null != mSkv) {
- mSkv.resetKeyPress(delay);
- }
- }
-
- public boolean handleBack(boolean realAction) {
- if (mPopupSkbShow) {
- if (!realAction) return true;
-
- dismissPopupSkb();
- mDiscardEvent = true;
- return true;
- }
- return false;
- }
-
- public void dismissPopups() {
- handleBack(true);
- resetKeyPress(0);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- Environment env = Environment.getInstance();
- int measuredWidth = env.getScreenWidth();
- int measuredHeight = getPaddingTop();
- measuredHeight += env.getSkbHeight();
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth,
- MeasureSpec.EXACTLY);
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(measuredHeight,
- MeasureSpec.EXACTLY);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
-
- if (mSkbFlipper.isFlipping()) {
- resetKeyPress(0);
- return true;
- }
-
- int x = (int) event.getX();
- int y = (int) event.getY();
- // Bias correction
- y = y + mYBiasCorrection;
- x = x + mXBiasCorrection;
-
- // Ignore short-distance movement event to get better performance.
- if (event.getAction() == MotionEvent.ACTION_MOVE) {
- if (Math.abs(x - mXLast) <= MOVE_TOLERANCE
- && Math.abs(y - mYLast) <= MOVE_TOLERANCE) {
- return true;
- }
- }
-
- mXLast = x;
- mYLast = y;
-
- if (!mPopupSkbShow) {
- if (mGestureDetector.onTouchEvent(event)) {
- resetKeyPress(0);
- mDiscardEvent = true;
- return true;
- }
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- resetKeyPress(0);
-
- mWaitForTouchUp = true;
- mDiscardEvent = false;
-
- mSkv = null;
- mSoftKeyDown = null;
- mSkv = inKeyboardView(x, y, mSkvPosInContainer);
- if (null != mSkv) {
- mSoftKeyDown = mSkv.onKeyPress(x - mSkvPosInContainer[0], y
- - mSkvPosInContainer[1], mLongPressTimer, false);
- }
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
- break;
- }
- if (mDiscardEvent) {
- resetKeyPress(0);
- break;
- }
-
- if (mPopupSkbShow && mPopupSkbNoResponse) {
- break;
- }
-
- SoftKeyboardView skv = inKeyboardView(x, y, mSkvPosInContainer);
- if (null != skv) {
- if (skv != mSkv) {
- mSkv = skv;
- mSoftKeyDown = mSkv.onKeyPress(x - mSkvPosInContainer[0], y
- - mSkvPosInContainer[1], mLongPressTimer, true);
- } else if (null != skv) {
- if (null != mSkv) {
- mSoftKeyDown = mSkv.onKeyMove(
- x - mSkvPosInContainer[0], y
- - mSkvPosInContainer[1]);
- if (null == mSoftKeyDown) {
- mDiscardEvent = true;
- }
- }
- }
- }
- break;
-
- case MotionEvent.ACTION_UP:
- if (mDiscardEvent) {
- resetKeyPress(0);
- break;
- }
-
- mWaitForTouchUp = false;
-
- // The view which got the {@link MotionEvent#ACTION_DOWN} event is
- // always used to handle this event.
- if (null != mSkv) {
- mSkv.onKeyRelease(x - mSkvPosInContainer[0], y
- - mSkvPosInContainer[1]);
- }
-
- if (!mPopupSkbShow || !mPopupSkbNoResponse) {
- responseKeyEvent(mSoftKeyDown);
- requestFocus();
- mSoftKeyFocus = mSoftKeyDown;
- mMajorView.changeFocusKey(mSoftKeyFocus);
- }
-
- if (mSkv == mPopupSkbView && !mPopupSkbNoResponse) {
- dismissPopupSkb();
- }
- mPopupSkbNoResponse = false;
- break;
-
- case MotionEvent.ACTION_CANCEL:
- break;
- }
-
- if (null == mSkv) {
- return false;
- }
-
- return true;
- }
-
- // Function for interface OnTouchListener, it is used to handle touch events
- // which will be delivered to the popup soft keyboard view.
- public boolean onTouch(View v, MotionEvent event) {
- // Translate the event to fit to the container.
- MotionEvent newEv = MotionEvent.obtain(event.getDownTime(), event
- .getEventTime(), event.getAction(), event.getX() + mPopupX,
- event.getY() + mPopupY, event.getPressure(), event.getSize(),
- event.getMetaState(), event.getXPrecision(), event
- .getYPrecision(), event.getDeviceId(), event
- .getEdgeFlags());
- boolean ret = onTouchEvent(newEv);
- return ret;
- }
-
- class LongPressTimer extends Handler implements Runnable {
- /**
- * When user presses a key for a long time, the timeout interval to
- * generate first {@link #LONG_PRESS_KEYNUM1} key events.
- */
- public static final int LONG_PRESS_TIMEOUT1 = 500;
-
- /**
- * When user presses a key for a long time, after the first
- * {@link #LONG_PRESS_KEYNUM1} key events, this timeout interval will be
- * used.
- */
- private static final int LONG_PRESS_TIMEOUT2 = 100;
-
- /**
- * When user presses a key for a long time, after the first
- * {@link #LONG_PRESS_KEYNUM2} key events, this timeout interval will be
- * used.
- */
- private static final int LONG_PRESS_TIMEOUT3 = 100;
-
- /**
- * When user presses a key for a long time, after the first
- * {@link #LONG_PRESS_KEYNUM1} key events, timeout interval
- * {@link #LONG_PRESS_TIMEOUT2} will be used instead.
- */
- public static final int LONG_PRESS_KEYNUM1 = 1;
-
- /**
- * When user presses a key for a long time, after the first
- * {@link #LONG_PRESS_KEYNUM2} key events, timeout interval
- * {@link #LONG_PRESS_TIMEOUT3} will be used instead.
- */
- public static final int LONG_PRESS_KEYNUM2 = 3;
-
- SkbContainer mSkbContainer;
-
- private int mResponseTimes = 0;
-
- public LongPressTimer(SkbContainer skbContainer) {
- mSkbContainer = skbContainer;
- }
-
- public void startTimer() {
- postAtTime(this, SystemClock.uptimeMillis() + LONG_PRESS_TIMEOUT1);
- mResponseTimes = 0;
- }
-
- public boolean removeTimer() {
- removeCallbacks(this);
- return true;
- }
-
- public void run() {
- if (mWaitForTouchUp) {
- mResponseTimes++;
- if (mSoftKeyDown.repeatable()) {
- if (mSoftKeyDown.isUserDefKey()) {
- if (1 == mResponseTimes) {
- if (mInputModeSwitcher
- .tryHandleLongPressSwitch(mSoftKeyDown.mKeyCode)) {
- mDiscardEvent = true;
- resetKeyPress(0);
- }
- }
- } else {
- responseKeyEvent(mSoftKeyDown);
- long timeout;
- if (mResponseTimes < LONG_PRESS_KEYNUM1) {
- timeout = LONG_PRESS_TIMEOUT1;
- } else if (mResponseTimes < LONG_PRESS_KEYNUM2) {
- timeout = LONG_PRESS_TIMEOUT2;
- } else {
- timeout = LONG_PRESS_TIMEOUT3;
- }
- postAtTime(this, SystemClock.uptimeMillis() + timeout);
- }
- } else {
- if (1 == mResponseTimes) {
- popupSymbols();
- }
- }
- }
- }
- }
-
- //Add by lyra, return value: lose keyboard focus
- public SoftKey processFunctionKey(int keyCode) {
- // TODO Auto-generated method stub
- SoftKeyboard skb = mMajorView.getSoftKeyboard();
- if (null == skb) return null;
-
- if(!this.hasFocus()){
- Log.d("SoftKeyboard", "keyboard no focus");
- return null;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- return mSoftKeyFocus;
- }
- else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- /* if(mSoftKeyFocus==null)
- mSoftKeyFocus=skb.getKey(0,-1);
- else{
- int row = mSoftKeyFocus.mRow;
- int loc = mSoftKeyFocus.mLocation-1;
- if(loc<0 && row==0)
- return null;
- else if(loc<0)
- {
- int i = row-1;
- for (; i >= 0; i--) {
- if(skb.getKeyRowForDisplay(i)!=null)
- break;
- }
-
- if(i>=0)
- row = i;
- }
- mSoftKeyFocus = skb.getKey(row,loc);
- } */
- if(mSoftKeyFocus==null)
- mSoftKeyFocus=skb.getKey(0,0);
- else
- {
- if (mSoftKeyFocus.mLocation > 0) {
- int x = mSoftKeyFocus.mLeft-skb.getKeyXMargin()-10;
- int y = mSoftKeyFocus.mTop+mSoftKeyFocus.height()/2;
- mSoftKeyFocus = skb.mapToKey(x,y);
- } else {
- mSoftKeyFocus = skb.getKey(mSoftKeyFocus.mRow, -1);
- }
- }
- }
- else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- /* if(mSoftKeyFocus==null)
- mSoftKeyFocus=skb.getKey(0,0);
- else{
- int row = mSoftKeyFocus.mRow;
- int loc = mSoftKeyFocus.mLocation;
-
- mSoftKeyFocus = skb.getKey(row,loc+1);
- if(mSoftKeyFocus==null){
- int i = row+1;
- for (; i < skb.getRowNum(); i++) {
- if(skb.getKeyRowForDisplay(i)!=null)
- break;
- }
- if(i<skb.getRowNum())
- mSoftKeyFocus = skb.getKey(i,0);
- else
- mSoftKeyFocus = skb.getKey(row, loc);
- }
- }*/
-
- if(mSoftKeyFocus==null)
- mSoftKeyFocus=skb.getKey(0,0);
- else
- {
- int keyNum = skb.getLocNum(mSoftKeyFocus.mRow);
- if (mSoftKeyFocus.mLocation < keyNum - 1) {
- int x = mSoftKeyFocus.mRight+skb.getKeyXMargin();
- int y = mSoftKeyFocus.mTop+mSoftKeyFocus.height()/2;
- mSoftKeyFocus = skb.mapToKey(x,y);
- } else {
- mSoftKeyFocus = skb.getKey(mSoftKeyFocus.mRow, 0);
- }
- }
-
- }
- else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- if(mSoftKeyFocus==null)
- mSoftKeyFocus=skb.getKey(0,0);
- else if(mSoftKeyFocus.mRow==0)
- return null;
- else
- {
- int x = mSoftKeyFocus.mLeft+mSoftKeyFocus.width()/2;
- int y = mSoftKeyFocus.mTop-mSoftKeyFocus.height()/2;
- mSoftKeyFocus = skb.mapToKey(x,y);
- //mSoftKeyFocus = skb.getKey(mSoftKeyFocus.mRow-1,mSoftKeyFocus.mLocation);
- }
- }
- else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- if(mSoftKeyFocus==null)
- mSoftKeyFocus=skb.getKey(0,0);
- else
- {
- int x = mSoftKeyFocus.mLeft+mSoftKeyFocus.width()/2;
- int y = mSoftKeyFocus.mBottom+mSoftKeyFocus.height()/2;
- mSoftKeyFocus = skb.mapToKey(x,y);
- //skb.getKey(mSoftKeyFocus.mRow+1,mSoftKeyFocus.mLocation);
- }
- }
-
- if(mSoftKeyFocus!=null)
- Log.d("SkbContainer", "focus Key code: "+ mSoftKeyFocus.mKeyCode + ", row="+mSoftKeyFocus.mRow+", loc="+mSoftKeyFocus.mLocation);
-
- // mMajorView.mSoftKeyFocus = mSoftKeyFocus;
- // mMajorView.invalidate();
- mMajorView.changeFocusKey(mSoftKeyFocus);
-
- return mSoftKeyFocus;
- }
-
- public void clearKeyFocus() {
- mSoftKeyFocus = null;
- if(mMajorView!=null)
- mMajorView.mSoftKeyFocus = null;
- clearFocus();
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SkbPool.java b/src/com/amlogic/inputmethod/remote/SkbPool.java
deleted file mode 100755
index 95cea6e..0000000
--- a/src/com/amlogic/inputmethod/remote/SkbPool.java
+++ b/dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import java.util.Vector;
-
-import android.content.Context;
-
-/**
- * Class used to cache previously loaded soft keyboard layouts.
- */
-public class SkbPool {
- private static SkbPool mInstance = null;
-
- private Vector<SkbTemplate> mSkbTemplates = new Vector<SkbTemplate>();
- private Vector<SoftKeyboard> mSoftKeyboards = new Vector<SoftKeyboard>();
-
- private SkbPool() {
- }
-
- public static SkbPool getInstance() {
- if (null == mInstance) mInstance = new SkbPool();
- return mInstance;
- }
-
- public void resetCachedSkb() {
- mSoftKeyboards.clear();
- }
-
- public SkbTemplate getSkbTemplate(int skbTemplateId, Context context, boolean force) {
- for (int i = 0; i < mSkbTemplates.size()&&(!force); i++) {
- SkbTemplate t = mSkbTemplates.elementAt(i);
- if (t.getSkbTemplateId() == skbTemplateId) {
- return t;
- }
- }
- if (null != context||(force && (null != context))) {
- XmlKeyboardLoader xkbl = new XmlKeyboardLoader(context);
- SkbTemplate t = xkbl.loadSkbTemplate(skbTemplateId);
- if (null != t) {
- mSkbTemplates.add(t);
- return t;
- }
- }
- return null;
- }
-
- public SoftKeyboard getSoftKeyboard(int skbCacheId, int skbXmlId,
- int skbWidth, int skbHeight, Context context) {
- return getSoftKeyboard( skbCacheId, skbXmlId, skbWidth, skbHeight, context, false);
- }
- /*@hide*/
- // Try to find the keyboard in the pool with the cache id. If there is no
- // keyboard found, try to load it with the given xml id.
- public SoftKeyboard getSoftKeyboard(int skbCacheId, int skbXmlId,
- int skbWidth, int skbHeight, Context context,boolean force) {
- for (int i = 0; i < mSoftKeyboards.size()&&(!force); i++) {
- SoftKeyboard skb = mSoftKeyboards.elementAt(i);
- if (skb.getCacheId() == skbCacheId && skb.getSkbXmlId() == skbXmlId) {
- skb.setSkbCoreSize(skbWidth, skbHeight);
- skb.setNewlyLoadedFlag(false);
- return skb;
- }
- }
- if (null != context ||((null != context) && force)) {
- XmlKeyboardLoader xkbl = new XmlKeyboardLoader(context);
- SoftKeyboard skb = xkbl.loadKeyboard(skbXmlId, skbWidth, skbHeight, force);
- if (skb != null) {
- if (skb.getCacheFlag()) {
- skb.setCacheId(skbCacheId);
- mSoftKeyboards.add(skb);
- }
- }
- return skb;
- }
- return null;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SkbTemplate.java b/src/com/amlogic/inputmethod/remote/SkbTemplate.java
deleted file mode 100755
index ae7e424..0000000
--- a/src/com/amlogic/inputmethod/remote/SkbTemplate.java
+++ b/dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.graphics.drawable.Drawable;
-
-import java.util.Vector;
-
-/**
- * Key icon definition. It is defined in soft keyboard template. A soft keyboard
- * can refer to such an icon in its xml file directly to improve performance.
- */
-class KeyIconRecord {
- int keyCode;
- Drawable icon;
- Drawable iconPopup;
-}
-
-
-/**
- * Default definition for a certain key. It is defined in soft keyboard
- * template. A soft keyboard can refer to a default key in its xml file. Nothing
- * of the key can be overwritten, including the size.
- */
-class KeyRecord {
- int keyId;
- SoftKey softKey;
-}
-
-
-/**
- * Soft keyboard template used by soft keyboards to share common resources. In
- * this way, memory cost is reduced.
- */
-public class SkbTemplate {
- private int mSkbTemplateId;
- private Drawable mSkbBg;
- private Drawable mBalloonBg;
- private Drawable mPopupBg;
- private float mXMargin = 0;
- private float mYMargin = 0;
- /** Key type list. */
- private Vector<SoftKeyType> mKeyTypeList = new Vector<SoftKeyType>();
-
- /**
- * Default key icon list. It is only for keys which do not have popup icons.
- */
- private Vector<KeyIconRecord> mKeyIconRecords = new Vector<KeyIconRecord>();
-
- /**
- * Default key list.
- */
- private Vector<KeyRecord> mKeyRecords = new Vector<KeyRecord>();
-
- public SkbTemplate(int skbTemplateId) {
- mSkbTemplateId = skbTemplateId;
- }
-
- public int getSkbTemplateId() {
- return mSkbTemplateId;
- }
-
- public void setBackgrounds(Drawable skbBg, Drawable balloonBg,
- Drawable popupBg) {
- mSkbBg = skbBg;
- mBalloonBg = balloonBg;
- mPopupBg = popupBg;
- }
-
- public Drawable getSkbBackground() {
- return mSkbBg;
- }
-
- public Drawable getBalloonBackground() {
- return mBalloonBg;
- }
-
- public Drawable getPopupBackground() {
- return mPopupBg;
- }
-
- public void setMargins(float xMargin, float yMargin) {
- mXMargin = xMargin;
- mYMargin = yMargin;
- }
-
- public float getXMargin() {
- return mXMargin;
- }
-
- public float getYMargin() {
- return mYMargin;
- }
-
- public SoftKeyType createKeyType(int id, Drawable bg, Drawable hlBg) {
- return new SoftKeyType(id, bg, hlBg);
- }
-
- public boolean addKeyType(SoftKeyType keyType) {
- // The newly added item should have the right id.
- if (mKeyTypeList.size() != keyType.mKeyTypeId) return false;
- mKeyTypeList.add(keyType);
- return true;
- }
-
- public SoftKeyType getKeyType(int typeId) {
- if (typeId < 0 || typeId > mKeyTypeList.size()) return null;
- return mKeyTypeList.elementAt(typeId);
- }
-
- public void addDefaultKeyIcons(int keyCode, Drawable icon,
- Drawable iconPopup) {
- if (null == icon || null == iconPopup) return;
-
- KeyIconRecord iconRecord = new KeyIconRecord();
- iconRecord.icon = icon;
- iconRecord.iconPopup = iconPopup;
- iconRecord.keyCode = keyCode;
-
- int size = mKeyIconRecords.size();
- int pos = 0;
- while (pos < size) {
- if (mKeyIconRecords.get(pos).keyCode >= keyCode) break;
- pos++;
- }
- mKeyIconRecords.add(pos, iconRecord);
- }
-
- public Drawable getDefaultKeyIcon(int keyCode) {
- int size = mKeyIconRecords.size();
- int pos = 0;
- while (pos < size) {
- KeyIconRecord iconRecord = mKeyIconRecords.get(pos);
- if (iconRecord.keyCode < keyCode) {
- pos++;
- continue;
- }
- if (iconRecord.keyCode == keyCode) {
- return iconRecord.icon;
- }
- return null;
- }
- return null;
- }
-
- public Drawable getDefaultKeyIconPopup(int keyCode) {
- int size = mKeyIconRecords.size();
- int pos = 0;
- while (pos < size) {
- KeyIconRecord iconRecord = mKeyIconRecords.get(pos);
- if (iconRecord.keyCode < keyCode) {
- pos++;
- continue;
- }
- if (iconRecord.keyCode == keyCode) {
- return iconRecord.iconPopup;
- }
- return null;
- }
- return null;
- }
-
- public void addDefaultKey(int keyId, SoftKey softKey) {
- if (null == softKey) return;
-
- KeyRecord keyRecord = new KeyRecord();
- keyRecord.keyId = keyId;
- keyRecord.softKey = softKey;
-
- int size = mKeyRecords.size();
- int pos = 0;
- while (pos < size) {
- if (mKeyRecords.get(pos).keyId >= keyId) break;
- pos++;
- }
- mKeyRecords.add(pos, keyRecord);
- }
-
- public SoftKey getDefaultKey(int keyId) {
- int size = mKeyRecords.size();
- int pos = 0;
- while (pos < size) {
- KeyRecord keyRecord = mKeyRecords.get(pos);
- if (keyRecord.keyId < keyId) {
- pos++;
- continue;
- }
- if (keyRecord.keyId == keyId) {
- return keyRecord.softKey;
- }
- return null;
- }
- return null;
- }
-}
-
-
-class SoftKeyType {
- public static final int KEYTYPE_ID_NORMAL_KEY = 0;
-
- public int mKeyTypeId;
- public Drawable mKeyBg;
- public Drawable mKeyHlBg;
- public int mColor;
- public int mColorHl;
- public int mColorBalloon;
-
- SoftKeyType(int id, Drawable bg, Drawable hlBg) {
- mKeyTypeId = id;
- mKeyBg = bg;
- mKeyHlBg = hlBg;
- }
-
- public void setColors(int color, int colorHl, int colorBalloon) {
- mColor = color;
- mColorHl = colorHl;
- mColorBalloon = colorBalloon;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SoftKey.java b/src/com/amlogic/inputmethod/remote/SoftKey.java
deleted file mode 100755
index 962fa43..0000000
--- a/src/com/amlogic/inputmethod/remote/SoftKey.java
+++ b/dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.graphics.drawable.Drawable;
-
-/**
- * Class for soft keys which defined in the keyboard xml file. A soft key can be
- * a basic key or a toggling key.
- *
- * @see com.amlogic.inputmethod.remote.SoftKeyToggle
- */
-public class SoftKey {
- protected static final int KEYMASK_REPEAT = 0x10000000;
- protected static final int KEYMASK_BALLOON = 0x20000000;
-
- /**
- * For a finger touch device, after user presses a key, there will be some
- * consequent moving events because of the changing in touching pressure. If
- * the moving distance in x is within this threshold, the moving events will
- * be ignored.
- */
- public static final int MAX_MOVE_TOLERANCE_X = 0;
-
- /**
- * For a finger touch device, after user presses a key, there will be some
- * consequent moving events because of the changing in touching pressure. If
- * the moving distance in y is within this threshold, the moving events will
- * be ignored.
- */
- public static final int MAX_MOVE_TOLERANCE_Y = 0;
-
- /**
- * Used to indicate the type and attributes of this key. the lowest 8 bits
- * should be reserved for SoftkeyToggle.
- */
- protected int mKeyMask;
-
- protected SoftKeyType mKeyType;
-
- protected Drawable mKeyIcon;
-
- protected Drawable mKeyIconPopup;
-
- protected String mKeyLabel;
-
- protected int mKeyCode;
-
- /**
- * If this value is not 0, this key can be used to popup a sub soft keyboard
- * when user presses it for some time.
- */
- public int mPopupSkbId;
-
- public float mLeftF;
- public float mRightF;
- public float mTopF;
- public float mBottomF;
- public int mLeft;
- public int mRight;
- public int mTop;
- public int mBottom;
-
- public int mRow;
- public int mLocation;
-
- public void setKeyType(SoftKeyType keyType, Drawable keyIcon,
- Drawable keyIconPopup) {
- mKeyType = keyType;
- mKeyIcon = keyIcon;
- mKeyIconPopup = keyIconPopup;
- }
-
- // The caller guarantees that all parameters are in [0, 1]
- public void setKeyDimensions(float left, float top, float right,
- float bottom) {
- mLeftF = left;
- mTopF = top;
- mRightF = right;
- mBottomF = bottom;
- }
-
- public void setKeyAttribute(int keyCode, String label, boolean repeat,
- boolean balloon) {
- mKeyCode = keyCode;
- mKeyLabel = label;
-
- if (repeat) {
- mKeyMask |= KEYMASK_REPEAT;
- } else {
- mKeyMask &= (~KEYMASK_REPEAT);
- }
-
- if (balloon) {
- mKeyMask |= KEYMASK_BALLOON;
- } else {
- mKeyMask &= (~KEYMASK_BALLOON);
- }
- }
-
- public void setPopupSkbId(int popupSkbId) {
- mPopupSkbId = popupSkbId;
- }
-
- // Call after setKeyDimensions(). The caller guarantees that the
- // keyboard with and height are valid.
- public void setSkbCoreSize(int skbWidth, int skbHeight) {
- mLeft = (int) (mLeftF * skbWidth);
- mRight = (int) (mRightF * skbWidth);
- mTop = (int) (mTopF * skbHeight);
- mBottom = (int) (mBottomF * skbHeight);
- }
-
- public Drawable getKeyIcon() {
- return mKeyIcon;
- }
-
- public Drawable getKeyIconPopup() {
- if (null != mKeyIconPopup) {
- return mKeyIconPopup;
- }
- return mKeyIcon;
- }
-
- public int getKeyCode() {
- return mKeyCode;
- }
-
- public String getKeyLabel() {
- return mKeyLabel;
- }
-
- public void changeCase(boolean upperCase) {
- if (null != mKeyLabel) {
- if (upperCase)
- mKeyLabel = mKeyLabel.toUpperCase();
- else
- mKeyLabel = mKeyLabel.toLowerCase();
- }
- }
-
- public Drawable getKeyBg() {
- return mKeyType.mKeyBg;
- }
-
- public Drawable getKeyHlBg() {
- return mKeyType.mKeyHlBg;
- }
-
- public int getColor() {
- return mKeyType.mColor;
- }
-
- public int getColorHl() {
- return mKeyType.mColorHl;
- }
-
- public int getColorBalloon() {
- return mKeyType.mColorBalloon;
- }
-
- public boolean isKeyCodeKey() {
- if (mKeyCode > 0) return true;
- return false;
- }
-
- public boolean isUserDefKey() {
- if (mKeyCode < 0) return true;
- return false;
- }
-
- public boolean isUniStrKey() {
- if (null != mKeyLabel && mKeyCode == 0) return true;
- return false;
- }
-
- public boolean needBalloon() {
- return (mKeyMask & KEYMASK_BALLOON) != 0;
- }
-
- public boolean repeatable() {
- return (mKeyMask & KEYMASK_REPEAT) != 0;
- }
-
- public int getPopupResId() {
- return mPopupSkbId;
- }
-
- public int width() {
- return mRight - mLeft;
- }
-
- public int height() {
- return mBottom - mTop;
- }
-
- public boolean moveWithinKey(int x, int y) {
- if (mLeft - MAX_MOVE_TOLERANCE_X <= x
- && mTop - MAX_MOVE_TOLERANCE_Y <= y
- && mRight + MAX_MOVE_TOLERANCE_X > x
- && mBottom + MAX_MOVE_TOLERANCE_Y > y) {
- return true;
- }
- return false;
- }
-
- @Override
- public String toString() {
- String str = "\n";
- str += " keyCode: " + String.valueOf(mKeyCode) + "\n";
- str += " keyMask: " + String.valueOf(mKeyMask) + "\n";
- str += " keyLabel: " + (mKeyLabel == null ? "null" : mKeyLabel) + "\n";
- str += " popupResId: " + String.valueOf(mPopupSkbId) + "\n";
- str += " Position: " + String.valueOf(mLeftF) + ", "
- + String.valueOf(mTopF) + ", " + String.valueOf(mRightF) + ", "
- + String.valueOf(mBottomF) + "\n";
- return str;
- }
-
- public void setKeyPos(int row, int location) {
- mRow = row;
- mLocation = location;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SoftKeyToggle.java b/src/com/amlogic/inputmethod/remote/SoftKeyToggle.java
deleted file mode 100755
index 261963c..0000000
--- a/src/com/amlogic/inputmethod/remote/SoftKeyToggle.java
+++ b/dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.graphics.drawable.Drawable;
-
-/**
- * Class for soft keys which defined in the keyboard xml file. A soft key can be
- * a basic key or a toggling key.
- *
- * @see com.amlogic.inputmethod.remote.SoftKey
- */
-public class SoftKeyToggle extends SoftKey {
- /**
- * The current state number is stored in the lowest 8 bits of mKeyMask, this
- * mask is used to get the state number. If the current state is 0, the
- * normal state is enabled; if the current state is more than 0, a toggle
- * state in the toggle state chain will be enabled.
- */
- private static final int KEYMASK_TOGGLE_STATE = 0x000000ff;
-
- private ToggleState mToggleState;
-
- public int getToggleStateId() {
- return (mKeyMask & KEYMASK_TOGGLE_STATE);
- }
-
- // The state id should be valid, and less than 255.
- // If resetIfNotFound is true and there is no such toggle state with the
- // given id, the key state will be reset.
- // If the key state is newly changed (enabled to the given state, or
- // reseted) and needs re-draw, return true.
- public boolean enableToggleState(int stateId, boolean resetIfNotFound) {
- int oldStateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
- if (oldStateId == stateId) return false;
-
- mKeyMask &= (~KEYMASK_TOGGLE_STATE);
- if (stateId > 0) {
- mKeyMask |= (KEYMASK_TOGGLE_STATE & stateId);
- if (getToggleState() == null) {
- mKeyMask &= (~KEYMASK_TOGGLE_STATE);
- if (!resetIfNotFound && oldStateId > 0) {
- mKeyMask |= (KEYMASK_TOGGLE_STATE & oldStateId);
- }
- return resetIfNotFound;
- } else {
- return true;
- }
- } else {
- return true;
- }
- }
-
- // The state id should be valid, and less than 255.
- // If resetIfNotFound is true and there is no such toggle state with the
- // given id, the key state will be reset.
- // If the key state is newly changed and needs re-draw, return true.
- public boolean disableToggleState(int stateId, boolean resetIfNotFound) {
- int oldStateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
- if (oldStateId == stateId) {
- mKeyMask &= (~KEYMASK_TOGGLE_STATE);
- return stateId != 0;
- }
-
- if (resetIfNotFound) {
- mKeyMask &= (~KEYMASK_TOGGLE_STATE);
- return oldStateId != 0;
- }
- return false;
- }
-
- // Clear any toggle state. If the key needs re-draw, return true.
- public boolean disableAllToggleStates() {
- int oldStateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
- mKeyMask &= (~KEYMASK_TOGGLE_STATE);
- return oldStateId != 0;
- }
-
- @Override
- public Drawable getKeyIcon() {
- ToggleState state = getToggleState();
- if (null != state) return state.mKeyIcon;
- return super.getKeyIcon();
- }
-
- @Override
- public Drawable getKeyIconPopup() {
- ToggleState state = getToggleState();
- if (null != state) {
- if (null != state.mKeyIconPopup) {
- return state.mKeyIconPopup;
- } else {
- return state.mKeyIcon;
- }
- }
- return super.getKeyIconPopup();
- }
-
- @Override
- public int getKeyCode() {
- ToggleState state = getToggleState();
- if (null != state) return state.mKeyCode;
- return mKeyCode;
- }
-
- @Override
- public String getKeyLabel() {
- ToggleState state = getToggleState();
- if (null != state) return state.mKeyLabel;
- return mKeyLabel;
- }
-
- @Override
- public Drawable getKeyBg() {
- ToggleState state = getToggleState();
- if (null != state && null != state.mKeyType) {
- return state.mKeyType.mKeyBg;
- }
- return mKeyType.mKeyBg;
- }
-
- @Override
- public Drawable getKeyHlBg() {
- ToggleState state = getToggleState();
- if (null != state && null != state.mKeyType) {
- return state.mKeyType.mKeyHlBg;
- }
- return mKeyType.mKeyHlBg;
- }
-
- @Override
- public int getColor() {
- ToggleState state = getToggleState();
- if (null != state && null != state.mKeyType) {
- return state.mKeyType.mColor;
- }
- return mKeyType.mColor;
- }
-
- @Override
- public int getColorHl() {
- ToggleState state = getToggleState();
- if (null != state && null != state.mKeyType) {
- return state.mKeyType.mColorHl;
- }
- return mKeyType.mColorHl;
- }
-
- @Override
- public int getColorBalloon() {
- ToggleState state = getToggleState();
- if (null != state && null != state.mKeyType) {
- return state.mKeyType.mColorBalloon;
- }
- return mKeyType.mColorBalloon;
- }
-
- @Override
- public boolean isKeyCodeKey() {
- ToggleState state = getToggleState();
- if (null != state) {
- if (state.mKeyCode > 0) return true;
- return false;
- }
- return super.isKeyCodeKey();
- }
-
- @Override
- public boolean isUserDefKey() {
- ToggleState state = getToggleState();
- if (null != state) {
- if (state.mKeyCode < 0) return true;
- return false;
- }
- return super.isUserDefKey();
- }
-
- @Override
- public boolean isUniStrKey() {
- ToggleState state = getToggleState();
- if (null != state) {
- if (null != state.mKeyLabel && state.mKeyCode == 0) {
- return true;
- }
- return false;
- }
- return super.isUniStrKey();
- }
-
- @Override
- public boolean needBalloon() {
- ToggleState state = getToggleState();
- if (null != state) {
- return (state.mIdAndFlags & KEYMASK_BALLOON) != 0;
- }
- return super.needBalloon();
- }
-
- @Override
- public boolean repeatable() {
- ToggleState state = getToggleState();
- if (null != state) {
- return (state.mIdAndFlags & KEYMASK_REPEAT) != 0;
- }
- return super.repeatable();
- }
-
- @Override
- public void changeCase(boolean lowerCase) {
- ToggleState state = getToggleState();
- if (null != state && null != state.mKeyLabel) {
- if (lowerCase)
- state.mKeyLabel = state.mKeyLabel.toLowerCase();
- else
- state.mKeyLabel = state.mKeyLabel.toUpperCase();
- }
- }
-
- public ToggleState createToggleState() {
- return new ToggleState();
- }
-
- public boolean setToggleStates(ToggleState rootState) {
- if (null == rootState) return false;
- mToggleState = rootState;
- return true;
- }
-
- private ToggleState getToggleState() {
- int stateId = (mKeyMask & KEYMASK_TOGGLE_STATE);
- if (0 == stateId) return null;
-
- ToggleState state = mToggleState;
- while ((null != state)
- && (state.mIdAndFlags & KEYMASK_TOGGLE_STATE) != stateId) {
- state = state.mNextState;
- }
- return state;
- }
-
- public class ToggleState {
- // The id should be bigger than 0;
- private int mIdAndFlags;
- public SoftKeyType mKeyType;
- public int mKeyCode;
- public Drawable mKeyIcon;
- public Drawable mKeyIconPopup;
- public String mKeyLabel;
- public ToggleState mNextState;
-
- public void setStateId(int stateId) {
- mIdAndFlags |= (stateId & KEYMASK_TOGGLE_STATE);
- }
-
- public void setStateFlags(boolean repeat, boolean balloon) {
- if (repeat) {
- mIdAndFlags |= KEYMASK_REPEAT;
- } else {
- mIdAndFlags &= (~KEYMASK_REPEAT);
- }
-
- if (balloon) {
- mIdAndFlags |= KEYMASK_BALLOON;
- } else {
- mIdAndFlags &= (~KEYMASK_BALLOON);
- }
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SoftKeyboard.java b/src/com/amlogic/inputmethod/remote/SoftKeyboard.java
deleted file mode 100755
index d00c365..0000000
--- a/src/com/amlogic/inputmethod/remote/SoftKeyboard.java
+++ b/dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import com.amlogic.inputmethod.remote.InputModeSwitcher.ToggleStates;
-
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.view.KeyEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class used to represent a soft keyboard definition, including the height, the
- * background image, the image for high light, the keys, etc.
- */
-public class SoftKeyboard {
- /** The XML resource id for this soft keyboard. */
- private int mSkbXmlId;
-
- /** Do we need to cache this soft keyboard? */
- private boolean mCacheFlag;
-
- /**
- * After user switches to this soft keyboard, if this flag is true, this
- * soft keyboard will be kept unless explicit switching operation is
- * performed, otherwise IME will switch back to the previous keyboard layout
- * whenever user clicks on any none-function key.
- **/
- private boolean mStickyFlag;
-
- /**
- * The cache id for this soft keyboard. It is used to identify it in the
- * soft keyboard pool.
- */
- private int mCacheId;
-
- /**
- * Used to indicate whether this soft keyboard is newly loaded from an XML
- * file or is just gotten from the soft keyboard pool.
- */
- private boolean mNewlyLoadedFlag = true;
-
- /** The width of the soft keyboard. */
- private int mSkbCoreWidth;
-
- /** The height of the soft keyboard. */
- private int mSkbCoreHeight;
-
- /** The soft keyboard template for this soft keyboard. */
- private SkbTemplate mSkbTemplate;
-
- /** Used to indicate whether this soft keyboard is a QWERTY keyboard. */
- private boolean mIsQwerty;
-
- /**
- * When {@link #mIsQwerty} is true, this member is Used to indicate that the
- * soft keyboard should be displayed in uppercase.
- */
- private boolean mIsQwertyUpperCase;
-
- /**
- * The id of the rows which are enabled. Rows with id
- * {@link KeyRow#ALWAYS_SHOW_ROW_ID} are always enabled.
- */
- private int mEnabledRowId;
-
- /**
- * Rows in this soft keyboard. Each row has a id. Only matched rows will be
- * enabled.
- */
- private List<KeyRow> mKeyRows;
-
- /**
- * Background of the soft keyboard. If it is null, the one in the soft
- * keyboard template will be used.
- **/
- public Drawable mSkbBg;
-
- /**
- * Background for key balloon. If it is null, the one in the soft keyboard
- * template will be used.
- **/
- private Drawable mBalloonBg;
-
- /**
- * Background for popup mini soft keyboard. If it is null, the one in the
- * soft keyboard template will be used.
- **/
- private Drawable mPopupBg;
-
- /** The left and right margin of a key. */
- private float mKeyXMargin = 0;
-
- /** The top and bottom margin of a key. */
- private float mKeyYMargin = 0;
-
- private Rect mTmpRect = new Rect();
-
- public SoftKeyboard(int skbXmlId, SkbTemplate skbTemplate, int skbWidth,
- int skbHeight) {
- mSkbXmlId = skbXmlId;
- mSkbTemplate = skbTemplate;
- mSkbCoreWidth = skbWidth;
- mSkbCoreHeight = skbHeight;
- }
-
- public void setFlags(boolean cacheFlag, boolean stickyFlag,
- boolean isQwerty, boolean isQwertyUpperCase) {
- mCacheFlag = cacheFlag;
- mStickyFlag = stickyFlag;
- mIsQwerty = isQwerty;
- mIsQwertyUpperCase = isQwertyUpperCase;
- }
-
- public boolean getCacheFlag() {
- return mCacheFlag;
- }
-
- public void setCacheId(int cacheId) {
- mCacheId = cacheId;
- }
-
- public boolean getStickyFlag() {
- return mStickyFlag;
- }
-
- public void setSkbBackground(Drawable skbBg) {
- mSkbBg = skbBg;
- }
-
- public void setPopupBackground(Drawable popupBg) {
- mPopupBg = popupBg;
- }
-
- public void setKeyBalloonBackground(Drawable balloonBg) {
- mBalloonBg = balloonBg;
- }
-
- public void setKeyMargins(float xMargin, float yMargin) {
- mKeyXMargin = xMargin;
- mKeyYMargin = yMargin;
- }
-
- public int getCacheId() {
- return mCacheId;
- }
-
- public void reset() {
- if (null != mKeyRows) mKeyRows.clear();
- }
-
- public void setNewlyLoadedFlag(boolean newlyLoadedFlag) {
- mNewlyLoadedFlag = newlyLoadedFlag;
- }
-
- public boolean getNewlyLoadedFlag() {
- return mNewlyLoadedFlag;
- }
-
- public void beginNewRow(int rowId, float yStartingPos) {
- if (null == mKeyRows) mKeyRows = new ArrayList<KeyRow>();
- KeyRow keyRow = new KeyRow();
- keyRow.mRowId = rowId;
- keyRow.mTopF = yStartingPos;
- keyRow.mBottomF = yStartingPos;
- keyRow.mSoftKeys = new ArrayList<SoftKey>();
- mKeyRows.add(keyRow);
- }
-
- public boolean addSoftKey(SoftKey softKey) {
- if (mKeyRows.size() == 0) return false;
- KeyRow keyRow = mKeyRows.get(mKeyRows.size() - 1);
- if (null == keyRow) return false;
- List<SoftKey> softKeys = keyRow.mSoftKeys;
-
- softKey.setSkbCoreSize(mSkbCoreWidth, mSkbCoreHeight);
- softKeys.add(softKey);
- softKey.setKeyPos(mKeyRows.size()-1, softKeys.size()-1);
- if (softKey.mTopF < keyRow.mTopF) {
- keyRow.mTopF = softKey.mTopF;
- }
- if (softKey.mBottomF > keyRow.mBottomF) {
- keyRow.mBottomF = softKey.mBottomF;
- }
- return true;
- }
-
- public int getSkbXmlId() {
- return mSkbXmlId;
- }
-
- // Set the size of the soft keyboard core. In other words, the background's
- // padding are not counted.
- public void setSkbCoreSize(int skbCoreWidth, int skbCoreHeight) {
- if (null == mKeyRows
- || (skbCoreWidth == mSkbCoreWidth && skbCoreHeight == mSkbCoreHeight)) {
- return;
- }
- for (int row = 0; row < mKeyRows.size(); row++) {
- KeyRow keyRow = mKeyRows.get(row);
- keyRow.mBottom = (int) (skbCoreHeight * keyRow.mBottomF);
- keyRow.mTop = (int) (skbCoreHeight * keyRow.mTopF);
-
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- for (int i = 0; i < softKeys.size(); i++) {
- SoftKey softKey = softKeys.get(i);
- softKey.setSkbCoreSize(skbCoreWidth, skbCoreHeight);
- }
- }
- mSkbCoreWidth = skbCoreWidth;
- mSkbCoreHeight = skbCoreHeight;
- }
-
- public int getSkbCoreWidth() {
- return mSkbCoreWidth;
- }
-
- public int getSkbCoreHeight() {
- return mSkbCoreHeight;
- }
-
- public int getSkbTotalWidth() {
- Rect padding = getPadding();
- return mSkbCoreWidth + padding.left + padding.right;
- }
-
- public int getSkbTotalHeight() {
- Rect padding = getPadding();
- return mSkbCoreHeight + padding.top + padding.bottom;
- }
-
- public int getKeyXMargin() {
- Environment env = Environment.getInstance();
- return (int) (mKeyXMargin * mSkbCoreWidth * env.getKeyXMarginFactor());
- }
-
- public int getKeyYMargin() {
- Environment env = Environment.getInstance();
- return (int) (mKeyYMargin * mSkbCoreHeight * env.getKeyYMarginFactor());
- }
-
- public Drawable getSkbBackground() {
- if (null != mSkbBg) return mSkbBg;
- return mSkbTemplate.getSkbBackground();
- }
-
- public Drawable getBalloonBackground() {
- if (null != mBalloonBg) return mBalloonBg;
- return mSkbTemplate.getBalloonBackground();
- }
-
- public Drawable getPopupBackground() {
- if (null != mPopupBg) return mPopupBg;
- return mSkbTemplate.getPopupBackground();
- }
-
- public int getRowNum() {
- if (null != mKeyRows) {
- return mKeyRows.size();
- }
- return 0;
- }
-
- public int getLocNum(int row) {
- if (null == mKeyRows)
- return 0;
-
- if (mKeyRows.size() <= row)
- row = mKeyRows.size() - 1;
- else if (row < 0)
- row = 0;
-
- List<SoftKey> softKeys = mKeyRows.get(row).mSoftKeys;
- return softKeys.size();
- }
-
- public KeyRow getKeyRowForDisplay(int row) {
- if (null != mKeyRows && mKeyRows.size() > row) {
- KeyRow keyRow = mKeyRows.get(row);
- if (KeyRow.ALWAYS_SHOW_ROW_ID == keyRow.mRowId
- || keyRow.mRowId == mEnabledRowId) {
- return keyRow;
- }
- }
- return null;
- }
-
- public SoftKey getKey(int row, int location) {
- if (null != mKeyRows) {
- if(mKeyRows.size() <= row)
- row = mKeyRows.size()-1;
- else if(row < 0)
- row = 0;
-
- List<SoftKey> softKeys = mKeyRows.get(row).mSoftKeys;
- if(location < 0)
- location = softKeys.size()-1;
- if (softKeys.size() > location) {
- return softKeys.get(location);
- }
- }
- return null;
- }
-
- public SoftKey mapToKey(int x, int y) {
- if (null == mKeyRows) {
- return null;
- }
- // If the position is inside the rectangle of a certain key, return that
- // key.
- int rowNum = mKeyRows.size();
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mKeyRows.get(row);
- if (KeyRow.ALWAYS_SHOW_ROW_ID != keyRow.mRowId
- && keyRow.mRowId != mEnabledRowId) continue;
- if (keyRow.mTop > y && keyRow.mBottom <= y) continue;
-
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int i = 0; i < keyNum; i++) {
- SoftKey sKey = softKeys.get(i);
- if (sKey.mLeft <= x && sKey.mTop <= y && sKey.mRight > x
- && sKey.mBottom > y) {
- return sKey;
- }
- }
- }
-
- // If the position is outside the rectangles of all keys, find the
- // nearest one.
- SoftKey nearestKey = null;
- float nearestDis = Float.MAX_VALUE;
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mKeyRows.get(row);
- if (KeyRow.ALWAYS_SHOW_ROW_ID != keyRow.mRowId
- && keyRow.mRowId != mEnabledRowId) continue;
- if (keyRow.mTop > y && keyRow.mBottom <= y) continue;
-
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int i = 0; i < keyNum; i++) {
- SoftKey sKey = softKeys.get(i);
- int disx = (sKey.mLeft + sKey.mRight) / 2 - x;
- int disy = (sKey.mTop + sKey.mBottom) / 2 - y;
- float dis = disx * disx + disy * disy;
- if (dis < nearestDis) {
- nearestDis = dis;
- nearestKey = sKey;
- }
- }
- }
- return nearestKey;
- }
-
- public void switchQwertyMode(int toggle_state_id, boolean upperCase) {
- if (!mIsQwerty) return;
-
- int rowNum = mKeyRows.size();
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mKeyRows.get(row);
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int i = 0; i < keyNum; i++) {
- SoftKey sKey = softKeys.get(i);
- if (sKey instanceof SoftKeyToggle) {
- ((SoftKeyToggle) sKey).enableToggleState(toggle_state_id,
- true);
- }
- if (sKey.mKeyCode >= KeyEvent.KEYCODE_A
- && sKey.mKeyCode <= KeyEvent.KEYCODE_Z) {
- sKey.changeCase(upperCase);
- }
- }
- }
- }
-
- public void enableToggleState(int toggleStateId, boolean resetIfNotFound) {
- int rowNum = mKeyRows.size();
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mKeyRows.get(row);
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int i = 0; i < keyNum; i++) {
- SoftKey sKey = softKeys.get(i);
- if (sKey instanceof SoftKeyToggle) {
- ((SoftKeyToggle) sKey).enableToggleState(toggleStateId,
- resetIfNotFound);
- }
- }
- }
- }
-
- public void disableToggleState(int toggleStateId, boolean resetIfNotFound) {
- int rowNum = mKeyRows.size();
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mKeyRows.get(row);
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int i = 0; i < keyNum; i++) {
- SoftKey sKey = softKeys.get(i);
- if (sKey instanceof SoftKeyToggle) {
- ((SoftKeyToggle) sKey).disableToggleState(toggleStateId,
- resetIfNotFound);
- }
- }
- }
- }
-
- public void enableToggleStates(ToggleStates toggleStates) {
- if (null == toggleStates) return;
-
- enableRow(toggleStates.mRowIdToEnable);
-
- boolean isQwerty = toggleStates.mQwerty;
- boolean isQwertyUpperCase = toggleStates.mQwertyUpperCase;
- boolean needUpdateQwerty = (isQwerty && mIsQwerty && (mIsQwertyUpperCase != isQwertyUpperCase));
- int states[] = toggleStates.mKeyStates;
- int statesNum = toggleStates.mKeyStatesNum;
-
- int rowNum = mKeyRows.size();
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mKeyRows.get(row);
- if (KeyRow.ALWAYS_SHOW_ROW_ID != keyRow.mRowId
- && keyRow.mRowId != mEnabledRowId) {
- continue;
- }
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int keyPos = 0; keyPos < keyNum; keyPos++) {
- SoftKey sKey = softKeys.get(keyPos);
- if (sKey instanceof SoftKeyToggle) {
- for (int statePos = 0; statePos < statesNum; statePos++) {
- ((SoftKeyToggle) sKey).enableToggleState(
- states[statePos], statePos == 0);
- }
- if (0 == statesNum) {
- ((SoftKeyToggle) sKey).disableAllToggleStates();
- }
- }
- if (needUpdateQwerty) {
- if (sKey.mKeyCode >= KeyEvent.KEYCODE_A
- && sKey.mKeyCode <= KeyEvent.KEYCODE_Z) {
- sKey.changeCase(isQwertyUpperCase);
- }
- }
- }
- }
- mIsQwertyUpperCase = isQwertyUpperCase;
- }
-
- private Rect getPadding() {
- mTmpRect.set(0, 0, 0, 0);
- Drawable skbBg = getSkbBackground();
- if (null == skbBg) return mTmpRect;
- skbBg.getPadding(mTmpRect);
- return mTmpRect;
- }
-
- /**
- * Enable a row with the give toggle Id. Rows with other toggle ids (except
- * the id {@link KeyRow#ALWAYS_SHOW_ROW_ID}) will be disabled.
- *
- * @param rowId The row id to enable.
- * @return True if the soft keyboard requires redrawing.
- */
- private boolean enableRow(int rowId) {
- if (KeyRow.ALWAYS_SHOW_ROW_ID == rowId) return false;
-
- boolean enabled = false;
- int rowNum = mKeyRows.size();
- for (int row = rowNum - 1; row >= 0; row--) {
- if (mKeyRows.get(row).mRowId == rowId) {
- enabled = true;
- break;
- }
- }
- if (enabled) {
- mEnabledRowId = rowId;
- }
- return enabled;
- }
-
- @Override
- public String toString() {
- String str = "------------------SkbInfo----------------------\n";
- String endStr = "-----------------------------------------------\n";
- str += "Width: " + String.valueOf(mSkbCoreWidth) + "\n";
- str += "Height: " + String.valueOf(mSkbCoreHeight) + "\n";
- str += "KeyRowNum: " + mKeyRows == null ? "0" : String.valueOf(mKeyRows
- .size())
- + "\n";
- if (null == mKeyRows) return str + endStr;
- int rowNum = mKeyRows.size();
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mKeyRows.get(row);
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int i = 0; i < softKeys.size(); i++) {
- str += "-key " + String.valueOf(i) + ":"
- + softKeys.get(i).toString();
- }
- }
- return str + endStr;
- }
-
- public String toShortString() {
- return super.toString();
- }
-
- class KeyRow {
- static final int ALWAYS_SHOW_ROW_ID = -1;
- static final int DEFAULT_ROW_ID = 0;
-
- List<SoftKey> mSoftKeys;
- /**
- * If the row id is {@link #ALWAYS_SHOW_ROW_ID}, this row will always be
- * enabled.
- */
- int mRowId;
- float mTopF;
- float mBottomF;
- int mTop;
- int mBottom;
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SoftKeyboardView.java b/src/com/amlogic/inputmethod/remote/SoftKeyboardView.java
deleted file mode 100755
index 36f5e05..0000000
--- a/src/com/amlogic/inputmethod/remote/SoftKeyboardView.java
+++ b/dev/null
@@ -1,495 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import com.amlogic.inputmethod.remote.SoftKeyboard.KeyRow;
-
-import java.util.List;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.drawable.Drawable;
-/*import android.os.Vibrator;*/
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * Class used to show a soft keyboard.
- *
- * A soft keyboard view should not handle touch event itself, because we do bias
- * correction, need a global strategy to map an event into a proper view to
- * achieve better user experience.
- */
-public class SoftKeyboardView extends View {
- /**
- * The definition of the soft keyboard for the current this soft keyboard
- * view.
- */
- private SoftKeyboard mSoftKeyboard;
-
- /**
- * The popup balloon hint for key press/release.
- */
- private BalloonHint mBalloonPopup;
-
- /**
- * The on-key balloon hint for key press/release. If it is null, on-key
- * highlight will be drawn on th soft keyboard view directly.
- */
- private BalloonHint mBalloonOnKey;
-
- /** Used to play key sounds. */
- private SoundManager mSoundManager;
-
- /** The last key pressed. */
- private SoftKey mSoftKeyDown;
-
- /** Used to indicate whether the user is holding on a key. */
- private boolean mKeyPressed = false;
-
- /**
- * The location offset of the view to the keyboard container.
- */
- private int mOffsetToSkbContainer[] = new int[2];
-
- /**
- * The location of the desired hint view to the keyboard container.
- */
- private int mHintLocationToSkbContainer[] = new int[2];
-
- /**
- * Text size for normal key.
- */
- private int mNormalKeyTextSize;
-
- /**
- * Text size for function key.
- */
- private int mFunctionKeyTextSize;
-
- /**
- * Long press timer used to response long-press.
- */
- private SkbContainer.LongPressTimer mLongPressTimer;
-
- /**
- * Repeated events for long press
- */
- private boolean mRepeatForLongPress = false;
-
- /**
- * If this parameter is true, the balloon will never be dismissed even if
- * user moves a lot from the pressed point.
- */
- private boolean mMovingNeverHidePopupBalloon = false;
-
- /** Vibration for key press. */
- private Vibrator mVibrator;
-
- /** Vibration pattern for key press. */
- protected long[] mVibratePattern = new long[] {1, 20};
-
- /**
- * The dirty rectangle used to mark the area to re-draw during key press and
- * release. Currently, whenever we can invalidate(Rect), view will call
- * onDraw() and we MUST draw the whole view. This dirty information is for
- * future use.
- */
- private Rect mDirtyRect = new Rect();
-
- private Paint mPaint;
- private FontMetricsInt mFmi;
- private boolean mDimSkb;
-
- /** Add by lyra:The last key pressed. */
- public SoftKey mSoftKeyFocus;
-
- public SoftKeyboardView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mSoundManager = SoundManager.getInstance(mContext);
-
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mFmi = mPaint.getFontMetricsInt();
- }
-
- public boolean setSoftKeyboard(SoftKeyboard softSkb) {
- if (null == softSkb) {
- return false;
- }
- mSoftKeyboard = softSkb;
- Drawable bg = softSkb.getSkbBackground();
- if (null != bg) setBackgroundDrawable(bg);
- return true;
- }
-
- public SoftKeyboard getSoftKeyboard() {
- return mSoftKeyboard;
- }
-
- public void resizeKeyboard(int skbWidth, int skbHeight) {
- mSoftKeyboard.setSkbCoreSize(skbWidth, skbHeight);
- }
-
- public void setBalloonHint(BalloonHint balloonOnKey,
- BalloonHint balloonPopup, boolean movingNeverHidePopup) {
- mBalloonOnKey = balloonOnKey;
- mBalloonPopup = balloonPopup;
- mMovingNeverHidePopupBalloon = movingNeverHidePopup;
- }
-
- public void setOffsetToSkbContainer(int offsetToSkbContainer[]) {
- mOffsetToSkbContainer[0] = offsetToSkbContainer[0];
- mOffsetToSkbContainer[1] = offsetToSkbContainer[1];
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int measuredWidth = 0;
- int measuredHeight = 0;
- if (null != mSoftKeyboard) {
- measuredWidth = mSoftKeyboard.getSkbCoreWidth();
- measuredHeight = mSoftKeyboard.getSkbCoreHeight();
- measuredWidth += mPaddingLeft + mPaddingRight;
- measuredHeight += mPaddingTop + mPaddingBottom;
- }
- setMeasuredDimension(measuredWidth, measuredHeight);
- }
-
- private void showBalloon(BalloonHint balloon, int balloonLocationToSkb[],
- boolean movePress) {
- long delay = BalloonHint.TIME_DELAY_SHOW;
- if (movePress) delay = 0;
- if (balloon.needForceDismiss()) {
- balloon.delayedDismiss(0);
- }
- if (!balloon.isShowing()) {
- balloon.delayedShow(delay, balloonLocationToSkb);
- } else {
- balloon.delayedUpdate(delay, balloonLocationToSkb, balloon
- .getWidth(), balloon.getHeight());
- }
- long b = System.currentTimeMillis();
- }
-
- public void resetKeyPress(long balloonDelay) {
- if (!mKeyPressed) return;
- mKeyPressed = false;
- if (null != mBalloonOnKey) {
- mBalloonOnKey.delayedDismiss(balloonDelay);
- } else {
- if (null != mSoftKeyDown) {
- if (mDirtyRect.isEmpty()) {
- mDirtyRect.set(mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
- mSoftKeyDown.mRight, mSoftKeyDown.mBottom);
- }
- invalidate(mDirtyRect);
- } else {
- invalidate();
- }
- }
- mBalloonPopup.delayedDismiss(balloonDelay);
- }
-
- // If movePress is true, means that this function is called because user
- // moves his finger to this button. If movePress is false, means that this
- // function is called when user just presses this key.
- public SoftKey onKeyPress(int x, int y,
- SkbContainer.LongPressTimer longPressTimer, boolean movePress) {
- mKeyPressed = false;
- boolean moveWithinPreviousKey = false;
- if (movePress) {
- SoftKey newKey = mSoftKeyboard.mapToKey(x, y);
- if (newKey == mSoftKeyDown) moveWithinPreviousKey = true;
- mSoftKeyDown = newKey;
- } else {
- mSoftKeyDown = mSoftKeyboard.mapToKey(x, y);
- }
- if (moveWithinPreviousKey || null == mSoftKeyDown) return mSoftKeyDown;
- mKeyPressed = true;
-
- if (!movePress) {
- tryPlayKeyDown();
- tryVibrate();
- }
-
- mLongPressTimer = longPressTimer;
-
- if (!movePress) {
- if (mSoftKeyDown.getPopupResId() > 0 || mSoftKeyDown.repeatable()) {
- mLongPressTimer.startTimer();
- }
- } else {
- mLongPressTimer.removeTimer();
- }
-
- int desired_width;
- int desired_height;
- float textSize;
- Environment env = Environment.getInstance();
-
- if (null != mBalloonOnKey) {
- Drawable keyHlBg = mSoftKeyDown.getKeyHlBg();
- mBalloonOnKey.setBalloonBackground(keyHlBg);
-
- // Prepare the on-key balloon
- int keyXMargin = mSoftKeyboard.getKeyXMargin();
- int keyYMargin = mSoftKeyboard.getKeyYMargin();
- desired_width = mSoftKeyDown.width() - 2 * keyXMargin;
- desired_height = mSoftKeyDown.height() - 2 * keyYMargin;
- textSize = env
- .getKeyTextSize(SoftKeyType.KEYTYPE_ID_NORMAL_KEY != mSoftKeyDown.mKeyType.mKeyTypeId);
- Drawable icon = mSoftKeyDown.getKeyIcon();
- if (null != icon) {
- mBalloonOnKey.setBalloonConfig(icon, desired_width,
- desired_height);
- } else {
- mBalloonOnKey.setBalloonConfig(mSoftKeyDown.getKeyLabel(),
- textSize, true, mSoftKeyDown.getColorHl(),
- desired_width, desired_height);
- }
-
- mHintLocationToSkbContainer[0] = mPaddingLeft + mSoftKeyDown.mLeft
- - (mBalloonOnKey.getWidth() - mSoftKeyDown.width()) / 2;
- mHintLocationToSkbContainer[0] += mOffsetToSkbContainer[0];
- mHintLocationToSkbContainer[1] = mPaddingTop
- + (mSoftKeyDown.mBottom - keyYMargin)
- - mBalloonOnKey.getHeight();
- mHintLocationToSkbContainer[1] += mOffsetToSkbContainer[1];
- showBalloon(mBalloonOnKey, mHintLocationToSkbContainer, movePress);
- } else {
- mDirtyRect.union(mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
- mSoftKeyDown.mRight, mSoftKeyDown.mBottom);
- invalidate(mDirtyRect);
- }
-
- // Prepare the popup balloon
- if (mSoftKeyDown.needBalloon()) {
- Drawable balloonBg = mSoftKeyboard.getBalloonBackground();
- mBalloonPopup.setBalloonBackground(balloonBg);
-
- desired_width = mSoftKeyDown.width() + env.getKeyBalloonWidthPlus();
- desired_height = mSoftKeyDown.height()
- + env.getKeyBalloonHeightPlus();
- textSize = env
- .getBalloonTextSize(SoftKeyType.KEYTYPE_ID_NORMAL_KEY != mSoftKeyDown.mKeyType.mKeyTypeId);
- Drawable iconPopup = mSoftKeyDown.getKeyIconPopup();
- if (null != iconPopup) {
- mBalloonPopup.setBalloonConfig(iconPopup, desired_width,
- desired_height);
- } else {
- mBalloonPopup.setBalloonConfig(mSoftKeyDown.getKeyLabel(),
- textSize, mSoftKeyDown.needBalloon(), mSoftKeyDown
- .getColorBalloon(), desired_width,
- desired_height);
- }
-
- // The position to show.
- mHintLocationToSkbContainer[0] = mPaddingLeft + mSoftKeyDown.mLeft
- + -(mBalloonPopup.getWidth() - mSoftKeyDown.width()) / 2;
- mHintLocationToSkbContainer[0] += mOffsetToSkbContainer[0];
- mHintLocationToSkbContainer[1] = mPaddingTop + mSoftKeyDown.mTop
- - mBalloonPopup.getHeight();
- mHintLocationToSkbContainer[1] += mOffsetToSkbContainer[1];
- showBalloon(mBalloonPopup, mHintLocationToSkbContainer, movePress);
- } else {
- mBalloonPopup.delayedDismiss(0);
- }
-
- if (mRepeatForLongPress) longPressTimer.startTimer();
- return mSoftKeyDown;
- }
-
- public SoftKey onKeyRelease(int x, int y) {
- mKeyPressed = false;
- if (null == mSoftKeyDown) return null;
-
- mLongPressTimer.removeTimer();
-
- if (null != mBalloonOnKey) {
- mBalloonOnKey.delayedDismiss(BalloonHint.TIME_DELAY_DISMISS);
- } else {
- mDirtyRect.union(mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
- mSoftKeyDown.mRight, mSoftKeyDown.mBottom);
- invalidate(mDirtyRect);
- }
-
- if (mSoftKeyDown.needBalloon()) {
- mBalloonPopup.delayedDismiss(BalloonHint.TIME_DELAY_DISMISS);
- }
-
- if (mSoftKeyDown.moveWithinKey(x - mPaddingLeft, y - mPaddingTop)) {
- return mSoftKeyDown;
- }
- return null;
- }
-
- public SoftKey onKeyMove(int x, int y) {
- if (null == mSoftKeyDown) return null;
-
- if (mSoftKeyDown.moveWithinKey(x - mPaddingLeft, y - mPaddingTop)) {
- return mSoftKeyDown;
- }
-
- // The current key needs to be updated.
- mDirtyRect.union(mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
- mSoftKeyDown.mRight, mSoftKeyDown.mBottom);
-
- if (mRepeatForLongPress) {
- if (mMovingNeverHidePopupBalloon) {
- return onKeyPress(x, y, mLongPressTimer, true);
- }
-
- if (null != mBalloonOnKey) {
- mBalloonOnKey.delayedDismiss(0);
- } else {
- invalidate(mDirtyRect);
- }
-
- if (mSoftKeyDown.needBalloon()) {
- mBalloonPopup.delayedDismiss(0);
- }
-
- if (null != mLongPressTimer) {
- mLongPressTimer.removeTimer();
- }
- return onKeyPress(x, y, mLongPressTimer, true);
- } else {
- // When user moves between keys, repeated response is disabled.
- return onKeyPress(x, y, mLongPressTimer, true);
- }
- }
-
- private void tryVibrate() {
- if (!Settings.getVibrate()) {
- return;
- }
- if (mVibrator == null) {
- mVibrator = new Vibrator();
- }
- mVibrator.vibrate(mVibratePattern, -1);
- }
-
- private void tryPlayKeyDown() {
- if (Settings.getKeySound()) {
- mSoundManager.playKeyDown();
- }
- }
-
- public void dimSoftKeyboard(boolean dimSkb) {
- mDimSkb = dimSkb;
- invalidate();
- }
-
- public void changeFocusKey(SoftKey key)
- {
- if(mSoftKeyFocus != key)
- {
- mSoftKeyFocus = key;
- invalidate();
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (null == mSoftKeyboard) return;
-
- canvas.translate(mPaddingLeft, mPaddingTop);
-
- Environment env = Environment.getInstance();
- mNormalKeyTextSize = env.getKeyTextSize(false);
- mFunctionKeyTextSize = env.getKeyTextSize(true);
- // Draw the last soft keyboard
- int rowNum = mSoftKeyboard.getRowNum();
- int keyXMargin = mSoftKeyboard.getKeyXMargin();
- int keyYMargin = mSoftKeyboard.getKeyYMargin();
- for (int row = 0; row < rowNum; row++) {
- KeyRow keyRow = mSoftKeyboard.getKeyRowForDisplay(row);
- if (null == keyRow) continue;
- List<SoftKey> softKeys = keyRow.mSoftKeys;
- int keyNum = softKeys.size();
- for (int i = 0; i < keyNum; i++) {
- SoftKey softKey = softKeys.get(i);
- if (SoftKeyType.KEYTYPE_ID_NORMAL_KEY == softKey.mKeyType.mKeyTypeId) {
- mPaint.setTextSize(mNormalKeyTextSize);
- } else {
- mPaint.setTextSize(mFunctionKeyTextSize);
- }
- drawSoftKey(canvas, softKey, keyXMargin, keyYMargin);
- }
- }
-
- if (mDimSkb) {
- mPaint.setColor(0xa0000000);
- canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
- }
-
- mDirtyRect.setEmpty();
- }
-
- private void drawSoftKey(Canvas canvas, SoftKey softKey, int keyXMargin,
- int keyYMargin) {
- Drawable bg;
- int textColor;
- if (mKeyPressed && softKey == mSoftKeyDown) {
- bg = softKey.getKeyHlBg();
- textColor = softKey.getColorHl();
- }
- //add focus key
- else if (softKey == mSoftKeyFocus) {
- bg = softKey.getKeyHlBg();
- textColor = softKey.getColor();
- } else {
- bg = softKey.getKeyBg();
- textColor = softKey.getColor();
- }
-
- if (null != bg) {
- bg.setBounds(softKey.mLeft + keyXMargin, softKey.mTop + keyYMargin,
- softKey.mRight - keyXMargin, softKey.mBottom - keyYMargin);
- bg.draw(canvas);
- }
-
- String keyLabel = softKey.getKeyLabel();
- Drawable keyIcon = softKey.getKeyIcon();
- if (null != keyIcon) {
- Drawable icon = keyIcon;
- int marginLeft = (softKey.width() - icon.getIntrinsicWidth()) / 2;
- int marginRight = softKey.width() - icon.getIntrinsicWidth()
- - marginLeft;
- int marginTop = (softKey.height() - icon.getIntrinsicHeight()) / 2;
- int marginBottom = softKey.height() - icon.getIntrinsicHeight()
- - marginTop;
- icon.setBounds(softKey.mLeft + marginLeft,
- softKey.mTop + marginTop, softKey.mRight - marginRight,
- softKey.mBottom - marginBottom);
- icon.draw(canvas);
- } else if (null != keyLabel) {
- mPaint.setColor(textColor);
- float x = softKey.mLeft
- + (softKey.width() - mPaint.measureText(keyLabel)) / 2.0f;
- int fontHeight = mFmi.bottom - mFmi.top;
- float marginY = (softKey.height() - fontHeight) / 2.0f;
- float y = softKey.mTop + marginY - mFmi.top + mFmi.bottom / 1.5f;
- canvas.drawText(keyLabel, x, y + 1, mPaint);
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/SoundManager.java b/src/com/amlogic/inputmethod/remote/SoundManager.java
deleted file mode 100755
index 200d242..0000000
--- a/src/com/amlogic/inputmethod/remote/SoundManager.java
+++ b/dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.content.Context;
-import android.media.AudioManager;
-
-/**
- * Class used to manage related sound resources.
- */
-public class SoundManager {
- private static SoundManager mInstance = null;
- private Context mContext;
- private AudioManager mAudioManager;
- // Align sound effect volume on music volume
- private final float FX_VOLUME = -1.0f;
- private boolean mSilentMode;
-
- private SoundManager(Context context) {
- mContext = context;
- updateRingerMode();
- }
-
- public void updateRingerMode() {
- if (mAudioManager == null) {
- mAudioManager = (AudioManager) mContext
- .getSystemService(Context.AUDIO_SERVICE);
- }
- mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
- }
-
- public static SoundManager getInstance(Context context) {
- if (null == mInstance) {
- if (null != context) {
- mInstance = new SoundManager(context);
- }
- }
- return mInstance;
- }
-
- public void playKeyDown() {
- if (mAudioManager == null) {
- updateRingerMode();
- }
- if (!mSilentMode) {
- int sound = AudioManager.FX_KEYPRESS_STANDARD;
- mAudioManager.playSoundEffect(sound, FX_VOLUME);
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/Vibrator.java b/src/com/amlogic/inputmethod/remote/Vibrator.java
deleted file mode 100755
index 2066ff3..0000000
--- a/src/com/amlogic/inputmethod/remote/Vibrator.java
+++ b/dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import android.util.Log;
-import android.os.IVibratorService;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-/**
- * Class that operates the vibrator on the device.
- * <p>
- * If your process exits, any vibration you started with will stop.
- * </p>
- */
-public class Vibrator
-{
- private static final String TAG = "Vibrator";
-
- IVibratorService mService;
- private final Binder mToken = new Binder();
-
- /** @hide */
- public Vibrator()
- {
- mService = IVibratorService.Stub.asInterface(
- ServiceManager.getService("vibrator"));
- }
-
- /**
- * Check whether the hardware has a vibrator. Returns true if a vibrator
- * exists, else false.
- */
- public boolean hasVibrator() {
- if (mService == null) {
- Log.w(TAG, "Failed to vibrate; no vibrator service.");
- return false;
- }
- try {
- return mService.hasVibrator();
- } catch (RemoteException e) {
- }
- return false;
- }
-
- /**
- * Turn the vibrator on.
- *
- * @param milliseconds The number of milliseconds to vibrate.
- */
- public void vibrate(long milliseconds)
- {
- if (mService == null) {
- Log.w(TAG, "Failed to vibrate; no vibrator service.");
- return;
- }
- /*
- try {
- mService.vibrate(milliseconds, mToken);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to vibrate.", e);
- }*/
- }
-
- /**
- * Vibrate with a given pattern.
- *
- * <p>
- * Pass in an array of ints that are the durations for which to turn on or off
- * the vibrator in milliseconds. The first value indicates the number of milliseconds
- * to wait before turning the vibrator on. The next value indicates the number of milliseconds
- * for which to keep the vibrator on before turning it off. Subsequent values alternate
- * between durations in milliseconds to turn the vibrator off or to turn the vibrator on.
- * </p><p>
- * To cause the pattern to repeat, pass the index into the pattern array at which
- * to start the repeat, or -1 to disable repeating.
- * </p>
- *
- * @param pattern an array of longs of times for which to turn the vibrator on or off.
- * @param repeat the index into pattern at which to repeat, or -1 if
- * you don't want to repeat.
- */
- public void vibrate(long[] pattern, int repeat)
- {
- if (mService == null) {
- Log.w(TAG, "Failed to vibrate; no vibrator service.");
- return;
- }
- // catch this here because the server will do nothing. pattern may
- // not be null, let that be checked, because the server will drop it
- // anyway
- if (repeat < pattern.length) {
- /*
- try {
- mService.vibratePattern(pattern, repeat, mToken);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to vibrate.", e);
- }*/
- } else {
- throw new ArrayIndexOutOfBoundsException();
- }
- }
-
- /**
- * Turn the vibrator off.
- */
- public void cancel()
- {
- if (mService == null) {
- return;
- }
- try {
- mService.cancelVibrate(mToken);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to cancel vibration.", e);
- }
- }
-}
diff --git a/src/com/amlogic/inputmethod/remote/XmlKeyboardLoader.java b/src/com/amlogic/inputmethod/remote/XmlKeyboardLoader.java
deleted file mode 100755
index ab89efe..0000000
--- a/src/com/amlogic/inputmethod/remote/XmlKeyboardLoader.java
+++ b/dev/null
@@ -1,835 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amlogic.inputmethod.remote;
-
-import com.amlogic.inputmethod.remote.SoftKeyboard.KeyRow;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
-
-import java.io.IOException;
-import java.util.regex.Pattern;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-/**
- * Class used to load a soft keyboard or a soft keyboard template from xml
- * files.
- */
-public class XmlKeyboardLoader {
- /**
- * The tag used to define an xml-based soft keyboard template.
- */
- private static final String XMLTAG_SKB_TEMPLATE = "skb_template";
-
- /**
- * The tag used to indicate the soft key type which is defined inside the
- * {@link #XMLTAG_SKB_TEMPLATE} element in the xml file. file.
- */
- private static final String XMLTAG_KEYTYPE = "key_type";
-
- /**
- * The tag used to define a default key icon for enter/delete/space keys. It
- * is defined inside the {@link #XMLTAG_SKB_TEMPLATE} element in the xml
- * file.
- */
- private static final String XMLTAG_KEYICON = "key_icon";
-
- /**
- * Attribute tag of the left and right margin for a key. A key's width
- * should be larger than double of this value. Defined inside
- * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
- */
- private static final String XMLATTR_KEY_XMARGIN = "key_xmargin";
-
- /**
- * Attribute tag of the top and bottom margin for a key. A key's height
- * should be larger than double of this value. Defined inside
- * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
- */
- private static final String XMLATTR_KEY_YMARGIN = "key_ymargin";
-
- /**
- * Attribute tag of the keyboard background image. Defined inside
- * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
- */
- private static final String XMLATTR_SKB_BG = "skb_bg";
-
- /**
- * Attribute tag of the balloon background image for key press. Defined
- * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
- */
- private static final String XMLATTR_BALLOON_BG = "balloon_bg";
-
- /**
- * Attribute tag of the popup balloon background image for key press or
- * popup mini keyboard. Defined inside {@link #XMLTAG_SKB_TEMPLATE} and
- * {@link #XMLTAG_KEYBOARD}.
- */
- private static final String XMLATTR_POPUP_BG = "popup_bg";
-
- /**
- * Attribute tag of the color to draw key label. Defined inside
- * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
- */
- private static final String XMLATTR_COLOR = "color";
-
- /**
- * Attribute tag of the color to draw key's highlighted label. Defined
- * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
- */
- private static final String XMLATTR_COLOR_HIGHLIGHT = "color_highlight";
-
- /**
- * Attribute tag of the color to draw key's label in the popup balloon.
- * Defined inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
- */
- private static final String XMLATTR_COLOR_BALLOON = "color_balloon";
-
- /**
- * Attribute tag of the id of {@link #XMLTAG_KEYTYPE} and
- * {@link #XMLTAG_KEY}. Key types and keys defined in a soft keyboard
- * template should have id, because a soft keyboard needs the id to refer to
- * these default definitions. If a key defined in {@link #XMLTAG_KEYBOARD}
- * does not id, that means the key is newly defined; if it has id (and only
- * has id), the id is used to find the default definition from the soft
- * keyboard template.
- */
- private static final String XMLATTR_ID = "id";
-
- /**
- * Attribute tag of the key background for a specified key type. Defined
- * inside {@link #XMLTAG_KEYTYPE}.
- */
- private static final String XMLATTR_KEYTYPE_BG = "bg";
-
- /**
- * Attribute tag of the key high-light background for a specified key type.
- * Defined inside {@link #XMLTAG_KEYTYPE}.
- */
- private static final String XMLATTR_KEYTYPE_HLBG = "hlbg";
-
- /**
- * Attribute tag of the starting x-position of an element. It can be defined
- * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}.
- * If not defined, 0 will be used. For a key defined in
- * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to
- * calculate its own position.
- */
- private static final String XMLATTR_START_POS_X = "start_pos_x";
-
- /**
- * Attribute tag of the starting y-position of an element. It can be defined
- * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}.
- * If not defined, 0 will be used. For a key defined in
- * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to
- * calculate its own position.
- */
- private static final String XMLATTR_START_POS_Y = "start_pos_y";
-
- /**
- * Attribute tag of a row's id. Defined {@link #XMLTAG_ROW}. If not defined,
- * -1 will be used. Rows with id -1 will be enabled always, rows with same
- * row id will be enabled when the id is the same to the activated id of the
- * soft keyboard.
- */
- private static final String XMLATTR_ROW_ID = "row_id";
-
- /** The tag used to indicate the keyboard element in the xml file. */
- private static final String XMLTAG_KEYBOARD = "keyboard";
-
- /** The tag used to indicate the row element in the xml file. */
- private static final String XMLTAG_ROW = "row";
-
- /** The tag used to indicate key-array element in the xml file. */
- private static final String XMLTAG_KEYS = "keys";
-
- /**
- * The tag used to indicate a key element in the xml file. If the element is
- * defined in a soft keyboard template, it should have an id. If it is
- * defined in a soft keyboard, id is not required.
- */
- private static final String XMLTAG_KEY = "key";
-
- /** The tag used to indicate a key's toggle element in the xml file. */
- private static final String XMLTAG_TOGGLE_STATE = "toggle_state";
-
- /**
- * Attribute tag of the toggle state id for toggle key. Defined inside
- * {@link #XMLTAG_TOGGLE_STATE}
- */
- private static final String XMLATTR_TOGGLE_STATE_ID = "state_id";
-
- /** Attribute tag of key template for the soft keyboard. */
- private static final String XMLATTR_SKB_TEMPLATE = "skb_template";
-
- /**
- * Attribute tag used to indicate whether this soft keyboard needs to be
- * cached in memory for future use. {@link #DEFAULT_SKB_CACHE_FLAG}
- * specifies the default value.
- */
- private static final String XMLATTR_SKB_CACHE_FLAG = "skb_cache_flag";
-
- /**
- * Attribute tag used to indicate whether this soft keyboard is sticky. A
- * sticky soft keyboard will keep the current layout unless user makes a
- * switch explicitly. A none sticky soft keyboard will automatically goes
- * back to the previous keyboard after click a none-function key.
- * {@link #DEFAULT_SKB_STICKY_FLAG} specifies the default value.
- */
- private static final String XMLATTR_SKB_STICKY_FLAG = "skb_sticky_flag";
-
- /** Attribute tag to indicate whether it is a QWERTY soft keyboard. */
- private static final String XMLATTR_QWERTY = "qwerty";
-
- /**
- * When the soft keyboard is a QWERTY one, this attribute tag to get the
- * information that whether it is defined in upper case.
- */
- private static final String XMLATTR_QWERTY_UPPERCASE = "qwerty_uppercase";
-
- /** Attribute tag of key type. */
- private static final String XMLATTR_KEY_TYPE = "key_type";
-
- /** Attribute tag of key width. */
- private static final String XMLATTR_KEY_WIDTH = "width";
-
- /** Attribute tag of key height. */
- private static final String XMLATTR_KEY_HEIGHT = "height";
-
- /** Attribute tag of the key's repeating ability. */
- private static final String XMLATTR_KEY_REPEAT = "repeat";
-
- /** Attribute tag of the key's behavior for balloon. */
- private static final String XMLATTR_KEY_BALLOON = "balloon";
-
- /** Attribute tag of the key splitter in a key array. */
- private static final String XMLATTR_KEY_SPLITTER = "splitter";
-
- /** Attribute tag of the key labels in a key array. */
- private static final String XMLATTR_KEY_LABELS = "labels";
-
- /** Attribute tag of the key codes in a key array. */
- private static final String XMLATTR_KEY_CODES = "codes";
-
- /** Attribute tag of the key label in a key. */
- private static final String XMLATTR_KEY_LABEL = "label";
-
- /** Attribute tag of the key code in a key. */
- private static final String XMLATTR_KEY_CODE = "code";
-
- /** Attribute tag of the key icon in a key. */
- private static final String XMLATTR_KEY_ICON = "icon";
-
- /** Attribute tag of the key's popup icon in a key. */
- private static final String XMLATTR_KEY_ICON_POPUP = "icon_popup";
-
- /** The id for a mini popup soft keyboard. */
- private static final String XMLATTR_KEY_POPUP_SKBID = "popup_skb";
-
- private static boolean DEFAULT_SKB_CACHE_FLAG = true;
-
- private static boolean DEFAULT_SKB_STICKY_FLAG = true;
-
- /**
- * The key type id for invalid key type. It is also used to generate next
- * valid key type id by adding 1.
- */
- private static final int KEYTYPE_ID_LAST = -1;
-
- private Context mContext;
-
- private Resources mResources;
-
- /** The event type in parsing the xml file. */
- private int mXmlEventType;
-
- /**
- * The current soft keyboard template used by the current soft keyboard
- * under loading.
- **/
- private SkbTemplate mSkbTemplate;
-
- /** The x position for the next key. */
- float mKeyXPos;
-
- /** The y position for the next key. */
- float mKeyYPos;
-
- /** The width of the keyboard to load. */
- int mSkbWidth;
-
- /** The height of the keyboard to load. */
- int mSkbHeight;
-
- /** Key margin in x-way. */
- float mKeyXMargin = 0;
-
- /** Key margin in y-way. */
- float mKeyYMargin = 0;
-
- /**
- * Used to indicate whether next event has been fetched during processing
- * the the current event.
- */
- boolean mNextEventFetched = false;
-
- String mAttrTmp;
-
- class KeyCommonAttributes {
- XmlResourceParser mXrp;
- int keyType;
- float keyWidth;
- float keyHeight;
- boolean repeat;
- boolean balloon;
-
- KeyCommonAttributes(XmlResourceParser xrp) {
- mXrp = xrp;
- balloon = true;
- }
-
- // Make sure the default object is not null.
- boolean getAttributes(KeyCommonAttributes defAttr) {
- keyType = getInteger(mXrp, XMLATTR_KEY_TYPE, defAttr.keyType);
- keyWidth = getFloat(mXrp, XMLATTR_KEY_WIDTH, defAttr.keyWidth);
- keyHeight = getFloat(mXrp, XMLATTR_KEY_HEIGHT, defAttr.keyHeight);
- repeat = getBoolean(mXrp, XMLATTR_KEY_REPEAT, defAttr.repeat);
- balloon = getBoolean(mXrp, XMLATTR_KEY_BALLOON, defAttr.balloon);
- if (keyType < 0 || keyWidth <= 0 || keyHeight <= 0) {
- return false;
- }
- return true;
- }
- }
-
- public XmlKeyboardLoader(Context context) {
- mContext = context;
- mResources = mContext.getResources();
- }
-
- public SkbTemplate loadSkbTemplate(int resourceId) {
- if (null == mContext || 0 == resourceId) {
- return null;
- }
- Resources r = mResources;
- XmlResourceParser xrp = r.getXml(resourceId);
-
- KeyCommonAttributes attrDef = new KeyCommonAttributes(xrp);
- KeyCommonAttributes attrKey = new KeyCommonAttributes(xrp);
-
- mSkbTemplate = new SkbTemplate(resourceId);
- int lastKeyTypeId = KEYTYPE_ID_LAST;
- int globalColor = 0;
- int globalColorHl = 0;
- int globalColorBalloon = 0;
- try {
- mXmlEventType = xrp.next();
- while (mXmlEventType != XmlResourceParser.END_DOCUMENT) {
- mNextEventFetched = false;
- if (mXmlEventType == XmlResourceParser.START_TAG) {
- String attribute = xrp.getName();
- if (XMLTAG_SKB_TEMPLATE.compareTo(attribute) == 0) {
- Drawable skbBg = getDrawable(xrp, XMLATTR_SKB_BG, null);
- Drawable balloonBg = getDrawable(xrp,
- XMLATTR_BALLOON_BG, null);
- Drawable popupBg = getDrawable(xrp, XMLATTR_POPUP_BG,
- null);
- if (null == skbBg || null == balloonBg
- || null == popupBg) {
- return null;
- }
- mSkbTemplate.setBackgrounds(skbBg, balloonBg, popupBg);
-
- float xMargin = getFloat(xrp, XMLATTR_KEY_XMARGIN, 0);
- float yMargin = getFloat(xrp, XMLATTR_KEY_YMARGIN, 0);
- mSkbTemplate.setMargins(xMargin, yMargin);
-
- // Get default global colors.
- globalColor = getColor(xrp, XMLATTR_COLOR, 0);
- globalColorHl = getColor(xrp, XMLATTR_COLOR_HIGHLIGHT,
- 0xffffffff);
- globalColorBalloon = getColor(xrp,
- XMLATTR_COLOR_BALLOON, 0xffffffff);
- } else if (XMLTAG_KEYTYPE.compareTo(attribute) == 0) {
- int id = getInteger(xrp, XMLATTR_ID, KEYTYPE_ID_LAST);
- Drawable bg = getDrawable(xrp, XMLATTR_KEYTYPE_BG, null);
- Drawable hlBg = getDrawable(xrp, XMLATTR_KEYTYPE_HLBG,
- null);
- int color = getColor(xrp, XMLATTR_COLOR, globalColor);
- int colorHl = getColor(xrp, XMLATTR_COLOR_HIGHLIGHT,
- globalColorHl);
- int colorBalloon = getColor(xrp, XMLATTR_COLOR_BALLOON,
- globalColorBalloon);
- if (id != lastKeyTypeId + 1) {
- return null;
- }
- SoftKeyType keyType = mSkbTemplate.createKeyType(id,
- bg, hlBg);
- keyType.setColors(color, colorHl, colorBalloon);
- if (!mSkbTemplate.addKeyType(keyType)) {
- return null;
- }
- lastKeyTypeId = id;
- } else if (XMLTAG_KEYICON.compareTo(attribute) == 0) {
- int keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0);
- Drawable icon = getDrawable(xrp, XMLATTR_KEY_ICON, null);
- Drawable iconPopup = getDrawable(xrp,
- XMLATTR_KEY_ICON_POPUP, null);
- if (null != icon && null != iconPopup) {
- mSkbTemplate.addDefaultKeyIcons(keyCode, icon,
- iconPopup);
- }
- } else if (XMLTAG_KEY.compareTo(attribute) == 0) {
- int keyId = this.getInteger(xrp, XMLATTR_ID, -1);
- if (-1 == keyId) return null;
-
- if (!attrKey.getAttributes(attrDef)) {
- return null;
- }
-
- // Update the key position for the key.
- mKeyXPos = getFloat(xrp, XMLATTR_START_POS_X, 0);
- mKeyYPos = getFloat(xrp, XMLATTR_START_POS_Y, 0);
-
- SoftKey softKey = getSoftKey(xrp, attrKey);
- if (null == softKey) return null;
- mSkbTemplate.addDefaultKey(keyId, softKey);
- }
- }
- // Get the next tag.
- if (!mNextEventFetched) mXmlEventType = xrp.next();
- }
- xrp.close();
- return mSkbTemplate;
- } catch (XmlPullParserException e) {
- // Log.e(TAG, "Ill-formatted keyboard template resource file");
- } catch (IOException e) {
- // Log.e(TAG, "Unable to keyboard template resource file");
- }
- return null;
- }
-
- public SoftKeyboard loadKeyboard(int resourceId, int skbWidth, int skbHeight, boolean force) {
- if (null == mContext) return null;
- Resources r = mResources;
- SkbPool skbPool = SkbPool.getInstance();
- XmlResourceParser xrp = mContext.getResources().getXml(resourceId);
- mSkbTemplate = null;
- SoftKeyboard softKeyboard = null;
- Drawable skbBg;
- Drawable popupBg;
- Drawable balloonBg;
- SoftKey softKey = null;
-
- KeyCommonAttributes attrDef = new KeyCommonAttributes(xrp);
- KeyCommonAttributes attrSkb = new KeyCommonAttributes(xrp);
- KeyCommonAttributes attrRow = new KeyCommonAttributes(xrp);
- KeyCommonAttributes attrKeys = new KeyCommonAttributes(xrp);
- KeyCommonAttributes attrKey = new KeyCommonAttributes(xrp);
-
- mKeyXPos = 0;
- mKeyYPos = 0;
- mSkbWidth = skbWidth;
- mSkbHeight = skbHeight;
-
- try {
- mKeyXMargin = 0;
- mKeyYMargin = 0;
- mXmlEventType = xrp.next();
- while (mXmlEventType != XmlResourceParser.END_DOCUMENT) {
- mNextEventFetched = false;
- if (mXmlEventType == XmlResourceParser.START_TAG) {
- String attr = xrp.getName();
- // 1. Is it the root element, "keyboard"?
- if (XMLTAG_KEYBOARD.compareTo(attr) == 0) {
- // 1.1 Get the keyboard template id.
- int skbTemplateId = xrp.getAttributeResourceValue(null,
- XMLATTR_SKB_TEMPLATE, 0);
-
- // 1.2 Try to get the template from pool. If it is not
- // in, the pool will try to load it.
- mSkbTemplate = skbPool.getSkbTemplate(skbTemplateId,
- mContext, force);
-
- if (null == mSkbTemplate
- || !attrSkb.getAttributes(attrDef)) {
- return null;
- }
-
- boolean cacheFlag = getBoolean(xrp,
- XMLATTR_SKB_CACHE_FLAG, DEFAULT_SKB_CACHE_FLAG);
- boolean stickyFlag = getBoolean(xrp,
- XMLATTR_SKB_STICKY_FLAG,
- DEFAULT_SKB_STICKY_FLAG);
- boolean isQwerty = getBoolean(xrp, XMLATTR_QWERTY,
- false);
- boolean isQwertyUpperCase = getBoolean(xrp,
- XMLATTR_QWERTY_UPPERCASE, false);
-
- softKeyboard = new SoftKeyboard(resourceId,
- mSkbTemplate, mSkbWidth, mSkbHeight);
- softKeyboard.setFlags(cacheFlag, stickyFlag, isQwerty,
- isQwertyUpperCase);
-
- mKeyXMargin = getFloat(xrp, XMLATTR_KEY_XMARGIN,
- mSkbTemplate.getXMargin());
- mKeyYMargin = getFloat(xrp, XMLATTR_KEY_YMARGIN,
- mSkbTemplate.getYMargin());
- skbBg = getDrawable(xrp, XMLATTR_SKB_BG, null);
- popupBg = getDrawable(xrp, XMLATTR_POPUP_BG, null);
- balloonBg = getDrawable(xrp, XMLATTR_BALLOON_BG, null);
- if (null != skbBg) {
- softKeyboard.setSkbBackground(skbBg);
- }
- if (null != popupBg) {
- softKeyboard.setPopupBackground(popupBg);
- }
- if (null != balloonBg) {
- softKeyboard.setKeyBalloonBackground(balloonBg);
- }
- softKeyboard.setKeyMargins(mKeyXMargin, mKeyYMargin);
- } else if (XMLTAG_ROW.compareTo(attr) == 0) {
- if (!attrRow.getAttributes(attrSkb)) {
- return null;
- }
- // Get the starting positions for the row.
- mKeyXPos = getFloat(xrp, XMLATTR_START_POS_X, 0);
- mKeyYPos = getFloat(xrp, XMLATTR_START_POS_Y, mKeyYPos);
- int rowId = getInteger(xrp, XMLATTR_ROW_ID,
- KeyRow.ALWAYS_SHOW_ROW_ID);
- softKeyboard.beginNewRow(rowId, mKeyYPos);
- } else if (XMLTAG_KEYS.compareTo(attr) == 0) {
- if (null == softKeyboard) return null;
- if (!attrKeys.getAttributes(attrRow)) {
- return null;
- }
-
- String splitter = xrp.getAttributeValue(null,
- XMLATTR_KEY_SPLITTER);
- splitter = Pattern.quote(splitter);
- String labels = xrp.getAttributeValue(null,
- XMLATTR_KEY_LABELS);
- String codes = xrp.getAttributeValue(null,
- XMLATTR_KEY_CODES);
- if (null == splitter || null == labels) {
- return null;
- }
- String labelArr[] = labels.split(splitter);
- String codeArr[] = null;
- if (null != codes) {
- codeArr = codes.split(splitter);
- if (labelArr.length != codeArr.length) {
- return null;
- }
- }
-
- for (int i = 0; i < labelArr.length; i++) {
- softKey = new SoftKey();
- int keyCode = 0;
- if (null != codeArr) {
- keyCode = Integer.valueOf(codeArr[i]);
- }
- softKey.setKeyAttribute(keyCode, labelArr[i],
- attrKeys.repeat, attrKeys.balloon);
-
- softKey.setKeyType(mSkbTemplate
- .getKeyType(attrKeys.keyType), null, null);
-
- float left, right, top, bottom;
- left = mKeyXPos;
-
- right = left + attrKeys.keyWidth;
- top = mKeyYPos;
- bottom = top + attrKeys.keyHeight;
-
- if (right - left < 2 * mKeyXMargin) return null;
- if (bottom - top < 2 * mKeyYMargin) return null;
-
- softKey.setKeyDimensions(left, top, right, bottom);
- softKeyboard.addSoftKey(softKey);
- mKeyXPos = right;
- if ((int) mKeyXPos * mSkbWidth > mSkbWidth) {
- return null;
- }
- }
- } else if (XMLTAG_KEY.compareTo(attr) == 0) {
- if (null == softKeyboard) {
- return null;
- }
- if (!attrKey.getAttributes(attrRow)) {
- return null;
- }
-
- int keyId = this.getInteger(xrp, XMLATTR_ID, -1);
- if (keyId >= 0) {
- softKey = mSkbTemplate.getDefaultKey(keyId);
- } else {
- softKey = getSoftKey(xrp, attrKey);
- }
- if (null == softKey) return null;
-
- // Update the position for next key.
- mKeyXPos = softKey.mRightF;
- if ((int) mKeyXPos * mSkbWidth > mSkbWidth) {
- return null;
- }
- // If the current xml event type becomes a starting tag,
- // it indicates that we have parsed too much to get
- // toggling states, and we started a new row. In this
- // case, the row starting position information should
- // be updated.
- if (mXmlEventType == XmlResourceParser.START_TAG) {
- attr = xrp.getName();
- if (XMLTAG_ROW.compareTo(attr) == 0) {
- mKeyYPos += attrRow.keyHeight;
- if ((int) mKeyYPos * mSkbHeight > mSkbHeight) {
- return null;
- }
- }
- }
- softKeyboard.addSoftKey(softKey);
- }
- } else if (mXmlEventType == XmlResourceParser.END_TAG) {
- String attr = xrp.getName();
- if (XMLTAG_ROW.compareTo(attr) == 0) {
- mKeyYPos += attrRow.keyHeight;
- if ((int) mKeyYPos * mSkbHeight > mSkbHeight) {
- return null;
- }
- }
- }
-
- // Get the next tag.
- if (!mNextEventFetched) mXmlEventType = xrp.next();
- }
- xrp.close();
- softKeyboard.setSkbCoreSize(mSkbWidth, mSkbHeight);
- return softKeyboard;
- } catch (XmlPullParserException e) {
- // Log.e(TAG, "Ill-formatted keybaord resource file");
- } catch (IOException e) {
- // Log.e(TAG, "Unable to read keyboard resource file");
- }
- return null;
- }
-
- // Caller makes sure xrp and r are valid.
- private SoftKey getSoftKey(XmlResourceParser xrp,
- KeyCommonAttributes attrKey) throws XmlPullParserException,
- IOException {
- int keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0);
- String keyLabel = getString(xrp, XMLATTR_KEY_LABEL, null);
- Drawable keyIcon = getDrawable(xrp, XMLATTR_KEY_ICON, null);
- Drawable keyIconPopup = getDrawable(xrp, XMLATTR_KEY_ICON_POPUP, null);
- int popupSkbId = xrp.getAttributeResourceValue(null,
- XMLATTR_KEY_POPUP_SKBID, 0);
-
- if (null == keyLabel && null == keyIcon) {
- keyIcon = mSkbTemplate.getDefaultKeyIcon(keyCode);
- keyIconPopup = mSkbTemplate.getDefaultKeyIconPopup(keyCode);
- if (null == keyIcon || null == keyIconPopup) return null;
- }
-
- // Dimension information must been initialized before
- // getting toggle state, because mKeyYPos may be changed
- // to next row when trying to get toggle state.
- float left, right, top, bottom;
- left = mKeyXPos;
- right = left + attrKey.keyWidth;
- top = mKeyYPos;
- bottom = top + attrKey.keyHeight;
-
- if (right - left < 2 * mKeyXMargin) return null;
- if (bottom - top < 2 * mKeyYMargin) return null;
-
- // Try to find if the next tag is
- // {@link #XMLTAG_TOGGLE_STATE_OF_KEY}, if yes, try to
- // create a toggle key.
- boolean toggleKey = false;
- mXmlEventType = xrp.next();
- mNextEventFetched = true;
-
- SoftKey softKey;
- if (mXmlEventType == XmlResourceParser.START_TAG) {
- mAttrTmp = xrp.getName();
- if (mAttrTmp.compareTo(XMLTAG_TOGGLE_STATE) == 0) {
- toggleKey = true;
- }
- }
- if (toggleKey) {
- softKey = new SoftKeyToggle();
- if (!((SoftKeyToggle) softKey).setToggleStates(getToggleStates(
- attrKey, (SoftKeyToggle) softKey, keyCode))) {
- return null;
- }
- } else {
- softKey = new SoftKey();
- }
-
- // Set the normal state
- softKey.setKeyAttribute(keyCode, keyLabel, attrKey.repeat,
- attrKey.balloon);
- softKey.setPopupSkbId(popupSkbId);
- softKey.setKeyType(mSkbTemplate.getKeyType(attrKey.keyType), keyIcon,
- keyIconPopup);
-
- softKey.setKeyDimensions(left, top, right, bottom);
- return softKey;
- }
-
- private SoftKeyToggle.ToggleState getToggleStates(
- KeyCommonAttributes attrKey, SoftKeyToggle softKey, int defKeyCode)
- throws XmlPullParserException, IOException {
- XmlResourceParser xrp = attrKey.mXrp;
- int stateId = getInteger(xrp, XMLATTR_TOGGLE_STATE_ID, 0);
- if (0 == stateId) return null;
-
- String keyLabel = getString(xrp, XMLATTR_KEY_LABEL, null);
- int keyTypeId = getInteger(xrp, XMLATTR_KEY_TYPE, KEYTYPE_ID_LAST);
- int keyCode;
- if (null == keyLabel) {
- keyCode = getInteger(xrp, XMLATTR_KEY_CODE, defKeyCode);
- } else {
- keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0);
- }
- Drawable icon = getDrawable(xrp, XMLATTR_KEY_ICON, null);
- Drawable iconPopup = getDrawable(xrp, XMLATTR_KEY_ICON_POPUP, null);
- if (null == icon && null == keyLabel) {
- return null;
- }
- SoftKeyToggle.ToggleState rootState = softKey.createToggleState();
- rootState.setStateId(stateId);
- rootState.mKeyType = null;
- if (KEYTYPE_ID_LAST != keyTypeId) {
- rootState.mKeyType = mSkbTemplate.getKeyType(keyTypeId);
- }
- rootState.mKeyCode = keyCode;
- rootState.mKeyIcon = icon;
- rootState.mKeyIconPopup = iconPopup;
- rootState.mKeyLabel = keyLabel;
-
- boolean repeat = getBoolean(xrp, XMLATTR_KEY_REPEAT, attrKey.repeat);
- boolean balloon = getBoolean(xrp, XMLATTR_KEY_BALLOON, attrKey.balloon);
- rootState.setStateFlags(repeat, balloon);
-
- rootState.mNextState = null;
-
- // If there is another toggle state.
- mXmlEventType = xrp.next();
- while (mXmlEventType != XmlResourceParser.START_TAG
- && mXmlEventType != XmlResourceParser.END_DOCUMENT) {
- mXmlEventType = xrp.next();
- }
- if (mXmlEventType == XmlResourceParser.START_TAG) {
- String attr = xrp.getName();
- if (attr.compareTo(XMLTAG_TOGGLE_STATE) == 0) {
- SoftKeyToggle.ToggleState nextState = getToggleStates(attrKey,
- softKey, defKeyCode);
- if (null == nextState) return null;
- rootState.mNextState = nextState;
- }
- }
-
- return rootState;
- }
-
- private int getInteger(XmlResourceParser xrp, String name, int defValue) {
- int resId = xrp.getAttributeResourceValue(null, name, 0);
- String s;
- if (resId == 0) {
- s = xrp.getAttributeValue(null, name);
- if (null == s) return defValue;
- try {
- int ret = Integer.valueOf(s);
- return ret;
- } catch (NumberFormatException e) {
- return defValue;
- }
- } else {
- return Integer.parseInt(mContext.getResources().getString(resId));
- }
- }
-
- private int getColor(XmlResourceParser xrp, String name, int defValue) {
- int resId = xrp.getAttributeResourceValue(null, name, 0);
- String s;
- if (resId == 0) {
- s = xrp.getAttributeValue(null, name);
- if (null == s) return defValue;
- try {
- int ret = Integer.valueOf(s);
- return ret;
- } catch (NumberFormatException e) {
- return defValue;
- }
- } else {
- return mContext.getResources().getColor(resId);
- }
- }
-
- private String getString(XmlResourceParser xrp, String name, String defValue) {
- int resId = xrp.getAttributeResourceValue(null, name, 0);
- if (resId == 0) {
- return xrp.getAttributeValue(null, name);
- } else {
- return mContext.getResources().getString(resId);
- }
- }
-
- private float getFloat(XmlResourceParser xrp, String name, float defValue) {
- int resId = xrp.getAttributeResourceValue(null, name, 0);
- if (resId == 0) {
- String s = xrp.getAttributeValue(null, name);
- if (null == s) return defValue;
- try {
- float ret;
- if (s.endsWith("%p")) {
- ret = Float.parseFloat(s.substring(0, s.length() - 2)) / 100;
- } else {
- ret = Float.parseFloat(s);
- }
- return ret;
- } catch (NumberFormatException e) {
- return defValue;
- }
- } else {
- return mContext.getResources().getDimension(resId);
- }
- }
-
- private boolean getBoolean(XmlResourceParser xrp, String name,
- boolean defValue) {
- String s = xrp.getAttributeValue(null, name);
- if (null == s) return defValue;
- try {
- boolean ret = Boolean.parseBoolean(s);
- return ret;
- } catch (NumberFormatException e) {
- return defValue;
- }
- }
-
- private Drawable getDrawable(XmlResourceParser xrp, String name,
- Drawable defValue) {
- int resId = xrp.getAttributeResourceValue(null, name, 0);
- if (0 == resId) return defValue;
- return mResources.getDrawable(resId);
- }
-}
diff --git a/src/com/droidlogic/inputmethod/remote/BalloonHint.java b/src/com/droidlogic/inputmethod/remote/BalloonHint.java
new file mode 100644
index 0000000..a96b4d0
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/BalloonHint.java
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.view.Gravity;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.widget.PopupWindow;
+
+/**
+ * Subclass of PopupWindow used as the feedback when user presses on a soft key
+ * or a candidate.
+ */
+public class BalloonHint extends PopupWindow {
+ /**
+ * Delayed time to show the balloon hint.
+ */
+ public static final int TIME_DELAY_SHOW = 0;
+
+ /**
+ * Delayed time to dismiss the balloon hint.
+ */
+ public static final int TIME_DELAY_DISMISS = 200;
+
+ /**
+ * The padding information of the balloon. Because PopupWindow's background
+ * can not be changed unless it is dismissed and shown again, we set the
+ * real background drawable to the content view, and make the PopupWindow's
+ * background transparent. So actually this padding information is for the
+ * content view.
+ */
+ private Rect mPaddingRect = new Rect();
+
+ /**
+ * The context used to create this balloon hint object.
+ */
+ private Context mContext;
+
+ /**
+ * Parent used to show the balloon window.
+ */
+ private View mParent;
+
+ /**
+ * The content view of the balloon.
+ */
+ BalloonView mBalloonView;
+
+ /**
+ * The measuring specification used to determine its size. Key-press
+ * balloons and candidates balloons have different measuring specifications.
+ */
+ private int mMeasureSpecMode;
+
+ /**
+ * Used to indicate whether the balloon needs to be dismissed forcibly.
+ */
+ private boolean mForceDismiss;
+
+ /**
+ * Timer used to show/dismiss the balloon window with some time delay.
+ */
+ private BalloonTimer mBalloonTimer;
+
+ private int mParentLocationInWindow[] = new int[2];
+
+ public BalloonHint ( Context context, View parent, int measureSpecMode ) {
+ super ( context );
+ mParent = parent;
+ mMeasureSpecMode = measureSpecMode;
+ setInputMethodMode ( PopupWindow.INPUT_METHOD_NOT_NEEDED );
+ setTouchable ( false );
+ setBackgroundDrawable ( new ColorDrawable ( 0 ) );
+ mBalloonView = new BalloonView ( context );
+ mBalloonView.setClickable ( false );
+ setContentView ( mBalloonView );
+ mBalloonTimer = new BalloonTimer();
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public Rect getPadding() {
+ return mPaddingRect;
+ }
+
+ public void setBalloonBackground ( Drawable drawable ) {
+ // We usually pick up a background from a soft keyboard template,
+ // and the object may has been set to this balloon before.
+ if ( mBalloonView.getBackground() == drawable ) { return; }
+ mBalloonView.setBackgroundDrawable ( drawable );
+ if ( null != drawable ) {
+ drawable.getPadding ( mPaddingRect );
+ } else {
+ mPaddingRect.set ( 0, 0, 0, 0 );
+ }
+ }
+
+ /**
+ * Set configurations to show text label in this balloon.
+ *
+ * @param label The text label to show in the balloon.
+ * @param textSize The text size used to show label.
+ * @param textBold Used to indicate whether the label should be bold.
+ * @param textColor The text color used to show label.
+ * @param width The desired width of the balloon. The real width is
+ * determined by the desired width and balloon's measuring
+ * specification.
+ * @param height The desired width of the balloon. The real width is
+ * determined by the desired width and balloon's measuring
+ * specification.
+ */
+ public void setBalloonConfig ( String label, float textSize,
+ boolean textBold, int textColor, int width, int height ) {
+ mBalloonView.setTextConfig ( label, textSize, textBold, textColor );
+ setBalloonSize ( width, height );
+ }
+
+ /**
+ * Set configurations to show text label in this balloon.
+ *
+ * @param icon The icon used to shown in this balloon.
+ * @param width The desired width of the balloon. The real width is
+ * determined by the desired width and balloon's measuring
+ * specification.
+ * @param height The desired width of the balloon. The real width is
+ * determined by the desired width and balloon's measuring
+ * specification.
+ */
+ public void setBalloonConfig ( Drawable icon, int width, int height ) {
+ mBalloonView.setIcon ( icon );
+ setBalloonSize ( width, height );
+ }
+
+
+ public boolean needForceDismiss() {
+ return mForceDismiss;
+ }
+
+ public int getPaddingLeft() {
+ return mPaddingRect.left;
+ }
+
+ public int getPaddingTop() {
+ return mPaddingRect.top;
+ }
+
+ public int getPaddingRight() {
+ return mPaddingRect.right;
+ }
+
+ public int getPaddingBottom() {
+ return mPaddingRect.bottom;
+ }
+
+ public void delayedShow ( long delay, int locationInParent[] ) {
+ if ( mBalloonTimer.isPending() ) {
+ mBalloonTimer.removeTimer();
+ }
+ if ( delay <= 0 ) {
+ mParent.getLocationInWindow ( mParentLocationInWindow );
+ showAtLocation ( mParent, Gravity.LEFT | Gravity.TOP,
+ locationInParent[0], locationInParent[1]
+ + mParentLocationInWindow[1] );
+ } else {
+ mBalloonTimer.startTimer ( delay, BalloonTimer.ACTION_SHOW,
+ locationInParent, -1, -1 );
+ }
+ }
+
+ public void delayedUpdate ( long delay, int locationInParent[],
+ int width, int height ) {
+ mBalloonView.invalidate();
+ if ( mBalloonTimer.isPending() ) {
+ mBalloonTimer.removeTimer();
+ }
+ if ( delay <= 0 ) {
+ mParent.getLocationInWindow ( mParentLocationInWindow );
+ update ( locationInParent[0], locationInParent[1]
+ + mParentLocationInWindow[1], width, height );
+ } else {
+ mBalloonTimer.startTimer ( delay, BalloonTimer.ACTION_UPDATE,
+ locationInParent, width, height );
+ }
+ }
+
+ public void delayedDismiss ( long delay ) {
+ if ( mBalloonTimer.isPending() ) {
+ mBalloonTimer.removeTimer();
+ int pendingAction = mBalloonTimer.getAction();
+ if ( 0 != delay && BalloonTimer.ACTION_HIDE != pendingAction ) {
+ mBalloonTimer.run();
+ }
+ }
+ if ( delay <= 0 ) {
+ dismiss();
+ } else {
+ mBalloonTimer.startTimer ( delay, BalloonTimer.ACTION_HIDE, null, -1,
+ -1 );
+ }
+ }
+
+ public void removeTimer() {
+ if ( mBalloonTimer.isPending() ) {
+ mBalloonTimer.removeTimer();
+ }
+ }
+
+ private void setBalloonSize ( int width, int height ) {
+ int widthMeasureSpec = MeasureSpec.makeMeasureSpec ( width,
+ mMeasureSpecMode );
+ int heightMeasureSpec = MeasureSpec.makeMeasureSpec ( height,
+ mMeasureSpecMode );
+ mBalloonView.measure ( widthMeasureSpec, heightMeasureSpec );
+ int oldWidth = getWidth();
+ int oldHeight = getHeight();
+ int newWidth = mBalloonView.getMeasuredWidth() + getPaddingLeft()
+ + getPaddingRight();
+ int newHeight = mBalloonView.getMeasuredHeight() + getPaddingTop()
+ + getPaddingBottom();
+ setWidth ( newWidth );
+ setHeight ( newHeight );
+ // If update() is called to update both size and position, the system
+ // will first MOVE the PopupWindow to the new position, and then
+ // perform a size-updating operation, so there will be a flash in
+ // PopupWindow if user presses a key and moves finger to next one whose
+ // size is different.
+ // PopupWindow will handle the updating issue in one go in the future,
+ // but before that, if we find the size is changed, a mandatory dismiss
+ // operation is required. In our UI design, normal QWERTY keys' width
+ // can be different in 1-pixel, and we do not dismiss the balloon when
+ // user move between QWERTY keys.
+ mForceDismiss = false;
+ if ( isShowing() ) {
+ mForceDismiss = oldWidth - newWidth > 1 || newWidth - oldWidth > 1;
+ }
+ }
+
+
+ private class BalloonTimer extends Handler implements Runnable {
+ public static final int ACTION_SHOW = 1;
+ public static final int ACTION_HIDE = 2;
+ public static final int ACTION_UPDATE = 3;
+
+ /**
+ * The pending action.
+ */
+ private int mAction;
+
+ private int mPositionInParent[] = new int[2];
+ private int mWidth;
+ private int mHeight;
+
+ private boolean mTimerPending = false;
+
+ public void startTimer ( long time, int action, int positionInParent[],
+ int width, int height ) {
+ mAction = action;
+ if ( ACTION_HIDE != action ) {
+ mPositionInParent[0] = positionInParent[0];
+ mPositionInParent[1] = positionInParent[1];
+ }
+ mWidth = width;
+ mHeight = height;
+ postDelayed ( this, time );
+ mTimerPending = true;
+ }
+
+ public boolean isPending() {
+ return mTimerPending;
+ }
+
+ public boolean removeTimer() {
+ if ( mTimerPending ) {
+ mTimerPending = false;
+ removeCallbacks ( this );
+ return true;
+ }
+ return false;
+ }
+
+ public int getAction() {
+ return mAction;
+ }
+
+ public void run() {
+ switch ( mAction ) {
+ case ACTION_SHOW:
+ mParent.getLocationInWindow ( mParentLocationInWindow );
+ showAtLocation ( mParent, Gravity.LEFT | Gravity.TOP,
+ mPositionInParent[0], mPositionInParent[1]
+ + mParentLocationInWindow[1] );
+ break;
+ case ACTION_HIDE:
+ dismiss();
+ break;
+ case ACTION_UPDATE:
+ mParent.getLocationInWindow ( mParentLocationInWindow );
+ update ( mPositionInParent[0], mPositionInParent[1]
+ + mParentLocationInWindow[1], mWidth, mHeight );
+ }
+ mTimerPending = false;
+ }
+ }
+
+ private class BalloonView extends View {
+ /**
+ * Suspension points used to display long items.
+ */
+ private static final String SUSPENSION_POINTS = "...";
+
+ /**
+ * The icon to be shown. If it is not null, {@link #mLabel} will be
+ * ignored.
+ */
+ private Drawable mIcon;
+
+ /**
+ * The label to be shown. It is enabled only if {@link #mIcon} is null.
+ */
+ private String mLabel;
+
+ private int mLabeColor = 0xff000000;
+ private Paint mPaintLabel;
+ private FontMetricsInt mFmi;
+
+ /**
+ * The width to show suspension points.
+ */
+ private float mSuspensionPointsWidth;
+
+
+ public BalloonView ( Context context ) {
+ super ( context );
+ mPaintLabel = new Paint();
+ mPaintLabel.setColor ( mLabeColor );
+ mPaintLabel.setAntiAlias ( true );
+ mPaintLabel.setFakeBoldText ( true );
+ mFmi = mPaintLabel.getFontMetricsInt();
+ }
+
+ public void setIcon ( Drawable icon ) {
+ mIcon = icon;
+ }
+
+ public void setTextConfig ( String label, float fontSize,
+ boolean textBold, int textColor ) {
+ // Icon should be cleared so that the label will be enabled.
+ mIcon = null;
+ mLabel = label;
+ mPaintLabel.setTextSize ( fontSize );
+ mPaintLabel.setFakeBoldText ( textBold );
+ mPaintLabel.setColor ( textColor );
+ mFmi = mPaintLabel.getFontMetricsInt();
+ mSuspensionPointsWidth = mPaintLabel.measureText ( SUSPENSION_POINTS );
+ }
+
+ @Override
+ protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) {
+ final int widthMode = MeasureSpec.getMode ( widthMeasureSpec );
+ final int heightMode = MeasureSpec.getMode ( heightMeasureSpec );
+ final int widthSize = MeasureSpec.getSize ( widthMeasureSpec );
+ final int heightSize = MeasureSpec.getSize ( heightMeasureSpec );
+ if ( widthMode == MeasureSpec.EXACTLY ) {
+ setMeasuredDimension ( widthSize, heightSize );
+ return;
+ }
+ int measuredWidth = mPaddingLeft + mPaddingRight;
+ int measuredHeight = mPaddingTop + mPaddingBottom;
+ if ( null != mIcon ) {
+ measuredWidth += mIcon.getIntrinsicWidth();
+ measuredHeight += mIcon.getIntrinsicHeight();
+ } else if ( null != mLabel ) {
+ measuredWidth += ( int ) ( mPaintLabel.measureText ( mLabel ) );
+ measuredHeight += mFmi.bottom - mFmi.top;
+ }
+ if ( widthSize > measuredWidth || widthMode == MeasureSpec.AT_MOST ) {
+ measuredWidth = widthSize;
+ }
+ if ( heightSize > measuredHeight
+ || heightMode == MeasureSpec.AT_MOST ) {
+ measuredHeight = heightSize;
+ }
+ int maxWidth = Environment.getInstance().getScreenWidth() -
+ mPaddingLeft - mPaddingRight;
+ if ( measuredWidth > maxWidth ) {
+ measuredWidth = maxWidth;
+ }
+ setMeasuredDimension ( measuredWidth, measuredHeight );
+ }
+
+ @Override
+ protected void onDraw ( Canvas canvas ) {
+ int width = getWidth();
+ int height = getHeight();
+ if ( null != mIcon ) {
+ int marginLeft = ( width - mIcon.getIntrinsicWidth() ) / 2;
+ int marginRight = width - mIcon.getIntrinsicWidth()
+ - marginLeft;
+ int marginTop = ( height - mIcon.getIntrinsicHeight() ) / 2;
+ int marginBottom = height - mIcon.getIntrinsicHeight()
+ - marginTop;
+ mIcon.setBounds ( marginLeft, marginTop, width - marginRight,
+ height - marginBottom );
+ mIcon.draw ( canvas );
+ } else if ( null != mLabel ) {
+ float labelMeasuredWidth = mPaintLabel.measureText ( mLabel );
+ float x = mPaddingLeft;
+ x += ( width - labelMeasuredWidth - mPaddingLeft - mPaddingRight ) / 2.0f;
+ String labelToDraw = mLabel;
+ if ( x < mPaddingLeft ) {
+ x = mPaddingLeft;
+ labelToDraw = getLimitedLabelForDrawing ( mLabel,
+ width - mPaddingLeft - mPaddingRight );
+ }
+ int fontHeight = mFmi.bottom - mFmi.top;
+ float marginY = ( height - fontHeight ) / 2.0f;
+ float y = marginY - mFmi.top;
+ canvas.drawText ( labelToDraw, x, y, mPaintLabel );
+ }
+ }
+
+ private String getLimitedLabelForDrawing ( String rawLabel,
+ float widthToDraw ) {
+ int subLen = rawLabel.length();
+ if ( subLen <= 1 ) { return rawLabel; }
+ do {
+ subLen--;
+ float width = mPaintLabel.measureText ( rawLabel, 0, subLen );
+ if ( width + mSuspensionPointsWidth <= widthToDraw || 1 >= subLen ) {
+ return rawLabel.substring ( 0, subLen ) +
+ SUSPENSION_POINTS;
+ }
+ } while ( true );
+ }
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/CandidateView.java b/src/com/droidlogic/inputmethod/remote/CandidateView.java
new file mode 100644
index 0000000..d79426d
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/CandidateView.java
@@ -0,0 +1,709 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import com.droidlogic.inputmethod.remote.RemoteIME.DecodingInfo;
+
+import java.util.Vector;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * View to show candidate list. There two candidate view instances which are
+ * used to show animation when user navigates between pages.
+ */
+public class CandidateView extends View {
+ /**
+ * The minimum width to show a item.
+ */
+ private static final float MIN_ITEM_WIDTH = 22;
+
+ /**
+ * Suspension points used to display long items.
+ */
+ private static final String SUSPENSION_POINTS = "...";
+
+ /**
+ * The width to draw candidates.
+ */
+ private int mContentWidth;
+
+ /**
+ * The height to draw candidate content.
+ */
+ private int mContentHeight;
+
+ /**
+ * Whether footnotes are displayed. Footnote is shown when hardware keyboard
+ * is available.
+ */
+ private boolean mShowFootnote = true;
+
+ /**
+ * Balloon hint for candidate press/release.
+ */
+ private BalloonHint mBalloonHint;
+
+ /**
+ * Desired position of the balloon to the input view.
+ */
+ private int mHintPositionToInputView[] = new int[2];
+
+ /**
+ * Decoding result to show.
+ */
+ private DecodingInfo mDecInfo;
+
+ /**
+ * Listener used to notify IME that user clicks a candidate, or navigate
+ * between them.
+ */
+ private CandidateViewListener mCvListener;
+
+ /**
+ * Used to notify the container to update the status of forward/backward
+ * arrows.
+ */
+ private ArrowUpdater mArrowUpdater;
+
+ /**
+ * If true, update the arrow status when drawing candidates.
+ */
+ private boolean mUpdateArrowStatusWhenDraw = false;
+
+ /**
+ * Page number of the page displayed in this view.
+ */
+ private int mPageNo;
+
+ /**
+ * Active candidate position in this page.
+ */
+ private int mActiveCandInPage;
+
+ /**
+ * Used to decided whether the active candidate should be highlighted or
+ * not. If user changes focus to composing view (The view to show Pinyin
+ * string), the highlight in candidate view should be removed.
+ */
+ private boolean mEnableActiveHighlight = true;
+
+ /**
+ * The page which is just calculated.
+ */
+ private int mPageNoCalculated = -1;
+
+ /**
+ * The Drawable used to display as the background of the high-lighted item.
+ */
+ private Drawable mActiveCellDrawable;
+
+ /**
+ * The Drawable used to display as separators between candidates.
+ */
+ private Drawable mSeparatorDrawable;
+
+ /**
+ * Color to draw normal candidates generated by IME.
+ */
+ private int mImeCandidateColor;
+
+ /**
+ * Color to draw normal candidates Recommended by application.
+ */
+ private int mRecommendedCandidateColor;
+
+ /**
+ * Color to draw the normal(not highlighted) candidates, it can be one of
+ * {@link #mImeCandidateColor} or {@link #mRecommendedCandidateColor}.
+ */
+ private int mNormalCandidateColor;
+
+ /**
+ * Color to draw the active(highlighted) candidates, including candidates
+ * from IME and candidates from application.
+ */
+ private int mActiveCandidateColor;
+
+ /**
+ * Text size to draw candidates generated by IME.
+ */
+ private int mImeCandidateTextSize;
+
+ /**
+ * Text size to draw candidates recommended by application.
+ */
+ private int mRecommendedCandidateTextSize;
+
+ /**
+ * The current text size to draw candidates. It can be one of
+ * {@link #mImeCandidateTextSize} or {@link #mRecommendedCandidateTextSize}.
+ */
+ private int mCandidateTextSize;
+
+ /**
+ * Paint used to draw candidates.
+ */
+ private Paint mCandidatesPaint;
+
+ /**
+ * Used to draw footnote.
+ */
+ private Paint mFootnotePaint;
+
+ /**
+ * The width to show suspension points.
+ */
+ private float mSuspensionPointsWidth;
+
+ /**
+ * Rectangle used to draw the active candidate.
+ */
+ private RectF mActiveCellRect;
+
+ /**
+ * Left and right margins for a candidate. It is specified in xml, and is
+ * the minimum margin for a candidate. The actual gap between two candidates
+ * is 2 * {@link #mCandidateMargin} + {@link #mSeparatorDrawable}.
+ * getIntrinsicWidth(). Because length of candidate is not fixed, there can
+ * be some extra space after the last candidate in the current page. In
+ * order to achieve best look-and-feel, this extra space will be divided and
+ * allocated to each candidates.
+ */
+ private float mCandidateMargin;
+
+ /**
+ * Left and right extra margins for a candidate.
+ */
+ private float mCandidateMarginExtra;
+
+ /**
+ * Rectangles for the candidates in this page.
+ **/
+ private Vector<RectF> mCandRects;
+
+ /**
+ * FontMetricsInt used to measure the size of candidates.
+ */
+ private FontMetricsInt mFmiCandidates;
+
+ /**
+ * FontMetricsInt used to measure the size of footnotes.
+ */
+ private FontMetricsInt mFmiFootnote;
+
+ private PressTimer mTimer = new PressTimer();
+
+ private GestureDetector mGestureDetector;
+
+ private int mLocationTmp[] = new int[2];
+
+ public CandidateView ( Context context, AttributeSet attrs ) {
+ super ( context, attrs );
+ Resources r = context.getResources();
+ Configuration conf = r.getConfiguration();
+ if ( conf.keyboard == Configuration.KEYBOARD_NOKEYS
+ || conf.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES ) {
+ mShowFootnote = false;
+ }
+ mActiveCellDrawable = r.getDrawable ( R.drawable.candidate_hl_bg );
+ mSeparatorDrawable = r.getDrawable ( R.drawable.candidates_vertical_line );
+ mCandidateMargin = r.getDimension ( R.dimen.candidate_margin_left_right );
+ mImeCandidateColor = r.getColor ( R.color.candidate_color );
+ mRecommendedCandidateColor = r.getColor ( R.color.recommended_candidate_color );
+ mNormalCandidateColor = mImeCandidateColor;
+ mActiveCandidateColor = r.getColor ( R.color.active_candidate_color );
+ mCandidatesPaint = new Paint();
+ mCandidatesPaint.setAntiAlias ( true );
+ mFootnotePaint = new Paint();
+ mFootnotePaint.setAntiAlias ( true );
+ mFootnotePaint.setColor ( r.getColor ( R.color.footnote_color ) );
+ mActiveCellRect = new RectF();
+ mCandRects = new Vector<RectF>();
+ }
+
+ @Override
+ protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) {
+ int mOldWidth = getMeasuredWidth();
+ int mOldHeight = getMeasuredHeight();
+ setMeasuredDimension ( getDefaultSize ( getSuggestedMinimumWidth(),
+ widthMeasureSpec ), getDefaultSize ( getSuggestedMinimumHeight(),
+ heightMeasureSpec ) );
+ if ( mOldWidth != getMeasuredWidth() || mOldHeight != getMeasuredHeight() ) {
+ onSizeChanged();
+ }
+ }
+
+ public void initialize ( ArrowUpdater arrowUpdater, BalloonHint balloonHint,
+ GestureDetector gestureDetector, CandidateViewListener cvListener ) {
+ mArrowUpdater = arrowUpdater;
+ mBalloonHint = balloonHint;
+ mGestureDetector = gestureDetector;
+ mCvListener = cvListener;
+ }
+
+ public void setDecodingInfo ( DecodingInfo decInfo ) {
+ if ( null == decInfo ) { return; }
+ mDecInfo = decInfo;
+ mPageNoCalculated = -1;
+ if ( mDecInfo.candidatesFromApp() ) {
+ mNormalCandidateColor = mRecommendedCandidateColor;
+ mCandidateTextSize = mRecommendedCandidateTextSize;
+ } else {
+ mNormalCandidateColor = mImeCandidateColor;
+ mCandidateTextSize = mImeCandidateTextSize;
+ }
+ if ( mCandidatesPaint.getTextSize() != mCandidateTextSize ) {
+ mCandidatesPaint.setTextSize ( mCandidateTextSize );
+ mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
+ mSuspensionPointsWidth =
+ mCandidatesPaint.measureText ( SUSPENSION_POINTS );
+ }
+ // Remove any pending timer for the previous list.
+ mTimer.removeTimer();
+ }
+
+ public int getActiveCandiatePosInPage() {
+ return mActiveCandInPage;
+ }
+
+ public int getActiveCandiatePosGlobal() {
+ return mDecInfo.mPageStart.get ( mPageNo ) + mActiveCandInPage;
+ }
+
+ /**
+ * Show a page in the decoding result set previously.
+ *
+ * @param pageNo Which page to show.
+ * @param activeCandInPage Which candidate should be set as active item.
+ * @param enableActiveHighlight When false, active item will not be
+ * highlighted.
+ */
+ public void showPage ( int pageNo, int activeCandInPage,
+ boolean enableActiveHighlight ) {
+ if ( null == mDecInfo ) { return; }
+ mPageNo = pageNo;
+ mActiveCandInPage = activeCandInPage;
+ if ( mEnableActiveHighlight != enableActiveHighlight ) {
+ mEnableActiveHighlight = enableActiveHighlight;
+ }
+ if ( !calculatePage ( mPageNo ) ) {
+ mUpdateArrowStatusWhenDraw = true;
+ } else {
+ mUpdateArrowStatusWhenDraw = false;
+ }
+ invalidate();
+ }
+
+ public void enableActiveHighlight ( boolean enableActiveHighlight ) {
+ if ( enableActiveHighlight == mEnableActiveHighlight ) { return; }
+ mEnableActiveHighlight = enableActiveHighlight;
+ invalidate();
+ }
+
+ public boolean activeCursorForward() {
+ if ( !mDecInfo.pageReady ( mPageNo ) ) { return false; }
+ int pageSize = mDecInfo.mPageStart.get ( mPageNo + 1 )
+ - mDecInfo.mPageStart.get ( mPageNo );
+ if ( mActiveCandInPage + 1 < pageSize ) {
+ showPage ( mPageNo, mActiveCandInPage + 1, true );
+ return true;
+ }
+ return false;
+ }
+
+ public boolean activeCurseBackward() {
+ if ( mActiveCandInPage > 0 ) {
+ showPage ( mPageNo, mActiveCandInPage - 1, true );
+ return true;
+ }
+ return false;
+ }
+
+ private void onSizeChanged() {
+ mContentWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
+ mContentHeight = ( int ) ( ( getMeasuredHeight() - mPaddingTop - mPaddingBottom ) * 0.95f );
+ /**
+ * How to decide the font size if the height for display is given?
+ * Now it is implemented in a stupid way.
+ */
+ int textSize = 1;
+ mCandidatesPaint.setTextSize ( textSize );
+ mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
+ while ( mFmiCandidates.bottom - mFmiCandidates.top < mContentHeight ) {
+ textSize++;
+ mCandidatesPaint.setTextSize ( textSize );
+ mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
+ }
+ mImeCandidateTextSize = textSize;
+ mRecommendedCandidateTextSize = textSize * 3 / 4;
+ if ( null == mDecInfo ) {
+ mCandidateTextSize = mImeCandidateTextSize;
+ mCandidatesPaint.setTextSize ( mCandidateTextSize );
+ mFmiCandidates = mCandidatesPaint.getFontMetricsInt();
+ mSuspensionPointsWidth =
+ mCandidatesPaint.measureText ( SUSPENSION_POINTS );
+ } else {
+ // Reset the decoding information to update members for painting.
+ setDecodingInfo ( mDecInfo );
+ }
+ textSize = 1;
+ mFootnotePaint.setTextSize ( textSize );
+ mFmiFootnote = mFootnotePaint.getFontMetricsInt();
+ while ( mFmiFootnote.bottom - mFmiFootnote.top < mContentHeight / 2 ) {
+ textSize++;
+ mFootnotePaint.setTextSize ( textSize );
+ mFmiFootnote = mFootnotePaint.getFontMetricsInt();
+ }
+ textSize--;
+ mFootnotePaint.setTextSize ( textSize );
+ mFmiFootnote = mFootnotePaint.getFontMetricsInt();
+ // When the size is changed, the first page will be displayed.
+ // mPageNo = 0;
+ // mActiveCandInPage = 0;
+ }
+
+ private boolean calculatePage ( int pageNo ) {
+ if ( pageNo == mPageNoCalculated ) { return true; }
+ mContentWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
+ mContentHeight = ( int ) ( ( getMeasuredHeight() - mPaddingTop - mPaddingBottom ) * 0.95f );
+ if ( mContentWidth <= 0 || mContentHeight <= 0 ) { return false; }
+ int candSize = mDecInfo.mCandidatesList.size();
+ // If the size of page exists, only calculate the extra margin.
+ boolean onlyExtraMargin = false;
+ int fromPage = mDecInfo.mPageStart.size() - 1;
+ if ( mDecInfo.mPageStart.size() > pageNo + 1 ) {
+ onlyExtraMargin = true;
+ fromPage = pageNo;
+ }
+ // If the previous pages have no information, calculate them first.
+ for ( int p = fromPage; p <= pageNo; p++ ) {
+ int pStart = mDecInfo.mPageStart.get ( p );
+ int pSize = 0;
+ int charNum = 0;
+ float lastItemWidth = 0;
+ float xPos;
+ xPos = 0;
+ xPos += mSeparatorDrawable.getIntrinsicWidth();
+ while ( xPos < mContentWidth && pStart + pSize < candSize ) {
+ int itemPos = pStart + pSize;
+ String itemStr = mDecInfo.mCandidatesList.get ( itemPos );
+ float itemWidth = mCandidatesPaint.measureText ( itemStr );
+ if ( itemWidth < MIN_ITEM_WIDTH ) { itemWidth = MIN_ITEM_WIDTH; }
+ itemWidth += mCandidateMargin * 2;
+ itemWidth += mSeparatorDrawable.getIntrinsicWidth();
+ if ( xPos + itemWidth < mContentWidth || 0 == pSize ) {
+ xPos += itemWidth;
+ lastItemWidth = itemWidth;
+ pSize++;
+ charNum += itemStr.length();
+ } else {
+ break;
+ }
+ }
+ if ( !onlyExtraMargin ) {
+ mDecInfo.mPageStart.add ( pStart + pSize );
+ mDecInfo.mCnToPage.add ( mDecInfo.mCnToPage.get ( p ) + charNum );
+ }
+ float marginExtra = ( mContentWidth - xPos ) / pSize / 2;
+ if ( mContentWidth - xPos > lastItemWidth ) {
+ // Must be the last page, because if there are more items,
+ // the next item's width must be less than lastItemWidth.
+ // In this case, if the last margin is less than the current
+ // one, the last margin can be used, so that the
+ // look-and-feeling will be the same as the previous page.
+ if ( mCandidateMarginExtra <= marginExtra ) {
+ marginExtra = mCandidateMarginExtra;
+ }
+ } else if ( pSize == 1 ) {
+ marginExtra = 0;
+ }
+ mCandidateMarginExtra = marginExtra;
+ }
+ mPageNoCalculated = pageNo;
+ return true;
+ }
+
+ @Override
+ protected void onDraw ( Canvas canvas ) {
+ super.onDraw ( canvas );
+ // The invisible candidate view(the one which is not in foreground) can
+ // also be called to drawn, but its decoding result and candidate list
+ // may be empty.
+ if ( null == mDecInfo || mDecInfo.isCandidatesListEmpty() ) { return; }
+ // Calculate page. If the paging information is ready, the function will
+ // return at once.
+ calculatePage ( mPageNo );
+ int pStart = mDecInfo.mPageStart.get ( mPageNo );
+ int pSize = mDecInfo.mPageStart.get ( mPageNo + 1 ) - pStart;
+ float candMargin = mCandidateMargin + mCandidateMarginExtra;
+ if ( mActiveCandInPage > pSize - 1 ) {
+ mActiveCandInPage = pSize - 1;
+ }
+ mCandRects.removeAllElements();
+ float xPos = mPaddingLeft;
+ int yPos = ( getMeasuredHeight() -
+ ( mFmiCandidates.bottom - mFmiCandidates.top ) ) / 2
+ - mFmiCandidates.top;
+ xPos += drawVerticalSeparator ( canvas, xPos );
+ for ( int i = 0; i < pSize; i++ ) {
+ float footnoteSize = 0;
+ String footnote = null;
+ if ( mShowFootnote ) {
+ footnote = Integer.toString ( i + 1 );
+ footnoteSize = mFootnotePaint.measureText ( footnote );
+ assert ( footnoteSize < candMargin );
+ }
+ String cand = mDecInfo.mCandidatesList.get ( pStart + i );
+ float candidateWidth = mCandidatesPaint.measureText ( cand );
+ float centerOffset = 0;
+ if ( candidateWidth < MIN_ITEM_WIDTH ) {
+ centerOffset = ( MIN_ITEM_WIDTH - candidateWidth ) / 2;
+ candidateWidth = MIN_ITEM_WIDTH;
+ }
+ float itemTotalWidth = candidateWidth + 2 * candMargin;
+ if ( mActiveCandInPage == i && mEnableActiveHighlight ) {
+ mActiveCellRect.set ( xPos, mPaddingTop + 1, xPos
+ + itemTotalWidth, getHeight() - mPaddingBottom - 1 );
+ mActiveCellDrawable.setBounds ( ( int ) mActiveCellRect.left,
+ ( int ) mActiveCellRect.top, ( int ) mActiveCellRect.right,
+ ( int ) mActiveCellRect.bottom );
+ mActiveCellDrawable.draw ( canvas );
+ }
+ if ( mCandRects.size() < pSize ) { mCandRects.add ( new RectF() ); }
+ mCandRects.elementAt ( i ).set ( xPos - 1, yPos + mFmiCandidates.top,
+ xPos + itemTotalWidth + 1, yPos + mFmiCandidates.bottom );
+ // Draw footnote
+ if ( mShowFootnote ) {
+ canvas.drawText ( footnote, xPos + ( candMargin - footnoteSize )
+ / 2, yPos, mFootnotePaint );
+ }
+ // Left margin
+ xPos += candMargin;
+ if ( candidateWidth > mContentWidth - xPos - centerOffset ) {
+ cand = getLimitedCandidateForDrawing ( cand,
+ mContentWidth - xPos - centerOffset );
+ }
+ if ( mActiveCandInPage == i && mEnableActiveHighlight ) {
+ mCandidatesPaint.setColor ( mActiveCandidateColor );
+ } else {
+ mCandidatesPaint.setColor ( mNormalCandidateColor );
+ }
+ canvas.drawText ( cand, xPos + centerOffset, yPos,
+ mCandidatesPaint );
+ // Candidate and right margin
+ xPos += candidateWidth + candMargin;
+ // Draw the separator between candidates.
+ xPos += drawVerticalSeparator ( canvas, xPos );
+ }
+ // Update the arrow status of the container.
+ if ( null != mArrowUpdater && mUpdateArrowStatusWhenDraw ) {
+ mArrowUpdater.updateArrowStatus();
+ mUpdateArrowStatusWhenDraw = false;
+ }
+ }
+
+ private String getLimitedCandidateForDrawing ( String rawCandidate,
+ float widthToDraw ) {
+ int subLen = rawCandidate.length();
+ if ( subLen <= 1 ) { return rawCandidate; }
+ do {
+ subLen--;
+ float width = mCandidatesPaint.measureText ( rawCandidate, 0, subLen );
+ if ( width + mSuspensionPointsWidth <= widthToDraw || 1 >= subLen ) {
+ return rawCandidate.substring ( 0, subLen ) +
+ SUSPENSION_POINTS;
+ }
+ } while ( true );
+ }
+
+ private float drawVerticalSeparator ( Canvas canvas, float xPos ) {
+ mSeparatorDrawable.setBounds ( ( int ) xPos, mPaddingTop, ( int ) xPos
+ + mSeparatorDrawable.getIntrinsicWidth(), getMeasuredHeight()
+ - mPaddingBottom );
+ mSeparatorDrawable.draw ( canvas );
+ return mSeparatorDrawable.getIntrinsicWidth();
+ }
+
+ private int mapToItemInPage ( int x, int y ) {
+ // mCandRects.size() == 0 happens when the page is set, but
+ // touch events occur before onDraw(). It usually happens with
+ // monkey test.
+ if ( !mDecInfo.pageReady ( mPageNo ) || mPageNoCalculated != mPageNo
+ || mCandRects.size() == 0 ) {
+ return -1;
+ }
+ int pageStart = mDecInfo.mPageStart.get ( mPageNo );
+ int pageSize = mDecInfo.mPageStart.get ( mPageNo + 1 ) - pageStart;
+ if ( mCandRects.size() < pageSize ) {
+ return -1;
+ }
+ // If not found, try to find the nearest one.
+ float nearestDis = Float.MAX_VALUE;
+ int nearest = -1;
+ for ( int i = 0; i < pageSize; i++ ) {
+ RectF r = mCandRects.elementAt ( i );
+ if ( r.left < x && r.right > x && r.top < y && r.bottom > y ) {
+ return i;
+ }
+ float disx = ( r.left + r.right ) / 2 - x;
+ float disy = ( r.top + r.bottom ) / 2 - y;
+ float dis = disx * disx + disy * disy;
+ if ( dis < nearestDis ) {
+ nearestDis = dis;
+ nearest = i;
+ }
+ }
+ return nearest;
+ }
+
+ // Because the candidate view under the current focused one may also get
+ // touching events. Here we just bypass the event to the container and let
+ // it decide which view should handle the event.
+ @Override
+ public boolean onTouchEvent ( MotionEvent event ) {
+ return super.onTouchEvent ( event );
+ }
+
+ public boolean onTouchEventReal ( MotionEvent event ) {
+ // The page in the background can also be touched.
+ if ( null == mDecInfo || !mDecInfo.pageReady ( mPageNo )
+ || mPageNoCalculated != mPageNo ) { return true; }
+ int x, y;
+ x = ( int ) event.getX();
+ y = ( int ) event.getY();
+ if ( mGestureDetector.onTouchEvent ( event ) ) {
+ mTimer.removeTimer();
+ mBalloonHint.delayedDismiss ( 0 );
+ return true;
+ }
+ int clickedItemInPage = -1;
+ switch ( event.getAction() ) {
+ case MotionEvent.ACTION_UP:
+ clickedItemInPage = mapToItemInPage ( x, y );
+ if ( clickedItemInPage >= 0 ) {
+ invalidate();
+ mCvListener.onClickChoice ( clickedItemInPage
+ + mDecInfo.mPageStart.get ( mPageNo ) );
+ }
+ mBalloonHint.delayedDismiss ( BalloonHint.TIME_DELAY_DISMISS );
+ break;
+ case MotionEvent.ACTION_DOWN:
+ clickedItemInPage = mapToItemInPage ( x, y );
+ if ( clickedItemInPage >= 0 ) {
+ showBalloon ( clickedItemInPage, true );
+ mTimer.startTimer ( BalloonHint.TIME_DELAY_SHOW, mPageNo,
+ clickedItemInPage );
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ break;
+ case MotionEvent.ACTION_MOVE:
+ clickedItemInPage = mapToItemInPage ( x, y );
+ if ( clickedItemInPage >= 0
+ && ( clickedItemInPage != mTimer.getActiveCandOfPageToShow() || mPageNo != mTimer
+ .getPageToShow() ) ) {
+ showBalloon ( clickedItemInPage, true );
+ mTimer.startTimer ( BalloonHint.TIME_DELAY_SHOW, mPageNo,
+ clickedItemInPage );
+ }
+ }
+ return true;
+ }
+
+ private void showBalloon ( int candPos, boolean delayedShow ) {
+ mBalloonHint.removeTimer();
+ RectF r = mCandRects.elementAt ( candPos );
+ int desired_width = ( int ) ( r.right - r.left );
+ int desired_height = ( int ) ( r.bottom - r.top );
+ mBalloonHint.setBalloonConfig ( mDecInfo.mCandidatesList
+ .get ( mDecInfo.mPageStart.get ( mPageNo ) + candPos ), 44, true,
+ mImeCandidateColor, desired_width, desired_height );
+ getLocationOnScreen ( mLocationTmp );
+ mHintPositionToInputView[0] = mLocationTmp[0]
+ + ( int ) ( r.left - ( mBalloonHint.getWidth() - desired_width ) / 2 );
+ mHintPositionToInputView[1] = -mBalloonHint.getHeight();
+ long delay = BalloonHint.TIME_DELAY_SHOW;
+ if ( !delayedShow ) { delay = 0; }
+ mBalloonHint.dismiss();
+ if ( !mBalloonHint.isShowing() ) {
+ mBalloonHint.delayedShow ( delay, mHintPositionToInputView );
+ } else {
+ mBalloonHint.delayedUpdate ( 0, mHintPositionToInputView, -1, -1 );
+ }
+ }
+
+ private class PressTimer extends Handler implements Runnable {
+ private boolean mTimerPending = false;
+ private int mPageNoToShow;
+ private int mActiveCandOfPage;
+
+ public PressTimer() {
+ super();
+ }
+
+ public void startTimer ( long afterMillis, int pageNo, int activeInPage ) {
+ mTimer.removeTimer();
+ postDelayed ( this, afterMillis );
+ mTimerPending = true;
+ mPageNoToShow = pageNo;
+ mActiveCandOfPage = activeInPage;
+ }
+
+ public int getPageToShow() {
+ return mPageNoToShow;
+ }
+
+ public int getActiveCandOfPageToShow() {
+ return mActiveCandOfPage;
+ }
+
+ public boolean removeTimer() {
+ if ( mTimerPending ) {
+ mTimerPending = false;
+ removeCallbacks ( this );
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isPending() {
+ return mTimerPending;
+ }
+
+ public void run() {
+ if ( mPageNoToShow >= 0 && mActiveCandOfPage >= 0 ) {
+ // Always enable to highlight the clicked one.
+ showPage ( mPageNoToShow, mActiveCandOfPage, true );
+ invalidate();
+ }
+ mTimerPending = false;
+ }
+ }
+}
diff --git a/src/com/amlogic/inputmethod/remote/CandidateViewListener.java b/src/com/droidlogic/inputmethod/remote/CandidateViewListener.java
index 9eb2580..fb3237b 100755..100644
--- a/src/com/amlogic/inputmethod/remote/CandidateViewListener.java
+++ b/src/com/droidlogic/inputmethod/remote/CandidateViewListener.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.amlogic.inputmethod.remote;
+package com.droidlogic.inputmethod.remote;
/**
* Interface to notify the input method when the user clicks a candidate or
* makes a direction-gesture on candidate view.
*/
public interface CandidateViewListener {
- public void onClickChoice(int choiceId);
+ public void onClickChoice ( int choiceId );
public void onToLeftGesture();
diff --git a/src/com/droidlogic/inputmethod/remote/CandidatesContainer.java b/src/com/droidlogic/inputmethod/remote/CandidatesContainer.java
new file mode 100644
index 0000000..2d4b6e5
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/CandidatesContainer.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import com.droidlogic.inputmethod.remote.RemoteIME.DecodingInfo;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.TranslateAnimation;
+import android.view.animation.Animation.AnimationListener;
+import android.widget.ImageButton;
+import android.widget.RelativeLayout;
+import android.widget.ViewFlipper;
+
+interface ArrowUpdater {
+ void updateArrowStatus();
+}
+
+
+/**
+ * Container used to host the two candidate views. When user drags on candidate
+ * view, animation is used to dismiss the current candidate view and show a new
+ * one. These two candidate views and their parent are hosted by this container.
+ * <p>
+ * Besides the candidate views, there are two arrow views to show the page
+ * forward/backward arrows.
+ * </p>
+ */
+public class CandidatesContainer extends RelativeLayout implements
+ OnTouchListener, AnimationListener, ArrowUpdater {
+ /**
+ * Alpha value to show an enabled arrow.
+ */
+ private static int ARROW_ALPHA_ENABLED = 0xff;
+
+ /**
+ * Alpha value to show an disabled arrow.
+ */
+ private static int ARROW_ALPHA_DISABLED = 0x40;
+
+ /**
+ * Animation time to show a new candidate view and dismiss the old one.
+ */
+ private static int ANIMATION_TIME = 200;
+
+ /**
+ * Listener used to notify IME that user clicks a candidate, or navigate
+ * between them.
+ */
+ private CandidateViewListener mCvListener;
+
+ /**
+ * The left arrow button used to show previous page.
+ */
+ private ImageButton mLeftArrowBtn;
+
+ /**
+ * The right arrow button used to show next page.
+ */
+ private ImageButton mRightArrowBtn;
+
+ /**
+ * Decoding result to show.
+ */
+ private DecodingInfo mDecInfo;
+
+ /**
+ * The animation view used to show candidates. It contains two views.
+ * Normally, the candidates are shown one of them. When user navigates to
+ * another page, animation effect will be performed.
+ */
+ private ViewFlipper mFlipper;
+
+ /**
+ * The x offset of the flipper in this container.
+ */
+ private int xOffsetForFlipper;
+
+ /**
+ * Animation used by the incoming view when the user navigates to a left
+ * page.
+ */
+ private Animation mInAnimPushLeft;
+
+ /**
+ * Animation used by the incoming view when the user navigates to a right
+ * page.
+ */
+ private Animation mInAnimPushRight;
+
+ /**
+ * Animation used by the incoming view when the user navigates to a page
+ * above. If the page navigation is triggered by DOWN key, this animation is
+ * used.
+ */
+ private Animation mInAnimPushUp;
+
+ /**
+ * Animation used by the incoming view when the user navigates to a page
+ * below. If the page navigation is triggered by UP key, this animation is
+ * used.
+ */
+ private Animation mInAnimPushDown;
+
+ /**
+ * Animation used by the outgoing view when the user navigates to a left
+ * page.
+ */
+ private Animation mOutAnimPushLeft;
+
+ /**
+ * Animation used by the outgoing view when the user navigates to a right
+ * page.
+ */
+ private Animation mOutAnimPushRight;
+
+ /**
+ * Animation used by the outgoing view when the user navigates to a page
+ * above. If the page navigation is triggered by DOWN key, this animation is
+ * used.
+ */
+ private Animation mOutAnimPushUp;
+
+ /**
+ * Animation used by the incoming view when the user navigates to a page
+ * below. If the page navigation is triggered by UP key, this animation is
+ * used.
+ */
+ private Animation mOutAnimPushDown;
+
+ /**
+ * Animation object which is used for the incoming view currently.
+ */
+ private Animation mInAnimInUse;
+
+ /**
+ * Animation object which is used for the outgoing view currently.
+ */
+ private Animation mOutAnimInUse;
+
+ /**
+ * Current page number in display.
+ */
+ private int mCurrentPage = -1;
+
+ public CandidatesContainer ( Context context, AttributeSet attrs ) {
+ super ( context, attrs );
+ }
+
+ public void initialize ( CandidateViewListener cvListener,
+ BalloonHint balloonHint, GestureDetector gestureDetector ) {
+ mCvListener = cvListener;
+ mLeftArrowBtn = ( ImageButton ) findViewById ( R.id.arrow_left_btn );
+ mRightArrowBtn = ( ImageButton ) findViewById ( R.id.arrow_right_btn );
+ mLeftArrowBtn.setOnTouchListener ( this );
+ mRightArrowBtn.setOnTouchListener ( this );
+ mFlipper = ( ViewFlipper ) findViewById ( R.id.candidate_flipper );
+ mFlipper.setMeasureAllChildren ( true );
+ invalidate();
+ requestLayout();
+ for ( int i = 0; i < mFlipper.getChildCount(); i++ ) {
+ CandidateView cv = ( CandidateView ) mFlipper.getChildAt ( i );
+ cv.initialize ( this, balloonHint, gestureDetector, mCvListener );
+ }
+ }
+
+ public void showCandidates ( RemoteIME.DecodingInfo decInfo,
+ boolean enableActiveHighlight ) {
+ if ( null == decInfo ) { return; }
+ mDecInfo = decInfo;
+ mCurrentPage = 0;
+ if ( decInfo.isCandidatesListEmpty() ) {
+ showArrow ( mLeftArrowBtn, false );
+ showArrow ( mRightArrowBtn, false );
+ } else {
+ showArrow ( mLeftArrowBtn, true );
+ showArrow ( mRightArrowBtn, true );
+ }
+ for ( int i = 0; i < mFlipper.getChildCount(); i++ ) {
+ CandidateView cv = ( CandidateView ) mFlipper.getChildAt ( i );
+ cv.setDecodingInfo ( mDecInfo );
+ }
+ stopAnimation();
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ cv.showPage ( mCurrentPage, 0, enableActiveHighlight );
+ updateArrowStatus();
+ invalidate();
+ }
+
+ public int getCurrentPage() {
+ return mCurrentPage;
+ }
+
+ public void enableActiveHighlight ( boolean enableActiveHighlight ) {
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ cv.enableActiveHighlight ( enableActiveHighlight );
+ invalidate();
+ }
+
+ @Override
+ protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) {
+ Environment env = Environment.getInstance();
+ int measuredWidth = env.getScreenWidth();
+ int measuredHeight = getPaddingTop();
+ measuredHeight += env.getHeightForCandidates();
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec ( measuredWidth,
+ MeasureSpec.EXACTLY );
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec ( measuredHeight,
+ MeasureSpec.EXACTLY );
+ super.onMeasure ( widthMeasureSpec, heightMeasureSpec );
+ if ( null != mLeftArrowBtn ) {
+ xOffsetForFlipper = mLeftArrowBtn.getMeasuredWidth();
+ }
+ }
+
+ public boolean activeCurseBackward() {
+ if ( mFlipper.isFlipping() || null == mDecInfo ) {
+ return false;
+ }
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ if ( cv.activeCurseBackward() ) {
+ cv.invalidate();
+ return true;
+ } else {
+ return pageBackward ( true, true );
+ }
+ }
+
+ public boolean activeCurseForward() {
+ if ( mFlipper.isFlipping() || null == mDecInfo ) {
+ return false;
+ }
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ if ( cv.activeCursorForward() ) {
+ cv.invalidate();
+ return true;
+ } else {
+ return pageForward ( true, true );
+ }
+ }
+
+ public boolean pageBackward ( boolean animLeftRight,
+ boolean enableActiveHighlight ) {
+ if ( null == mDecInfo ) { return false; }
+ if ( mFlipper.isFlipping() || 0 == mCurrentPage ) { return false; }
+ int child = mFlipper.getDisplayedChild();
+ int childNext = ( child + 1 ) % 2;
+ CandidateView cv = ( CandidateView ) mFlipper.getChildAt ( child );
+ CandidateView cvNext = ( CandidateView ) mFlipper.getChildAt ( childNext );
+ mCurrentPage--;
+ int activeCandInPage = cv.getActiveCandiatePosInPage();
+ if ( animLeftRight )
+ activeCandInPage = mDecInfo.mPageStart.elementAt ( mCurrentPage + 1 )
+ - mDecInfo.mPageStart.elementAt ( mCurrentPage ) - 1;
+ cvNext.showPage ( mCurrentPage, activeCandInPage, enableActiveHighlight );
+ loadAnimation ( animLeftRight, false );
+ startAnimation();
+ updateArrowStatus();
+ return true;
+ }
+
+ public boolean pageForward ( boolean animLeftRight,
+ boolean enableActiveHighlight ) {
+ if ( null == mDecInfo ) { return false; }
+ if ( mFlipper.isFlipping() || !mDecInfo.preparePage ( mCurrentPage + 1 ) ) {
+ return false;
+ }
+ int child = mFlipper.getDisplayedChild();
+ int childNext = ( child + 1 ) % 2;
+ CandidateView cv = ( CandidateView ) mFlipper.getChildAt ( child );
+ int activeCandInPage = cv.getActiveCandiatePosInPage();
+ cv.enableActiveHighlight ( enableActiveHighlight );
+ CandidateView cvNext = ( CandidateView ) mFlipper.getChildAt ( childNext );
+ mCurrentPage++;
+ if ( animLeftRight ) { activeCandInPage = 0; }
+ cvNext.showPage ( mCurrentPage, activeCandInPage, enableActiveHighlight );
+ loadAnimation ( animLeftRight, true );
+ startAnimation();
+ updateArrowStatus();
+ return true;
+ }
+
+ public int getActiveCandiatePos() {
+ if ( null == mDecInfo ) { return -1; }
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ return cv.getActiveCandiatePosGlobal();
+ }
+
+ public void updateArrowStatus() {
+ if ( mCurrentPage < 0 ) { return; }
+ boolean forwardEnabled = mDecInfo.pageForwardable ( mCurrentPage );
+ boolean backwardEnabled = mDecInfo.pageBackwardable ( mCurrentPage );
+ if ( backwardEnabled ) {
+ enableArrow ( mLeftArrowBtn, true );
+ } else {
+ enableArrow ( mLeftArrowBtn, false );
+ }
+ if ( forwardEnabled ) {
+ enableArrow ( mRightArrowBtn, true );
+ } else {
+ enableArrow ( mRightArrowBtn, false );
+ }
+ }
+
+ private void enableArrow ( ImageButton arrowBtn, boolean enabled ) {
+ arrowBtn.setEnabled ( enabled );
+ if ( enabled ) {
+ arrowBtn.setAlpha ( ARROW_ALPHA_ENABLED );
+ } else {
+ arrowBtn.setAlpha ( ARROW_ALPHA_DISABLED );
+ }
+ }
+
+ private void showArrow ( ImageButton arrowBtn, boolean show ) {
+ if ( show ) {
+ arrowBtn.setVisibility ( View.VISIBLE );
+ } else {
+ arrowBtn.setVisibility ( View.INVISIBLE );
+ }
+ }
+
+ public boolean onTouch ( View v, MotionEvent event ) {
+ if ( event.getAction() == MotionEvent.ACTION_DOWN ) {
+ if ( v == mLeftArrowBtn ) {
+ mCvListener.onToRightGesture();
+ } else if ( v == mRightArrowBtn ) {
+ mCvListener.onToLeftGesture();
+ }
+ } else if ( event.getAction() == MotionEvent.ACTION_UP ) {
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ cv.enableActiveHighlight ( true );
+ }
+ return false;
+ }
+
+ // The reason why we handle candiate view's touch events here is because
+ // that the view under the focused view may get touch events instead of the
+ // focused one.
+ @Override
+ public boolean onTouchEvent ( MotionEvent event ) {
+ event.offsetLocation ( -xOffsetForFlipper, 0 );
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ cv.onTouchEventReal ( event );
+ return true;
+ }
+
+ public void loadAnimation ( boolean animLeftRight, boolean forward ) {
+ if ( animLeftRight ) {
+ if ( forward ) {
+ if ( null == mInAnimPushLeft ) {
+ mInAnimPushLeft = createAnimation ( 1.0f, 0, 0, 0, 0, 1.0f,
+ ANIMATION_TIME );
+ mOutAnimPushLeft = createAnimation ( 0, -1.0f, 0, 0, 1.0f, 0,
+ ANIMATION_TIME );
+ }
+ mInAnimInUse = mInAnimPushLeft;
+ mOutAnimInUse = mOutAnimPushLeft;
+ } else {
+ if ( null == mInAnimPushRight ) {
+ mInAnimPushRight = createAnimation ( -1.0f, 0, 0, 0, 0, 1.0f,
+ ANIMATION_TIME );
+ mOutAnimPushRight = createAnimation ( 0, 1.0f, 0, 0, 1.0f, 0,
+ ANIMATION_TIME );
+ }
+ mInAnimInUse = mInAnimPushRight;
+ mOutAnimInUse = mOutAnimPushRight;
+ }
+ } else {
+ if ( forward ) {
+ if ( null == mInAnimPushUp ) {
+ mInAnimPushUp = createAnimation ( 0, 0, 1.0f, 0, 0, 1.0f,
+ ANIMATION_TIME );
+ mOutAnimPushUp = createAnimation ( 0, 0, 0, -1.0f, 1.0f, 0,
+ ANIMATION_TIME );
+ }
+ mInAnimInUse = mInAnimPushUp;
+ mOutAnimInUse = mOutAnimPushUp;
+ } else {
+ if ( null == mInAnimPushDown ) {
+ mInAnimPushDown = createAnimation ( 0, 0, -1.0f, 0, 0, 1.0f,
+ ANIMATION_TIME );
+ mOutAnimPushDown = createAnimation ( 0, 0, 0, 1.0f, 1.0f, 0,
+ ANIMATION_TIME );
+ }
+ mInAnimInUse = mInAnimPushDown;
+ mOutAnimInUse = mOutAnimPushDown;
+ }
+ }
+ mInAnimInUse.setAnimationListener ( this );
+ mFlipper.setInAnimation ( mInAnimInUse );
+ mFlipper.setOutAnimation ( mOutAnimInUse );
+ }
+
+ private Animation createAnimation ( float xFrom, float xTo, float yFrom,
+ float yTo, float alphaFrom, float alphaTo, long duration ) {
+ AnimationSet animSet = new AnimationSet ( getContext(), null );
+ Animation trans = new TranslateAnimation ( Animation.RELATIVE_TO_SELF,
+ xFrom, Animation.RELATIVE_TO_SELF, xTo,
+ Animation.RELATIVE_TO_SELF, yFrom, Animation.RELATIVE_TO_SELF,
+ yTo );
+ Animation alpha = new AlphaAnimation ( alphaFrom, alphaTo );
+ animSet.addAnimation ( trans );
+ animSet.addAnimation ( alpha );
+ animSet.setDuration ( duration );
+ return animSet;
+ }
+
+ private void startAnimation() {
+ mFlipper.showNext();
+ }
+
+ private void stopAnimation() {
+ mFlipper.stopFlipping();
+ }
+
+ public void onAnimationEnd ( Animation animation ) {
+ if ( !mLeftArrowBtn.isPressed() && !mRightArrowBtn.isPressed() ) {
+ CandidateView cv = ( CandidateView ) mFlipper.getCurrentView();
+ cv.enableActiveHighlight ( true );
+ }
+ }
+
+ public void onAnimationRepeat ( Animation animation ) {
+ }
+
+ public void onAnimationStart ( Animation animation ) {
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/ComposingView.java b/src/com/droidlogic/inputmethod/remote/ComposingView.java
new file mode 100644
index 0000000..3366776
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/ComposingView.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * View used to show composing string (The Pinyin string for the unselected
+ * syllables and the Chinese string for the selected syllables.)
+ */
+public class ComposingView extends View {
+ /**
+ * <p>
+ * There are three statuses for the composing view.
+ * </p>
+ *
+ * <p>
+ * {@link #SHOW_PINYIN} is used to show the current Pinyin string without
+ * highlighted effect. When user inputs Pinyin characters one by one, the
+ * Pinyin string will be shown in this mode.
+ * </p>
+ * <p>
+ * {@link #SHOW_STRING_LOWERCASE} is used to show the Pinyin string in
+ * lowercase with highlighted effect. When user presses UP key and there is
+ * no fixed Chinese characters, composing view will switch from
+ * {@link #SHOW_PINYIN} to this mode, and in this mode, user can press
+ * confirm key to input the lower-case string, so that user can input
+ * English letter in Chinese mode.
+ * </p>
+ * <p>
+ * {@link #EDIT_PINYIN} is used to edit the Pinyin string (shown with
+ * highlighted effect). When current status is {@link #SHOW_PINYIN} and user
+ * presses UP key, if there are fixed Characters, the input method will
+ * switch to {@link #EDIT_PINYIN} thus user can modify some characters in
+ * the middle of the Pinyin string. If the current status is
+ * {@link #SHOW_STRING_LOWERCASE} and user presses LEFT and RIGHT key, it
+ * will also switch to {@link #EDIT_PINYIN}.
+ * </p>
+ * <p>
+ * Whenever user presses down key, the status switches to
+ * {@link #SHOW_PINYIN}.
+ * </p>
+ * <p>
+ * When composing view's status is {@link #SHOW_PINYIN}, the IME's status is
+ * {@link RemoteIME.ImeState#STATE_INPUT}, otherwise, the IME's status
+ * should be {@link RemoteIME.ImeState#STATE_COMPOSING}.
+ * </p>
+ */
+ public enum ComposingStatus {
+ SHOW_PINYIN, SHOW_STRING_LOWERCASE, EDIT_PINYIN,
+ }
+
+ private static final int LEFT_RIGHT_MARGIN = 5;
+
+ /**
+ * Used to draw composing string. When drawing the active and idle part of
+ * the spelling(Pinyin) string, the color may be changed.
+ */
+ private Paint mPaint;
+
+ /**
+ * Drawable used to draw highlight effect.
+ */
+ private Drawable mHlDrawable;
+
+ /**
+ * Drawable used to draw cursor for editing mode.
+ */
+ private Drawable mCursor;
+
+ /**
+ * Used to estimate dimensions to show the string .
+ */
+ private FontMetricsInt mFmi;
+
+ private int mStrColor;
+ private int mStrColorHl;
+ private int mStrColorIdle;
+
+ private int mFontSize;
+
+ private ComposingStatus mComposingStatus;
+
+ RemoteIME.DecodingInfo mDecInfo;
+
+ public ComposingView ( Context context, AttributeSet attrs ) {
+ super ( context, attrs );
+ Resources r = context.getResources();
+ mHlDrawable = r.getDrawable ( R.drawable.composing_hl_bg );
+ mCursor = r.getDrawable ( R.drawable.composing_area_cursor );
+ mStrColor = r.getColor ( R.color.composing_color );
+ mStrColorHl = r.getColor ( R.color.composing_color_hl );
+ mStrColorIdle = r.getColor ( R.color.composing_color_idle );
+ mFontSize = r.getDimensionPixelSize ( R.dimen.composing_height );
+ mPaint = new Paint();
+ mPaint.setColor ( mStrColor );
+ mPaint.setAntiAlias ( true );
+ mPaint.setTextSize ( mFontSize );
+ mFmi = mPaint.getFontMetricsInt();
+ }
+
+ public void reset() {
+ mComposingStatus = ComposingStatus.SHOW_PINYIN;
+ }
+
+ /**
+ * Set the composing string to show. If the IME status is
+ * {@link RemoteIME.ImeState#STATE_INPUT}, the composing view's status will
+ * be set to {@link ComposingStatus#SHOW_PINYIN}, otherwise the composing
+ * view will set its status to {@link ComposingStatus#SHOW_STRING_LOWERCASE}
+ * or {@link ComposingStatus#EDIT_PINYIN} automatically.
+ */
+ public void setDecodingInfo ( RemoteIME.DecodingInfo decInfo,
+ RemoteIME.ImeState imeStatus ) {
+ mDecInfo = decInfo;
+ if ( RemoteIME.ImeState.STATE_INPUT == imeStatus ) {
+ mComposingStatus = ComposingStatus.SHOW_PINYIN;
+ mDecInfo.moveCursorToEdge ( false );
+ } else {
+ if ( decInfo.getFixedLen() != 0
+ || ComposingStatus.EDIT_PINYIN == mComposingStatus ) {
+ mComposingStatus = ComposingStatus.EDIT_PINYIN;
+ } else {
+ mComposingStatus = ComposingStatus.SHOW_STRING_LOWERCASE;
+ }
+ mDecInfo.moveCursor ( 0 );
+ }
+ measure ( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT );
+ requestLayout();
+ invalidate();
+ }
+
+ public boolean moveCursor ( int keyCode ) {
+ if ( keyCode != KeyEvent.KEYCODE_DPAD_LEFT
+ && keyCode != KeyEvent.KEYCODE_DPAD_RIGHT ) { return false; }
+ if ( ComposingStatus.EDIT_PINYIN == mComposingStatus ) {
+ int offset = 0;
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
+ offset = -1;
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) { offset = 1; }
+ mDecInfo.moveCursor ( offset );
+ } else if ( ComposingStatus.SHOW_STRING_LOWERCASE == mComposingStatus ) {
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+ || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ mComposingStatus = ComposingStatus.EDIT_PINYIN;
+ measure ( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT );
+ requestLayout();
+ }
+ }
+ invalidate();
+ return true;
+ }
+
+ public ComposingStatus getComposingStatus() {
+ return mComposingStatus;
+ }
+
+ @Override
+ protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) {
+ float width;
+ int height;
+ height = mFmi.bottom - mFmi.top + mPaddingTop + mPaddingBottom;
+ if ( null == mDecInfo ) {
+ width = 0;
+ } else {
+ width = mPaddingLeft + mPaddingRight + LEFT_RIGHT_MARGIN * 2;
+ String str;
+ if ( ComposingStatus.SHOW_STRING_LOWERCASE == mComposingStatus ) {
+ str = mDecInfo.getOrigianlSplStr().toString();
+ } else {
+ str = mDecInfo.getComposingStrForDisplay();
+ }
+ width += mPaint.measureText ( str, 0, str.length() );
+ }
+ setMeasuredDimension ( ( int ) ( width + 0.5f ), height );
+ }
+
+ @Override
+ protected void onDraw ( Canvas canvas ) {
+ if ( ComposingStatus.EDIT_PINYIN == mComposingStatus
+ || ComposingStatus.SHOW_PINYIN == mComposingStatus ) {
+ drawForPinyin ( canvas );
+ return;
+ }
+ float x, y;
+ x = mPaddingLeft + LEFT_RIGHT_MARGIN;
+ y = -mFmi.top + mPaddingTop;
+ mPaint.setColor ( mStrColorHl );
+ mHlDrawable.setBounds ( mPaddingLeft, mPaddingTop, getWidth()
+ - mPaddingRight, getHeight() - mPaddingBottom );
+ mHlDrawable.draw ( canvas );
+ String splStr = mDecInfo.getOrigianlSplStr().toString();
+ canvas.drawText ( splStr, 0, splStr.length(), x, y, mPaint );
+ }
+
+ private void drawCursor ( Canvas canvas, float x ) {
+ mCursor.setBounds ( ( int ) x, mPaddingTop, ( int ) x
+ + mCursor.getIntrinsicWidth(), getHeight() - mPaddingBottom );
+ mCursor.draw ( canvas );
+ }
+
+ private void drawForPinyin ( Canvas canvas ) {
+ float x, y;
+ x = mPaddingLeft + LEFT_RIGHT_MARGIN;
+ y = -mFmi.top + mPaddingTop;
+ mPaint.setColor ( mStrColor );
+ int cursorPos = mDecInfo.getCursorPosInCmpsDisplay();
+ int cmpsPos = cursorPos;
+ String cmpsStr = mDecInfo.getComposingStrForDisplay();
+ int activeCmpsLen = mDecInfo.getActiveCmpsDisplayLen();
+ if ( cursorPos > activeCmpsLen ) { cmpsPos = activeCmpsLen; }
+ canvas.drawText ( cmpsStr, 0, cmpsPos, x, y, mPaint );
+ x += mPaint.measureText ( cmpsStr, 0, cmpsPos );
+ if ( cursorPos <= activeCmpsLen ) {
+ if ( ComposingStatus.EDIT_PINYIN == mComposingStatus ) {
+ drawCursor ( canvas, x );
+ }
+ canvas.drawText ( cmpsStr, cmpsPos, activeCmpsLen, x, y, mPaint );
+ }
+ x += mPaint.measureText ( cmpsStr, cmpsPos, activeCmpsLen );
+ if ( cmpsStr.length() > activeCmpsLen ) {
+ mPaint.setColor ( mStrColorIdle );
+ int oriPos = activeCmpsLen;
+ if ( cursorPos > activeCmpsLen ) {
+ if ( cursorPos > cmpsStr.length() ) { cursorPos = cmpsStr.length(); }
+ canvas.drawText ( cmpsStr, oriPos, cursorPos, x, y, mPaint );
+ x += mPaint.measureText ( cmpsStr, oriPos, cursorPos );
+ if ( ComposingStatus.EDIT_PINYIN == mComposingStatus ) {
+ drawCursor ( canvas, x );
+ }
+ oriPos = cursorPos;
+ }
+ canvas.drawText ( cmpsStr, oriPos, cmpsStr.length(), x, y, mPaint );
+ }
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/EnglishInputProcessor.java b/src/com/droidlogic/inputmethod/remote/EnglishInputProcessor.java
new file mode 100644
index 0000000..208faae
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/EnglishInputProcessor.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.view.KeyEvent;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * Class to handle English input.
+ */
+public class EnglishInputProcessor {
+
+ private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+ private boolean mShiftTag = false;
+ public boolean processKey ( InputConnection inputContext, KeyEvent event,
+ boolean upperCase, boolean realAction ) {
+ if ( null == inputContext || null == event ) { return false; }
+ int keyCode = event.getKeyCode();
+ CharSequence prefix = null;
+ prefix = inputContext.getTextBeforeCursor ( 2, 0 );
+ if ( !realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT ) {
+ mShiftTag = true;
+ }
+ int keyChar;
+ keyChar = 0;
+ if ( keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z ) {
+ keyChar = keyCode - KeyEvent.KEYCODE_A + 'a';
+ if ( upperCase ) {
+ keyChar = keyChar + 'A' - 'a';
+ }
+ } else if ( keyCode >= KeyEvent.KEYCODE_0
+ && keyCode <= KeyEvent.KEYCODE_9 ) {
+ keyChar = keyCode - KeyEvent.KEYCODE_0 + '0';
+ if ( event.isShiftPressed() ) {
+ return false;
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_COMMA ) {
+ keyChar = ',';
+ } else if ( keyCode == KeyEvent.KEYCODE_PERIOD ) {
+ keyChar = '.';
+ } else if ( keyCode == KeyEvent.KEYCODE_APOSTROPHE ) {
+ keyChar = '\'';
+ } else if ( keyCode == KeyEvent.KEYCODE_AT ) {
+ keyChar = '@';
+ } else if ( keyCode == KeyEvent.KEYCODE_SLASH ) { keyChar = '/'; }
+ if ( mShiftTag ) {
+ keyChar = 0;
+ }
+ if ( 0 == keyChar ) {
+ mLastKeyCode = keyCode;
+ String insert = null;
+ if ( KeyEvent.KEYCODE_DEL == keyCode ) {
+ if ( realAction ) {
+ inputContext.deleteSurroundingText ( 1, 0 );
+ }
+ } else if ( KeyEvent.KEYCODE_ENTER == keyCode ) {
+ insert = "\n";
+ } else if ( KeyEvent.KEYCODE_SPACE == keyCode ) {
+ insert = " ";
+ } else {
+ if ( realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT ) {
+ mShiftTag = false;
+ mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+ }
+ return false;
+ }
+ if ( null != insert && realAction ) {
+ inputContext.commitText ( insert, insert.length() );
+ }
+ return true;
+ }
+ if ( !realAction ) {
+ return true;
+ }
+ if ( KeyEvent.KEYCODE_SHIFT_LEFT == mLastKeyCode
+ || KeyEvent.KEYCODE_SHIFT_LEFT == mLastKeyCode ) {
+ if ( keyChar >= 'a' && keyChar <= 'z' ) {
+ keyChar = keyChar - 'a' + 'A';
+ }
+ } else if ( KeyEvent.KEYCODE_ALT_LEFT == mLastKeyCode ) {
+ }
+ String result = String.valueOf ( ( char ) keyChar );
+ inputContext.commitText ( result, result.length() );
+ mLastKeyCode = keyCode;
+ return true;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/Environment.java b/src/com/droidlogic/inputmethod/remote/Environment.java
new file mode 100644
index 0000000..0ed312f
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/Environment.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.view.Display;
+import android.view.WindowManager;
+import com.droidlogic.app.SystemControlManager;
+
+/**
+ * Global environment configurations for showing soft keyboard and candidate
+ * view. All original dimension values are defined in float, and the real size
+ * is calculated from the float values of and screen size. In this way, this
+ * input method can work even when screen size is changed.
+ */
+public class Environment {
+ /**
+ * The key height for portrait mode. It is relative to the screen height.
+ */
+ private static final float KEY_HEIGHT_RATIO_PORTRAIT = 0.105f;
+
+ /**
+ * The key height for landscape mode. It is relative to the screen height.
+ */
+ private static final float KEY_HEIGHT_RATIO_LANDSCAPE = 0.063f;
+
+ /**
+ * The height of the candidates area for portrait mode. It is relative to
+ * screen height.
+ */
+ private static final float CANDIDATES_AREA_HEIGHT_RATIO_PORTRAIT = 0.084f;
+
+ /**
+ * The height of the candidates area for portrait mode. It is relative to
+ * screen height.
+ */
+ private static final float CANDIDATES_AREA_HEIGHT_RATIO_LANDSCAPE = 0.125f;
+
+ /**
+ * How much should the balloon width be larger than width of the real key.
+ * It is relative to the smaller one of screen width and height.
+ */
+ private static final float KEY_BALLOON_WIDTH_PLUS_RATIO = 0.08f;
+
+ /**
+ * How much should the balloon height be larger than that of the real key.
+ * It is relative to the smaller one of screen width and height.
+ */
+ private static final float KEY_BALLOON_HEIGHT_PLUS_RATIO = 0.08f;
+
+ /**
+ * The text size for normal keys. It is relative to the smaller one of
+ * screen width and height.
+ */
+ private static final float NORMAL_KEY_TEXT_SIZE_RATIO = 0.032f;
+
+ /**
+ * The text size for function keys. It is relative to the smaller one of
+ * screen width and height.
+ */
+ private static final float FUNCTION_KEY_TEXT_SIZE_RATIO = 0.024f;
+
+ /**
+ * The text size balloons of normal keys. It is relative to the smaller one
+ * of screen width and height.
+ */
+ private static final float NORMAL_BALLOON_TEXT_SIZE_RATIO = 0.12f;
+
+ /**
+ * The text size balloons of function keys. It is relative to the smaller
+ * one of screen width and height.
+ */
+ private static final float FUNCTION_BALLOON_TEXT_SIZE_RATIO = 0.085f;
+
+ /**
+ * The configurations are managed in a singleton.
+ */
+ private static Environment mInstance;
+
+ private int mScreenWidth;
+ private int mScreenHeight;
+ private int mKeyHeight;
+ private int mCandidatesAreaHeight;
+ private int mKeyBalloonWidthPlus;
+ private int mKeyBalloonHeightPlus;
+ private int mNormalKeyTextSize;
+ private int mFunctionKeyTextSize;
+ private int mNormalBalloonTextSize;
+ private int mFunctionBalloonTextSize;
+ private Configuration mConfig = new Configuration();
+ private boolean mDebug = false;
+
+ private Environment() {
+ }
+
+ public static Environment getInstance() {
+ if ( null == mInstance ) {
+ mInstance = new Environment();
+ }
+ return mInstance;
+ }
+
+ public void onConfigurationChanged ( Configuration newConfig, Context context ) {
+ //density and display-size will be change when switch outputmode between 1080 and 720, need to update configuration
+ SystemControlManager sw = new SystemControlManager ( context );
+ if ( ( mConfig.orientation != newConfig.orientation ) || ( sw.getPropertyBoolean ( "ro.platform.has.realoutputmode", false ) ) ) {
+ WindowManager wm = ( WindowManager ) context.getSystemService ( Context.WINDOW_SERVICE );
+ Display d = wm.getDefaultDisplay();
+ mScreenWidth = d.getWidth();
+ mScreenHeight = d.getHeight();
+ int scale;
+ if ( mScreenHeight > mScreenWidth ) {
+ mKeyHeight = ( int ) ( mScreenHeight * KEY_HEIGHT_RATIO_PORTRAIT );
+ mCandidatesAreaHeight = ( int ) ( mScreenHeight * CANDIDATES_AREA_HEIGHT_RATIO_PORTRAIT );
+ scale = mScreenWidth;
+ } else {
+ mKeyHeight = ( int ) ( mScreenHeight * KEY_HEIGHT_RATIO_LANDSCAPE );
+ mCandidatesAreaHeight = ( int ) ( mScreenHeight * CANDIDATES_AREA_HEIGHT_RATIO_LANDSCAPE );
+ scale = mScreenHeight;
+ }
+ mNormalKeyTextSize = ( int ) ( scale * NORMAL_KEY_TEXT_SIZE_RATIO );
+ mFunctionKeyTextSize = ( int ) ( scale * FUNCTION_KEY_TEXT_SIZE_RATIO );
+ mNormalBalloonTextSize = ( int ) ( scale * NORMAL_BALLOON_TEXT_SIZE_RATIO );
+ mFunctionBalloonTextSize = ( int ) ( scale * FUNCTION_BALLOON_TEXT_SIZE_RATIO );
+ mKeyBalloonWidthPlus = ( int ) ( scale * KEY_BALLOON_WIDTH_PLUS_RATIO );
+ mKeyBalloonHeightPlus = ( int ) ( scale * KEY_BALLOON_HEIGHT_PLUS_RATIO );
+ }
+ mConfig.updateFrom ( newConfig );
+ }
+
+ public Configuration getConfiguration() {
+ return mConfig;
+ }
+
+ public int getScreenWidth() {
+ return mScreenWidth;
+ }
+
+ public int getScreenHeight() {
+ return mScreenHeight;
+ }
+
+ public int getHeightForCandidates() {
+ return mCandidatesAreaHeight;
+ }
+
+ public float getKeyXMarginFactor() {
+ return 1.0f;
+ }
+
+ public float getKeyYMarginFactor() {
+ if ( Configuration.ORIENTATION_LANDSCAPE == mConfig.orientation ) {
+ return 0.7f;
+ }
+ return 1.0f;
+ }
+
+ public int getKeyHeight() {
+ return mKeyHeight;
+ }
+
+ public int getKeyBalloonWidthPlus() {
+ return mKeyBalloonWidthPlus;
+ }
+
+ public int getKeyBalloonHeightPlus() {
+ return mKeyBalloonHeightPlus;
+ }
+
+ public int getSkbHeight() {
+ if ( Configuration.ORIENTATION_PORTRAIT == mConfig.orientation ) {
+ return mKeyHeight * 4;
+ } else if ( Configuration.ORIENTATION_LANDSCAPE == mConfig.orientation ) {
+ return mKeyHeight * 4;
+ }
+ return 0;
+ }
+
+ public int getKeyTextSize ( boolean isFunctionKey ) {
+ if ( isFunctionKey ) {
+ return mFunctionKeyTextSize;
+ } else {
+ return mNormalKeyTextSize;
+ }
+ }
+
+ public int getBalloonTextSize ( boolean isFunctionKey ) {
+ if ( isFunctionKey ) {
+ return mFunctionBalloonTextSize;
+ } else {
+ return mNormalBalloonTextSize;
+ }
+ }
+
+ public boolean hasHardKeyboard() {
+ if ( mConfig.keyboard == Configuration.KEYBOARD_NOKEYS
+ || mConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES ) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean needDebug() {
+ return mDebug;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/InputModeSwitcher.java b/src/com/droidlogic/inputmethod/remote/InputModeSwitcher.java
new file mode 100644
index 0000000..bea569e
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/InputModeSwitcher.java
@@ -0,0 +1,814 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import com.droidlogic.inputmethod.remote.SoftKeyboard.KeyRow;
+
+import android.content.res.Resources;
+import android.view.inputmethod.EditorInfo;
+
+import java.util.Locale;
+/**
+ * Switcher used to switching input mode between Chinese, English, symbol,etc.
+ */
+public class InputModeSwitcher {
+ /**
+ * User defined key code, used by soft keyboard.
+ */
+ private static final int USERDEF_KEYCODE_SHIFT_1 = -1;
+
+ /**
+ * User defined key code, used by soft keyboard.
+ */
+ private static final int USERDEF_KEYCODE_LANG_2 = -2;
+
+ /**
+ * User defined key code, used by soft keyboard.
+ */
+ private static final int USERDEF_KEYCODE_SYM_3 = -3;
+
+ /**
+ * User defined key code, used by soft keyboard.
+ */
+ public static final int USERDEF_KEYCODE_PHONE_SYM_4 = -4;
+
+ /**
+ * User defined key code, used by soft keyboard.
+ */
+ private static final int USERDEF_KEYCODE_MORE_SYM_5 = -5;
+
+ /**
+ * User defined key code, used by soft keyboard.
+ */
+ private static final int USERDEF_KEYCODE_SMILEY_6 = -6;
+
+
+ /**
+ * Bits used to indicate soft keyboard layout. If none bit is set, the
+ * current input mode does not require a soft keyboard.
+ **/
+ private static final int MASK_SKB_LAYOUT = 0xf0000000;
+
+ /**
+ * A kind of soft keyboard layout. An input mode should be anded with
+ * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
+ */
+ private static final int MASK_SKB_LAYOUT_QWERTY = 0x10000000;
+
+ /**
+ * A kind of soft keyboard layout. An input mode should be anded with
+ * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
+ */
+ private static final int MASK_SKB_LAYOUT_SYMBOL1 = 0x20000000;
+
+ /**
+ * A kind of soft keyboard layout. An input mode should be anded with
+ * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
+ */
+ private static final int MASK_SKB_LAYOUT_SYMBOL2 = 0x30000000;
+
+ /**
+ * A kind of soft keyboard layout. An input mode should be anded with
+ * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
+ */
+ private static final int MASK_SKB_LAYOUT_SMILEY = 0x40000000;
+
+ /**
+ * A kind of soft keyboard layout. An input mode should be anded with
+ * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
+ */
+ private static final int MASK_SKB_LAYOUT_PHONE = 0x50000000;
+
+ /**
+ * Used to indicate which language the current input mode is in. If the
+ * current input mode works with a none-QWERTY soft keyboard, these bits are
+ * also used to get language information. For example, a Chinese symbol soft
+ * keyboard and an English one are different in an icon which is used to
+ * tell user the language information. BTW, the smiley soft keyboard mode
+ * should be set with {@link #MASK_LANGUAGE_CN} because it can only be
+ * launched from Chinese QWERTY soft keyboard, and it has Chinese icon on
+ * soft keyboard.
+ */
+ private static final int MASK_LANGUAGE = 0x0f000000;
+
+ /**
+ * Used to indicate the current language. An input mode should be anded with
+ * {@link #MASK_LANGUAGE} to get this information.
+ */
+ private static final int MASK_LANGUAGE_CN = 0x01000000;
+
+ /**
+ * Used to indicate the current language. An input mode should be anded with
+ * {@link #MASK_LANGUAGE} to get this information.
+ */
+ private static final int MASK_LANGUAGE_EN = 0x02000000;
+
+ /**
+ * Used to indicate which case the current input mode is in. For example,
+ * English QWERTY has lowercase and uppercase. For the Chinese QWERTY, these
+ * bits are ignored. For phone keyboard layout, these bits can be
+ * {@link #MASK_CASE_UPPER} to request symbol page for phone soft keyboard.
+ */
+ private static final int MASK_CASE = 0x00f00000;
+
+ /**
+ * Used to indicate the current case information. An input mode should be
+ * anded with {@link #MASK_CASE} to get this information.
+ */
+ private static final int MASK_CASE_LOWER = 0x00100000;
+
+ /**
+ * Used to indicate the current case information. An input mode should be
+ * anded with {@link #MASK_CASE} to get this information.
+ */
+ private static final int MASK_CASE_UPPER = 0x00200000;
+
+ /**
+ * Mode for inputing English with soft keyboard.
+ */
+ public static final int MODE_SKB_ENGLISH = ( MASK_SKB_LAYOUT_QWERTY | MASK_LANGUAGE_EN );
+
+ /**
+ * Mode for inputing Chinese with soft keyboard.
+ */
+ public static final int MODE_SKB_CHINESE = ( MASK_SKB_LAYOUT_QWERTY | MASK_LANGUAGE_CN );
+
+ /**
+ * Mode for inputing basic symbols for Chinese mode with soft keyboard.
+ */
+ public static final int MODE_SKB_SYMBOL1_CN = ( MASK_SKB_LAYOUT_SYMBOL1 | MASK_LANGUAGE_CN );
+
+ /**
+ * Mode for inputing more symbols for Chinese mode with soft keyboard.
+ */
+ public static final int MODE_SKB_SYMBOL2_CN = ( MASK_SKB_LAYOUT_SYMBOL2 | MASK_LANGUAGE_CN );
+
+ /**
+ * Mode for inputing English lower characters with soft keyboard.
+ */
+ public static final int MODE_SKB_ENGLISH_LOWER = ( MASK_SKB_LAYOUT_QWERTY
+ | MASK_LANGUAGE_EN | MASK_CASE_LOWER );
+
+ /**
+ * Mode for inputing English upper characters with soft keyboard.
+ */
+ public static final int MODE_SKB_ENGLISH_UPPER = ( MASK_SKB_LAYOUT_QWERTY
+ | MASK_LANGUAGE_EN | MASK_CASE_UPPER );
+
+ /**
+ * Mode for inputing basic symbols for English mode with soft keyboard.
+ */
+ public static final int MODE_SKB_SYMBOL1_EN = ( MASK_SKB_LAYOUT_SYMBOL1 | MASK_LANGUAGE_EN );
+
+ /**
+ * Mode for inputing more symbols for English mode with soft keyboard.
+ */
+ public static final int MODE_SKB_SYMBOL2_EN = ( MASK_SKB_LAYOUT_SYMBOL2 | MASK_LANGUAGE_EN );
+
+ /**
+ * Mode for inputing smileys with soft keyboard.
+ */
+ public static final int MODE_SKB_SMILEY = ( MASK_SKB_LAYOUT_SMILEY | MASK_LANGUAGE_CN );
+
+ /**
+ * Mode for inputing phone numbers.
+ */
+ public static final int MODE_SKB_PHONE_NUM = ( MASK_SKB_LAYOUT_PHONE );
+
+ /**
+ * Mode for inputing phone numbers.
+ */
+ public static final int MODE_SKB_PHONE_SYM = ( MASK_SKB_LAYOUT_PHONE | MASK_CASE_UPPER );
+
+ /**
+ * Mode for inputing Chinese with a hardware keyboard.
+ */
+ public static final int MODE_HKB_CHINESE = ( MASK_LANGUAGE_CN );
+
+ /**
+ * Mode for inputing English with a hardware keyboard
+ */
+ public static final int MODE_HKB_ENGLISH = ( MASK_LANGUAGE_EN );
+
+ /**
+ * Unset mode.
+ */
+ public static final int MODE_UNSET = 0;
+
+ /**
+ * Maximum toggle states for a soft keyboard.
+ */
+ public static final int MAX_TOGGLE_STATES = 4;
+
+ /**
+ * The input mode for the current edit box.
+ */
+ private int mInputMode = MODE_UNSET;
+
+ /**
+ * Used to remember previous input mode. When user enters an edit field, the
+ * previous input mode will be tried. If the previous mode can not be used
+ * for the current situation (For example, previous mode is a soft keyboard
+ * mode to input symbols, and we have a hardware keyboard for the current
+ * situation), {@link #mRecentLauageInputMode} will be tried.
+ **/
+ private int mPreviousInputMode = MODE_SKB_CHINESE;
+
+ /**
+ * Used to remember recent mode to input language.
+ */
+ private int mRecentLauageInputMode = MODE_SKB_CHINESE;
+
+ /**
+ * Editor information of the current edit box.
+ */
+ private EditorInfo mEditorInfo;
+
+ /**
+ * Used to indicate required toggling operations.
+ */
+ private ToggleStates mToggleStates = new ToggleStates();
+
+ /**
+ * The current field is a short message field?
+ */
+ private boolean mShortMessageField;
+
+ /**
+ * Is return key in normal state?
+ */
+ private boolean mEnterKeyNormal = true;
+
+ /**
+ * Current icon. 0 for none icon.
+ */
+ int mInputIcon = R.drawable.ime_pinyin;
+
+ /**
+ * IME service.
+ */
+ private RemoteIME mImeService;
+
+ /**
+ * Key toggling state for Chinese mode.
+ */
+ private int mToggleStateCn;
+
+ /**
+ * Key toggling state for Chinese mode with candidates.
+ */
+ private int mToggleStateCnCand;
+
+ /**
+ * Key toggling state for English lowwercase mode.
+ */
+ private int mToggleStateEnLower;
+
+ /**
+ * Key toggling state for English upppercase mode.
+ */
+ private int mToggleStateEnUpper;
+
+ /**
+ * Key toggling state for English symbol mode for the first page.
+ */
+ private int mToggleStateEnSym1;
+
+ /**
+ * Key toggling state for English symbol mode for the second page.
+ */
+ private int mToggleStateEnSym2;
+
+ /**
+ * Key toggling state for smiley mode.
+ */
+ private int mToggleStateSmiley;
+
+ /**
+ * Key toggling state for phone symbol mode.
+ */
+ private int mToggleStatePhoneSym;
+
+ /**
+ * Key toggling state for GO action of ENTER key.
+ */
+ private int mToggleStateGo;
+
+ /**
+ * Key toggling state for SEARCH action of ENTER key.
+ */
+ private int mToggleStateSearch;
+
+ /**
+ * Key toggling state for SEND action of ENTER key.
+ */
+ private int mToggleStateSend;
+
+ /**
+ * Key toggling state for NEXT action of ENTER key.
+ */
+ private int mToggleStateNext;
+
+ /**
+ * Key toggling state for SEND action of ENTER key.
+ */
+ private int mToggleStateDone;
+
+ /**
+ * QWERTY row toggling state for Chinese input.
+ */
+ private int mToggleRowCn;
+
+ /**
+ * QWERTY row toggling state for English input.
+ */
+ private int mToggleRowEn;
+
+ /**
+ * QWERTY row toggling state for URI input.
+ */
+ private int mToggleRowUri;
+
+ /**
+ * QWERTY row toggling state for email address input.
+ */
+ private int mToggleRowEmailAddress;
+
+ class ToggleStates {
+ /**
+ * If it is true, this soft keyboard is a QWERTY one.
+ */
+ boolean mQwerty;
+
+ /**
+ * If {@link #mQwerty} is true, this variable is used to decide the
+ * letter case of the QWERTY keyboard.
+ */
+ boolean mQwertyUpperCase;
+
+ /**
+ * The id of enabled row in the soft keyboard. Refer to
+ * {@link com.droidlogic.inputmethod.remote.SoftKeyboard.KeyRow} for
+ * details.
+ */
+ public int mRowIdToEnable;
+
+ /**
+ * Used to store all other toggle states for the current input mode.
+ */
+ public int mKeyStates[] = new int[MAX_TOGGLE_STATES];
+
+ /**
+ * Number of states to toggle.
+ */
+ public int mKeyStatesNum;
+ }
+
+ public InputModeSwitcher ( RemoteIME imeService ) {
+ mImeService = imeService;
+ if ( "zh".equals ( Locale.getDefault().getLanguage() ) ) {
+ mRecentLauageInputMode = MODE_SKB_CHINESE;
+ } else {
+ mRecentLauageInputMode = MODE_SKB_ENGLISH;
+ }
+ Resources r = mImeService.getResources();
+ mToggleStateCn = Integer.parseInt ( r.getString ( R.string.toggle_cn ) );
+ mToggleStateCnCand = Integer.parseInt ( r
+ .getString ( R.string.toggle_cn_cand ) );
+ mToggleStateEnLower = Integer.parseInt ( r
+ .getString ( R.string.toggle_en_lower ) );
+ mToggleStateEnUpper = Integer.parseInt ( r
+ .getString ( R.string.toggle_en_upper ) );
+ mToggleStateEnSym1 = Integer.parseInt ( r
+ .getString ( R.string.toggle_en_sym1 ) );
+ mToggleStateEnSym2 = Integer.parseInt ( r
+ .getString ( R.string.toggle_en_sym2 ) );
+ mToggleStateSmiley = Integer.parseInt ( r
+ .getString ( R.string.toggle_smiley ) );
+ mToggleStatePhoneSym = Integer.parseInt ( r
+ .getString ( R.string.toggle_phone_sym ) );
+ mToggleStateGo = Integer
+ .parseInt ( r.getString ( R.string.toggle_enter_go ) );
+ mToggleStateSearch = Integer.parseInt ( r
+ .getString ( R.string.toggle_enter_search ) );
+ mToggleStateSend = Integer.parseInt ( r
+ .getString ( R.string.toggle_enter_send ) );
+ mToggleStateNext = Integer.parseInt ( r
+ .getString ( R.string.toggle_enter_next ) );
+ mToggleStateDone = Integer.parseInt ( r
+ .getString ( R.string.toggle_enter_done ) );
+ mToggleRowCn = Integer.parseInt ( r.getString ( R.string.toggle_row_cn ) );
+ mToggleRowEn = Integer.parseInt ( r.getString ( R.string.toggle_row_en ) );
+ mToggleRowUri = Integer.parseInt ( r.getString ( R.string.toggle_row_uri ) );
+ mToggleRowEmailAddress = Integer.parseInt ( r
+ .getString ( R.string.toggle_row_emailaddress ) );
+ }
+
+ public int getInputMode() {
+ return mInputMode;
+ }
+
+ public ToggleStates getToggleStates() {
+ return mToggleStates;
+ }
+
+ public int getSkbLayout() {
+ int layout = ( mInputMode & MASK_SKB_LAYOUT );
+ switch ( layout ) {
+ case MASK_SKB_LAYOUT_QWERTY:
+ return R.xml.skb_qwerty;
+ case MASK_SKB_LAYOUT_SYMBOL1:
+ return R.xml.skb_sym1;
+ case MASK_SKB_LAYOUT_SYMBOL2:
+ return R.xml.skb_sym2;
+ case MASK_SKB_LAYOUT_SMILEY:
+ return R.xml.skb_smiley;
+ case MASK_SKB_LAYOUT_PHONE:
+ return R.xml.skb_phone;
+ }
+ return 0;
+ }
+
+ // Return the icon to update.
+ public int switchLanguageWithHkb() {
+ int newInputMode = MODE_HKB_CHINESE;
+ mInputIcon = R.drawable.ime_pinyin;
+ if ( MODE_HKB_CHINESE == mInputMode ) {
+ newInputMode = MODE_HKB_ENGLISH;
+ mInputIcon = R.drawable.ime_en;
+ }
+ saveInputMode ( newInputMode );
+ return mInputIcon;
+ }
+
+ // Return the icon to update.
+ public int switchModeForUserKey ( int userKey ) {
+ int newInputMode = MODE_UNSET;
+ if ( USERDEF_KEYCODE_LANG_2 == userKey ) {
+ if ( MODE_SKB_CHINESE == mInputMode ) {
+ newInputMode = MODE_SKB_ENGLISH_LOWER;
+ } else if ( MODE_SKB_ENGLISH_LOWER == mInputMode
+ || MODE_SKB_ENGLISH_UPPER == mInputMode ) {
+ newInputMode = MODE_SKB_CHINESE;
+ } else if ( MODE_SKB_SYMBOL1_CN == mInputMode ) {
+ newInputMode = MODE_SKB_SYMBOL1_EN;
+ } else if ( MODE_SKB_SYMBOL1_EN == mInputMode ) {
+ newInputMode = MODE_SKB_SYMBOL1_CN;
+ } else if ( MODE_SKB_SYMBOL2_CN == mInputMode ) {
+ newInputMode = MODE_SKB_SYMBOL2_EN;
+ } else if ( MODE_SKB_SYMBOL2_EN == mInputMode ) {
+ newInputMode = MODE_SKB_SYMBOL2_CN;
+ } else if ( MODE_SKB_SMILEY == mInputMode ) {
+ newInputMode = MODE_SKB_CHINESE;
+ }
+ } else if ( USERDEF_KEYCODE_SYM_3 == userKey ) {
+ if ( MODE_SKB_CHINESE == mInputMode ) {
+ newInputMode = MODE_SKB_SYMBOL1_CN;
+ } else if ( MODE_SKB_ENGLISH_UPPER == mInputMode
+ || MODE_SKB_ENGLISH_LOWER == mInputMode ) {
+ newInputMode = MODE_SKB_SYMBOL1_EN;
+ } else if ( MODE_SKB_SYMBOL1_EN == mInputMode
+ || MODE_SKB_SYMBOL2_EN == mInputMode ) {
+ newInputMode = MODE_SKB_ENGLISH_LOWER;
+ } else if ( MODE_SKB_SYMBOL1_CN == mInputMode
+ || MODE_SKB_SYMBOL2_CN == mInputMode ) {
+ newInputMode = MODE_SKB_CHINESE;
+ } else if ( MODE_SKB_SMILEY == mInputMode ) {
+ newInputMode = MODE_SKB_SYMBOL1_CN;
+ }
+ } else if ( USERDEF_KEYCODE_SHIFT_1 == userKey ) {
+ if ( MODE_SKB_ENGLISH_LOWER == mInputMode ) {
+ newInputMode = MODE_SKB_ENGLISH_UPPER;
+ } else if ( MODE_SKB_ENGLISH_UPPER == mInputMode ) {
+ newInputMode = MODE_SKB_ENGLISH_LOWER;
+ }
+ } else if ( USERDEF_KEYCODE_MORE_SYM_5 == userKey ) {
+ int sym = ( MASK_SKB_LAYOUT & mInputMode );
+ if ( MASK_SKB_LAYOUT_SYMBOL1 == sym ) {
+ sym = MASK_SKB_LAYOUT_SYMBOL2;
+ } else {
+ sym = MASK_SKB_LAYOUT_SYMBOL1;
+ }
+ newInputMode = ( ( mInputMode & ( ~MASK_SKB_LAYOUT ) ) | sym );
+ } else if ( USERDEF_KEYCODE_SMILEY_6 == userKey ) {
+ if ( MODE_SKB_CHINESE == mInputMode ) {
+ newInputMode = MODE_SKB_SMILEY;
+ } else {
+ newInputMode = MODE_SKB_CHINESE;
+ }
+ } else if ( USERDEF_KEYCODE_PHONE_SYM_4 == userKey ) {
+ if ( MODE_SKB_PHONE_NUM == mInputMode ) {
+ newInputMode = MODE_SKB_PHONE_SYM;
+ } else {
+ newInputMode = MODE_SKB_PHONE_NUM;
+ }
+ }
+ if ( newInputMode == mInputMode || MODE_UNSET == newInputMode ) {
+ return mInputIcon;
+ }
+ saveInputMode ( newInputMode );
+ prepareToggleStates ( true );
+ return mInputIcon;
+ }
+
+ // Return the icon to update.
+ public int requestInputWithHkb ( EditorInfo editorInfo ) {
+ mShortMessageField = false;
+ boolean english = false;
+ int newInputMode = MODE_HKB_CHINESE;
+ switch ( editorInfo.inputType & EditorInfo.TYPE_MASK_CLASS ) {
+ case EditorInfo.TYPE_CLASS_NUMBER:
+ case EditorInfo.TYPE_CLASS_PHONE:
+ case EditorInfo.TYPE_CLASS_DATETIME:
+ english = true;
+ break;
+ case EditorInfo.TYPE_CLASS_TEXT:
+ int v = editorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
+ if ( v == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ || v == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
+ || v == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+ || v == EditorInfo.TYPE_TEXT_VARIATION_URI ) {
+ english = true;
+ } else if ( v == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE ) {
+ mShortMessageField = true;
+ }
+ break;
+ default:
+ }
+ if ( english ) {
+ // If the application request English mode, we switch to it.
+ newInputMode = MODE_HKB_ENGLISH;
+ } else {
+ // If the application do not request English mode, we will
+ // try to keep the previous mode to input language text.
+ // Because there is not soft keyboard, we need discard all
+ // soft keyboard related information from the previous language
+ // mode.
+ if ( ( mRecentLauageInputMode & MASK_LANGUAGE ) == MASK_LANGUAGE_CN ) {
+ newInputMode = MODE_HKB_CHINESE;
+ } else {
+ newInputMode = MODE_HKB_ENGLISH;
+ }
+ }
+ mEditorInfo = editorInfo;
+ saveInputMode ( newInputMode );
+ prepareToggleStates ( false );
+ return mInputIcon;
+ }
+
+ // Return the icon to update.
+ public int requestInputWithSkb ( EditorInfo editorInfo ) {
+ mShortMessageField = false;
+ int newInputMode = MODE_SKB_CHINESE;
+ switch ( editorInfo.inputType & EditorInfo.TYPE_MASK_CLASS ) {
+ case EditorInfo.TYPE_CLASS_NUMBER:
+ case EditorInfo.TYPE_CLASS_DATETIME:
+ newInputMode = MODE_SKB_SYMBOL1_EN;
+ break;
+ case EditorInfo.TYPE_CLASS_PHONE:
+ newInputMode = MODE_SKB_PHONE_NUM;
+ break;
+ case EditorInfo.TYPE_CLASS_TEXT:
+ int v = editorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
+ if ( v == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ || v == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
+ || v == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+ || v == EditorInfo.TYPE_TEXT_VARIATION_URI ) {
+ // If the application request English mode, we switch to it.
+ newInputMode = MODE_SKB_ENGLISH_LOWER;
+ } else {
+ if ( v == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE ) {
+ mShortMessageField = true;
+ }
+ // If the application do not request English mode, we will
+ // try to keep the previous mode.
+ int skbLayout = ( mInputMode & MASK_SKB_LAYOUT );
+ newInputMode = mInputMode;
+ if ( 0 == skbLayout ) {
+ if ( ( mInputMode & MASK_LANGUAGE ) == MASK_LANGUAGE_CN ) {
+ newInputMode = MODE_SKB_CHINESE;
+ } else {
+ newInputMode = MODE_SKB_ENGLISH_LOWER;
+ }
+ }
+ }
+ break;
+ default:
+ // Try to keep the previous mode.
+ int skbLayout = ( mInputMode & MASK_SKB_LAYOUT );
+ newInputMode = mInputMode;
+ if ( 0 == skbLayout ) {
+ if ( ( mInputMode & MASK_LANGUAGE ) == MASK_LANGUAGE_CN ) {
+ newInputMode = MODE_SKB_CHINESE;
+ } else {
+ newInputMode = MODE_SKB_ENGLISH_LOWER;
+ }
+ }
+ break;
+ }
+ mEditorInfo = editorInfo;
+ saveInputMode ( newInputMode );
+ prepareToggleStates ( true );
+ return mInputIcon;
+ }
+
+ // Return the icon to update.
+ public int requestBackToPreviousSkb() {
+ int layout = ( mInputMode & MASK_SKB_LAYOUT );
+ int lastLayout = ( mPreviousInputMode & MASK_SKB_LAYOUT );
+ if ( 0 != layout && 0 != lastLayout ) {
+ mInputMode = mPreviousInputMode;
+ saveInputMode ( mInputMode );
+ prepareToggleStates ( true );
+ return mInputIcon;
+ }
+ return 0;
+ }
+
+ public int getTooggleStateForCnCand() {
+ return mToggleStateCnCand;
+ }
+
+ public boolean isEnglishWithHkb() {
+ return MODE_HKB_ENGLISH == mInputMode;
+ }
+
+ public boolean isEnglishWithSkb() {
+ return MODE_SKB_ENGLISH_LOWER == mInputMode
+ || MODE_SKB_ENGLISH_UPPER == mInputMode;
+ }
+
+ public boolean isEnglishUpperCaseWithSkb() {
+ return MODE_SKB_ENGLISH_UPPER == mInputMode;
+ }
+
+ public boolean isChineseText() {
+ int skbLayout = ( mInputMode & MASK_SKB_LAYOUT );
+ if ( MASK_SKB_LAYOUT_QWERTY == skbLayout || 0 == skbLayout ) {
+ int language = ( mInputMode & MASK_LANGUAGE );
+ if ( MASK_LANGUAGE_CN == language ) { return true; }
+ }
+ return false;
+ }
+
+ public boolean isChineseTextWithHkb() {
+ int skbLayout = ( mInputMode & MASK_SKB_LAYOUT );
+ if ( 0 == skbLayout ) {
+ int language = ( mInputMode & MASK_LANGUAGE );
+ if ( MASK_LANGUAGE_CN == language ) { return true; }
+ }
+ return false;
+ }
+
+ public boolean isChineseTextWithSkb() {
+ int skbLayout = ( mInputMode & MASK_SKB_LAYOUT );
+ if ( MASK_SKB_LAYOUT_QWERTY == skbLayout ) {
+ int language = ( mInputMode & MASK_LANGUAGE );
+ if ( MASK_LANGUAGE_CN == language ) { return true; }
+ }
+ return false;
+ }
+
+ public boolean isSymbolWithSkb() {
+ int skbLayout = ( mInputMode & MASK_SKB_LAYOUT );
+ if ( MASK_SKB_LAYOUT_SYMBOL1 == skbLayout
+ || MASK_SKB_LAYOUT_SYMBOL2 == skbLayout ) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isEnterNoramlState() {
+ return mEnterKeyNormal;
+ }
+
+ public boolean tryHandleLongPressSwitch ( int keyCode ) {
+ if ( USERDEF_KEYCODE_LANG_2 == keyCode
+ || USERDEF_KEYCODE_PHONE_SYM_4 == keyCode ) {
+ mImeService.showOptionsMenu();
+ return true;
+ }
+ return false;
+ }
+
+ private void saveInputMode ( int newInputMode ) {
+ mPreviousInputMode = mInputMode;
+ mInputMode = newInputMode;
+ int skbLayout = ( mInputMode & MASK_SKB_LAYOUT );
+ if ( MASK_SKB_LAYOUT_QWERTY == skbLayout || 0 == skbLayout ) {
+ mRecentLauageInputMode = mInputMode;
+ }
+ mInputIcon = R.drawable.ime_pinyin;
+ if ( isEnglishWithHkb() ) {
+ mInputIcon = R.drawable.ime_en;
+ } else if ( isChineseTextWithHkb() ) {
+ mInputIcon = R.drawable.ime_pinyin;
+ }
+ if ( !Environment.getInstance().hasHardKeyboard() ) {
+ mInputIcon = 0;
+ }
+ }
+
+ private void prepareToggleStates ( boolean needSkb ) {
+ mEnterKeyNormal = true;
+ if ( !needSkb ) { return; }
+ mToggleStates.mQwerty = false;
+ mToggleStates.mKeyStatesNum = 0;
+ int states[] = mToggleStates.mKeyStates;
+ int statesNum = 0;
+ // Toggle state for language.
+ int language = ( mInputMode & MASK_LANGUAGE );
+ int layout = ( mInputMode & MASK_SKB_LAYOUT );
+ int charcase = ( mInputMode & MASK_CASE );
+ int variation = mEditorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
+ if ( MASK_SKB_LAYOUT_PHONE != layout ) {
+ if ( MASK_LANGUAGE_CN == language ) {
+ // Chinese and Chinese symbol are always the default states,
+ // do not add a toggling operation.
+ if ( MASK_SKB_LAYOUT_QWERTY == layout ) {
+ mToggleStates.mQwerty = true;
+ mToggleStates.mQwertyUpperCase = true;
+ if ( mShortMessageField ) {
+ states[statesNum] = mToggleStateSmiley;
+ statesNum++;
+ }
+ }
+ } else if ( MASK_LANGUAGE_EN == language ) {
+ if ( MASK_SKB_LAYOUT_QWERTY == layout ) {
+ mToggleStates.mQwerty = true;
+ mToggleStates.mQwertyUpperCase = false;
+ states[statesNum] = mToggleStateEnLower;
+ if ( MASK_CASE_UPPER == charcase ) {
+ mToggleStates.mQwertyUpperCase = true;
+ states[statesNum] = mToggleStateEnUpper;
+ }
+ statesNum++;
+ } else if ( MASK_SKB_LAYOUT_SYMBOL1 == layout ) {
+ states[statesNum] = mToggleStateEnSym1;
+ statesNum++;
+ } else if ( MASK_SKB_LAYOUT_SYMBOL2 == layout ) {
+ states[statesNum] = mToggleStateEnSym2;
+ statesNum++;
+ }
+ }
+ // Toggle rows for QWERTY.
+ mToggleStates.mRowIdToEnable = KeyRow.DEFAULT_ROW_ID;
+ if ( variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ) {
+ mToggleStates.mRowIdToEnable = mToggleRowEmailAddress;
+ } else if ( variation == EditorInfo.TYPE_TEXT_VARIATION_URI ) {
+ mToggleStates.mRowIdToEnable = mToggleRowUri;
+ } else if ( MASK_LANGUAGE_CN == language ) {
+ mToggleStates.mRowIdToEnable = mToggleRowCn;
+ } else if ( MASK_LANGUAGE_EN == language ) {
+ mToggleStates.mRowIdToEnable = mToggleRowEn;
+ }
+ } else {
+ if ( MASK_CASE_UPPER == charcase ) {
+ states[statesNum] = mToggleStatePhoneSym;
+ statesNum++;
+ }
+ }
+ // Toggle state for enter key.
+ int action = mEditorInfo.imeOptions
+ & ( EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION );
+ if ( action == EditorInfo.IME_ACTION_GO ) {
+ states[statesNum] = mToggleStateGo;
+ statesNum++;
+ mEnterKeyNormal = false;
+ } else if ( action == EditorInfo.IME_ACTION_SEARCH ) {
+ states[statesNum] = mToggleStateSearch;
+ statesNum++;
+ mEnterKeyNormal = false;
+ } else if ( action == EditorInfo.IME_ACTION_SEND ) {
+ states[statesNum] = mToggleStateSend;
+ statesNum++;
+ mEnterKeyNormal = false;
+ } else if ( action == EditorInfo.IME_ACTION_NEXT ) {
+ int f = mEditorInfo.inputType & EditorInfo.TYPE_MASK_FLAGS;
+ if ( f != EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE ) {
+ states[statesNum] = mToggleStateNext;
+ statesNum++;
+ mEnterKeyNormal = false;
+ }
+ } else if ( action == EditorInfo.IME_ACTION_DONE ) {
+ states[statesNum] = mToggleStateDone;
+ statesNum++;
+ mEnterKeyNormal = false;
+ }
+ mToggleStates.mKeyStatesNum = statesNum;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/KeyMapDream.java b/src/com/droidlogic/inputmethod/remote/KeyMapDream.java
new file mode 100644
index 0000000..2fe6007
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/KeyMapDream.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.view.KeyEvent;
+
+/**
+ * Class used to map the symbols on Dream's hardware keyboard to corresponding
+ * Chinese full-width symbols.
+ */
+public class KeyMapDream {
+ // Number of shift bits to store full-width symbols
+ private static final int SHIFT_FWCH = 8;
+ private static final int[] mKeyMap = {
+ KeyEvent.KEYCODE_UNKNOWN,
+ KeyEvent.KEYCODE_SOFT_LEFT,
+ KeyEvent.KEYCODE_SOFT_RIGHT,
+ KeyEvent.KEYCODE_HOME,
+ KeyEvent.KEYCODE_BACK,
+ KeyEvent.KEYCODE_CALL,
+ KeyEvent.KEYCODE_ENDCALL,
+ KeyEvent.KEYCODE_0 | ( '\uff09' << SHIFT_FWCH ), // )
+ KeyEvent.KEYCODE_1 | ( '\uff01' << SHIFT_FWCH ), // !
+ KeyEvent.KEYCODE_2 | ( '\uff20' << SHIFT_FWCH ), // @
+ KeyEvent.KEYCODE_3 | ( '\uff03' << SHIFT_FWCH ), // #
+ KeyEvent.KEYCODE_4 | ( '\uffe5' << SHIFT_FWCH ), // $ - fullwidth Yuan
+ KeyEvent.KEYCODE_5 | ( '\uff05' << SHIFT_FWCH ), // %
+ KeyEvent.KEYCODE_6 | ( '\u2026' << SHIFT_FWCH ), // ^ - Apostrophe
+ KeyEvent.KEYCODE_7 | ( '\uff06' << SHIFT_FWCH ), // &
+ KeyEvent.KEYCODE_8 | ( '\uff0a' << SHIFT_FWCH ), // *
+ KeyEvent.KEYCODE_9 | ( '\uff08' << SHIFT_FWCH ), // (
+ KeyEvent.KEYCODE_STAR,
+ KeyEvent.KEYCODE_POUND,
+ KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN,
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.KEYCODE_DPAD_CENTER,
+ KeyEvent.KEYCODE_VOLUME_UP,
+ KeyEvent.KEYCODE_VOLUME_DOWN,
+ KeyEvent.KEYCODE_POWER,
+ KeyEvent.KEYCODE_CAMERA,
+ KeyEvent.KEYCODE_CLEAR,
+ KeyEvent.KEYCODE_A,
+ KeyEvent.KEYCODE_B | ( '\uff3d' << SHIFT_FWCH ), // ]
+ KeyEvent.KEYCODE_C | ( '\u00a9' << SHIFT_FWCH ), // copyright
+ KeyEvent.KEYCODE_D | ( '\u3001' << SHIFT_FWCH ), // \\
+ KeyEvent.KEYCODE_E | ( '_' << SHIFT_FWCH ), // _
+ KeyEvent.KEYCODE_F | ( '\uff5b' << SHIFT_FWCH ), // {
+ KeyEvent.KEYCODE_G | ( '\uff5d' << SHIFT_FWCH ), // }
+ KeyEvent.KEYCODE_H | ( '\uff1a' << SHIFT_FWCH ), // :
+ KeyEvent.KEYCODE_I | ( '\uff0d' << SHIFT_FWCH ), // -
+ KeyEvent.KEYCODE_J | ( '\uff1b' << SHIFT_FWCH ), // ;
+ KeyEvent.KEYCODE_K | ( '\u201c' << SHIFT_FWCH ), // "
+ KeyEvent.KEYCODE_L | ( '\u2019' << SHIFT_FWCH ), // '
+ KeyEvent.KEYCODE_M | ( '\u300b' << SHIFT_FWCH ), // > - French quotes
+ KeyEvent.KEYCODE_N | ( '\u300a' << SHIFT_FWCH ), // < - French quotes
+ KeyEvent.KEYCODE_O | ( '\uff0b' << SHIFT_FWCH ), // +
+ KeyEvent.KEYCODE_P | ( '\uff1d' << SHIFT_FWCH ), // =
+ KeyEvent.KEYCODE_Q | ( '\t' << SHIFT_FWCH ), // \t
+ KeyEvent.KEYCODE_R | ( '\u00ae' << SHIFT_FWCH ), // trademark
+ KeyEvent.KEYCODE_S | ( '\uff5c' << SHIFT_FWCH ), // |
+ KeyEvent.KEYCODE_T | ( '\u20ac' << SHIFT_FWCH ), //
+ KeyEvent.KEYCODE_U | ( '\u00d7' << SHIFT_FWCH ), // multiplier
+ KeyEvent.KEYCODE_V | ( '\uff3b' << SHIFT_FWCH ), // [
+ KeyEvent.KEYCODE_W | ( '\uff40' << SHIFT_FWCH ), // `
+ KeyEvent.KEYCODE_X, KeyEvent.KEYCODE_Y | ( '\u00f7' << SHIFT_FWCH ),
+ KeyEvent.KEYCODE_Z,
+ KeyEvent.KEYCODE_COMMA | ( '\uff1f' << SHIFT_FWCH ),
+ KeyEvent.KEYCODE_PERIOD | ( '\uff0f' << SHIFT_FWCH ),
+ KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_ALT_RIGHT,
+ KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SHIFT_RIGHT,
+ KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_SYM,
+ KeyEvent.KEYCODE_EXPLORER, KeyEvent.KEYCODE_ENVELOPE,
+ KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_DEL,
+ KeyEvent.KEYCODE_GRAVE, KeyEvent.KEYCODE_MINUS,
+ KeyEvent.KEYCODE_EQUALS, KeyEvent.KEYCODE_LEFT_BRACKET,
+ KeyEvent.KEYCODE_RIGHT_BRACKET, KeyEvent.KEYCODE_BACKSLASH,
+ KeyEvent.KEYCODE_SEMICOLON, KeyEvent.KEYCODE_APOSTROPHE,
+ KeyEvent.KEYCODE_SLASH,
+ KeyEvent.KEYCODE_AT | ( '\uff5e' << SHIFT_FWCH ),
+ KeyEvent.KEYCODE_NUM, KeyEvent.KEYCODE_HEADSETHOOK,
+ KeyEvent.KEYCODE_FOCUS, KeyEvent.KEYCODE_PLUS,
+ KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_NOTIFICATION,
+ KeyEvent.KEYCODE_SEARCH,
+ };
+
+ static public char getChineseLabel ( int keyCode ) {
+ if ( keyCode <= 0 || keyCode >= KeyEvent.getMaxKeyCode() ) { return 0; }
+ assert ( ( mKeyMap[keyCode] & 0x000000ff ) == keyCode );
+ return ( char ) ( mKeyMap[keyCode] >> SHIFT_FWCH );
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/PinyinDecoderService.java b/src/com/droidlogic/inputmethod/remote/PinyinDecoderService.java
new file mode 100644
index 0000000..6d6fffe
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/PinyinDecoderService.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import com.droidlogic.inputmethod.remote.IPinyinDecoderService;
+
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+import java.util.Vector;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * This class is used to separate the input method kernel in an individual
+ * service so that both IME and IME-syncer can use it.
+ */
+public class PinyinDecoderService extends Service {
+ native static boolean nativeImOpenDecoder ( byte fn_sys_dict[],
+ byte fn_usr_dict[] );
+
+ native static boolean nativeImOpenDecoderFd ( FileDescriptor fd,
+ long startOffset, long length, byte fn_usr_dict[] );
+
+ native static void nativeImSetMaxLens ( int maxSpsLen, int maxHzsLen );
+
+ native static boolean nativeImCloseDecoder();
+
+ native static int nativeImSearch ( byte pyBuf[], int pyLen );
+
+ native static int nativeImDelSearch ( int pos, boolean is_pos_in_splid,
+ boolean clear_fixed_this_step );
+
+ native static void nativeImResetSearch();
+
+ native static int nativeImAddLetter ( byte ch );
+
+ native static String nativeImGetPyStr ( boolean decoded );
+
+ native static int nativeImGetPyStrLen ( boolean decoded );
+
+ native static int[] nativeImGetSplStart();
+
+ native static String nativeImGetChoice ( int choiceId );
+
+ native static int nativeImChoose ( int choiceId );
+
+ native static int nativeImCancelLastChoice();
+
+ native static int nativeImGetFixedLen();
+
+ native static boolean nativeImCancelInput();
+
+ native static boolean nativeImFlushCache();
+
+ native static int nativeImGetPredictsNum ( String fixedStr );
+
+ native static String nativeImGetPredictItem ( int predictNo );
+
+ // Sync related
+ native static String nativeSyncUserDict ( byte[] user_dict, String tomerge );
+
+ native static boolean nativeSyncBegin ( byte[] user_dict );
+
+ native static boolean nativeSyncFinish();
+
+ native static String nativeSyncGetLemmas();
+
+ native static int nativeSyncPutLemmas ( String tomerge );
+
+ native static int nativeSyncGetLastCount();
+
+ native static int nativeSyncGetTotalCount();
+
+ native static boolean nativeSyncClearLastGot();
+
+ native static int nativeSyncGetCapacity();
+
+ private final static int MAX_PATH_FILE_LENGTH = 100;
+ private static boolean inited = false;
+
+ private String mUsr_dict_file;
+
+ static {
+ try {
+ System.loadLibrary ( "jni_remoteime" );
+ } catch ( UnsatisfiedLinkError ule ) {
+ Log.e ( "PinyinDecoderService",
+ "WARNING: Could not load jni_remoteime natives" );
+ }
+ }
+
+ // Get file name of the specified dictionary
+ private boolean getUsrDictFileName ( byte usr_dict[] ) {
+ if ( null == usr_dict ) {
+ return false;
+ }
+ for ( int i = 0; i < mUsr_dict_file.length(); i++ ) {
+ usr_dict[i] = ( byte ) mUsr_dict_file.charAt ( i );
+ }
+ usr_dict[mUsr_dict_file.length()] = 0;
+ return true;
+ }
+
+ private void initPinyinEngine() {
+ byte usr_dict[];
+ usr_dict = new byte[MAX_PATH_FILE_LENGTH];
+ // Here is how we open a built-in dictionary for access through
+ // a file descriptor...
+ AssetFileDescriptor afd = getResources().openRawResourceFd (
+ R.raw.dict_pinyin );
+ if ( Environment.getInstance().needDebug() ) {
+ Log
+ .i ( "foo", "Dict: start=" + afd.getStartOffset()
+ + ", length=" + afd.getLength() + ", fd="
+ + afd.getParcelFileDescriptor() );
+ }
+ if ( getUsrDictFileName ( usr_dict ) ) {
+ inited = nativeImOpenDecoderFd ( afd.getFileDescriptor(), afd
+ .getStartOffset(), afd.getLength(), usr_dict );
+ }
+ try {
+ afd.close();
+ } catch ( IOException e ) {
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mUsr_dict_file = getFileStreamPath ( "usr_dict.dat" ).getPath();
+ // This is a hack to make sure our "files" directory has been
+ // created.
+ try {
+ openFileOutput ( "dummy", 0 ).close();
+ } catch ( FileNotFoundException e ) {
+ } catch ( IOException e ) {
+ }
+ initPinyinEngine();
+ }
+
+ @Override
+ public void onDestroy() {
+ nativeImCloseDecoder();
+ inited = false;
+ super.onDestroy();
+ }
+
+ private final IPinyinDecoderService.Stub mBinder = new IPinyinDecoderService.Stub() {
+ public int getInt() {
+ return 12345;
+ }
+ public void setMaxLens ( int maxSpsLen, int maxHzsLen ) {
+ nativeImSetMaxLens ( maxSpsLen, maxHzsLen );
+ }
+ public int imSearch ( byte[] pyBuf, int pyLen ) {
+ return nativeImSearch ( pyBuf, pyLen );
+ }
+ public int imDelSearch ( int pos, boolean is_pos_in_splid,
+ boolean clear_fixed_this_step ) {
+ return nativeImDelSearch ( pos, is_pos_in_splid,
+ clear_fixed_this_step );
+ }
+ public void imResetSearch() {
+ nativeImResetSearch();
+ }
+ public int imAddLetter ( byte ch ) {
+ return nativeImAddLetter ( ch );
+ }
+ public String imGetPyStr ( boolean decoded ) {
+ return nativeImGetPyStr ( decoded );
+ }
+ public int imGetPyStrLen ( boolean decoded ) {
+ return nativeImGetPyStrLen ( decoded );
+ }
+ public int[] imGetSplStart() {
+ return nativeImGetSplStart();
+ }
+ public String imGetChoice ( int choiceId ) {
+ return nativeImGetChoice ( choiceId );
+ }
+ public String imGetChoices ( int choicesNum ) {
+ String retStr = null;
+ for ( int i = 0; i < choicesNum; i++ ) {
+ if ( null == retStr ) {
+ retStr = nativeImGetChoice ( i );
+ } else {
+ retStr += " " + nativeImGetChoice ( i );
+ }
+ }
+ return retStr;
+ }
+ public List<String> imGetChoiceList ( int choicesStart, int choicesNum,
+ int sentFixedLen ) {
+ Vector<String> choiceList = new Vector<String>();
+ for ( int i = choicesStart; i < choicesStart + choicesNum; i++ ) {
+ String retStr = nativeImGetChoice ( i );
+ if ( 0 == i ) { retStr = retStr.substring ( sentFixedLen ); }
+ choiceList.add ( retStr );
+ }
+ return choiceList;
+ }
+ public int imChoose ( int choiceId ) {
+ return nativeImChoose ( choiceId );
+ }
+ public int imCancelLastChoice() {
+ return nativeImCancelLastChoice();
+ }
+ public int imGetFixedLen() {
+ return nativeImGetFixedLen();
+ }
+ public boolean imCancelInput() {
+ return nativeImCancelInput();
+ }
+ public void imFlushCache() {
+ nativeImFlushCache();
+ }
+ public int imGetPredictsNum ( String fixedStr ) {
+ return nativeImGetPredictsNum ( fixedStr );
+ }
+ public String imGetPredictItem ( int predictNo ) {
+ return nativeImGetPredictItem ( predictNo );
+ }
+ public List<String> imGetPredictList ( int predictsStart, int predictsNum ) {
+ Vector<String> predictList = new Vector<String>();
+ for ( int i = predictsStart; i < predictsStart + predictsNum; i++ ) {
+ predictList.add ( nativeImGetPredictItem ( i ) );
+ }
+ return predictList;
+ }
+ public String syncUserDict ( String tomerge ) {
+ byte usr_dict[];
+ usr_dict = new byte[MAX_PATH_FILE_LENGTH];
+ if ( getUsrDictFileName ( usr_dict ) ) {
+ return nativeSyncUserDict ( usr_dict, tomerge );
+ }
+ return null;
+ }
+ public boolean syncBegin() {
+ byte usr_dict[];
+ usr_dict = new byte[MAX_PATH_FILE_LENGTH];
+ if ( getUsrDictFileName ( usr_dict ) ) {
+ return nativeSyncBegin ( usr_dict );
+ }
+ return false;
+ }
+ public void syncFinish() {
+ nativeSyncFinish();
+ }
+ public int syncPutLemmas ( String tomerge ) {
+ return nativeSyncPutLemmas ( tomerge );
+ }
+ public String syncGetLemmas() {
+ return nativeSyncGetLemmas();
+ }
+ public int syncGetLastCount() {
+ return nativeSyncGetLastCount();
+ }
+ public int syncGetTotalCount() {
+ return nativeSyncGetTotalCount();
+ }
+ public void syncClearLastGot() {
+ nativeSyncClearLastGot();
+ }
+ public int imSyncGetCapacity() {
+ return nativeSyncGetCapacity();
+ }
+ };
+
+ @Override
+ public IBinder onBind ( Intent intent ) {
+ return mBinder;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/RemoteIME.java b/src/com/droidlogic/inputmethod/remote/RemoteIME.java
new file mode 100644
index 0000000..09ea9e2
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/RemoteIME.java
@@ -0,0 +1,2158 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.inputmethodservice.InputMethodService;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.GestureDetector;
+import android.view.LayoutInflater;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+import com.droidlogic.app.SystemControlManager;
+
+/**
+ * Main class of the Pinyin input method.
+ */
+public class RemoteIME extends InputMethodService {
+ /**
+ * TAG for debug.
+ */
+ static final String TAG = "RemoteIME";
+
+ /**
+ * If is is true, IME will simulate key events for delete key, and send the
+ * events back to the application.
+ */
+ private static final boolean SIMULATE_KEY_DELETE = true;
+
+ /**
+ * Necessary environment configurations like screen size for this IME.
+ */
+ private Environment mEnvironment;
+
+ /**
+ * Used to switch input mode.
+ */
+ private InputModeSwitcher mInputModeSwitcher;
+
+ /**
+ * Soft keyboard container view to host real soft keyboard view.
+ */
+ private SkbContainer mSkbContainer;
+
+ /**
+ * The floating container which contains the composing view. If necessary,
+ * some other view like candiates container can also be put here.
+ */
+ private LinearLayout mFloatingContainer;
+
+ /**
+ * View to show the composing string.
+ */
+ private ComposingView mComposingView;
+
+ /**
+ * Window to show the composing string.
+ */
+ private PopupWindow mFloatingWindow;
+
+ /**
+ * Used to show the floating window.
+ */
+ private PopupTimer mFloatingWindowTimer = new PopupTimer();
+
+ /**
+ * View to show candidates list.
+ */
+ private CandidatesContainer mCandidatesContainer;
+
+ /**
+ * Balloon used when user presses a candidate.
+ */
+ private BalloonHint mCandidatesBalloon;
+
+ /**
+ * Used to notify the input method when the user touch a candidate.
+ */
+ private ChoiceNotifier mChoiceNotifier;
+
+ /**
+ * Used to notify gestures from soft keyboard.
+ */
+ private OnGestureListener mGestureListenerSkb;
+
+ /**
+ * Used to notify gestures from candidates view.
+ */
+ private OnGestureListener mGestureListenerCandidates;
+
+ /**
+ * The on-screen movement gesture detector for soft keyboard.
+ */
+ private GestureDetector mGestureDetectorSkb;
+
+ /**
+ * The on-screen movement gesture detector for candidates view.
+ */
+ private GestureDetector mGestureDetectorCandidates;
+
+ /**
+ * Option dialog to choose settings and other IMEs.
+ */
+ private AlertDialog mOptionsDialog;
+
+ /**
+ * Connection used to bind the decoding service.
+ */
+ private PinyinDecoderServiceConnection mPinyinDecoderServiceConnection;
+
+ /**
+ * The current IME status.
+ *
+ * @see com.droidlogic.inputmethod.remote.RemoteIME.ImeState
+ */
+ private ImeState mImeState = ImeState.STATE_IDLE;
+
+ /**
+ * The decoding information, include spelling(Pinyin) string, decoding
+ * result, etc.
+ */
+ private DecodingInfo mDecInfo = new DecodingInfo();
+
+ // private TextUpdateReceiver text_receiver;//added by Linyu Bao,2011-03-10
+ // private static final String TEXT_UPDATE_BROAD = "com.skyworth.controlservice.updatetext";//added by Linyu Bao,2011-03-10
+ // private static final String UPDATE_TEXT = "update_text";//added by Linyu Bao,2011-03-10
+
+ /**
+ * For English input.
+ */
+ private EnglishInputProcessor mImEn;
+
+ private Boolean mEnterEnabled;
+
+ private Boolean mShiftTag = false;
+ private SystemControlManager sw = null;
+ // receive ringer mode changes
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive ( Context context, Intent intent ) {
+ SoundManager.getInstance ( context ).updateRingerMode();
+ }
+ };
+
+ @Override
+ public void onCreate() {
+ mEnvironment = Environment.getInstance();
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onCreate." );
+ }
+ super.onCreate();
+ mEnterEnabled = getBaseContext().getResources().getBoolean ( R.bool.is_enableEnter );
+ startPinyinDecoderService();
+ mImEn = new EnglishInputProcessor();
+ Settings.getInstance ( PreferenceManager
+ .getDefaultSharedPreferences ( getApplicationContext() ) );
+ mInputModeSwitcher = new InputModeSwitcher ( this );
+ mChoiceNotifier = new ChoiceNotifier ( this );
+ mGestureListenerSkb = new OnGestureListener ( false );
+ mGestureListenerCandidates = new OnGestureListener ( true );
+ mGestureDetectorSkb = new GestureDetector ( this, mGestureListenerSkb );
+ mGestureDetectorCandidates = new GestureDetector ( this,
+ mGestureListenerCandidates );
+ mEnvironment.onConfigurationChanged ( getResources().getConfiguration(),
+ this );
+ sw = new SystemControlManager ( this );
+ }
+
+ @Override
+ public void onDestroy() {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onDestroy." );
+ }
+ unbindService ( mPinyinDecoderServiceConnection );
+ Settings.releaseInstance();
+ super.onDestroy();
+ }
+
+ @Override
+ public void onConfigurationChanged ( Configuration newConfig ) {
+ Environment env = Environment.getInstance();
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onConfigurationChanged" );
+ Log.d ( TAG, "--last config: " + env.getConfiguration().toString() );
+ Log.d ( TAG, "---new config: " + newConfig.toString() );
+ }
+ // We need to change the local environment first so that UI components
+ // can get the environment instance to handle size issues. When
+ // super.onConfigurationChanged() is called, onCreateCandidatesView()
+ // and onCreateInputView() will be executed if necessary.
+ env.onConfigurationChanged ( newConfig, this );
+ // Clear related UI of the previous configuration.
+ if ( null != mSkbContainer ) {
+ mSkbContainer.dismissPopups();
+ }
+ if ( null != mCandidatesBalloon ) {
+ mCandidatesBalloon.dismiss();
+ }
+ if ( newConfig.diff ( env.getConfiguration() ) != 0 ) {
+ super.onConfigurationChanged ( newConfig );
+ }
+ //density and display-size will be change when switch outputmode between 1080 and 720, need to update configuration
+ if ( sw.getPropertyBoolean ( "ro.platform.has.realoutputmode", false ) ) {
+ super.onConfigurationChanged ( newConfig );
+ }
+ resetToIdleState ( false );
+ }
+
+ @Override
+ public boolean onKeyDown ( int keyCode, KeyEvent event ) {
+ if ( processKey ( event, 0 != event.getRepeatCount() ) ) { return true; }
+ return super.onKeyDown ( keyCode, event );
+ }
+
+ @Override
+ public boolean onKeyUp ( int keyCode, KeyEvent event ) {
+ if ( processKey ( event, true ) ) { return true; }
+ return super.onKeyUp ( keyCode, event );
+ }
+
+ private boolean processKey ( KeyEvent event, boolean realAction ) {
+ Log.d ( TAG, "keycode: " + event.getKeyCode() + ", realAction: "
+ + realAction );
+ if ( ImeState.STATE_BYPASS == mImeState ) { return false; }
+ int keyCode = event.getKeyCode();
+ // SHIFT-SPACE is used to switch between Chinese and English
+ // when HKB is on.
+ if ( KeyEvent.KEYCODE_SPACE == keyCode && event.isShiftPressed() ) {
+ if ( !realAction ) { return true; }
+ updateIcon ( mInputModeSwitcher.switchLanguageWithHkb() );
+ resetToIdleState ( false );
+ int allMetaState = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON
+ | KeyEvent.META_ALT_RIGHT_ON | KeyEvent.META_SHIFT_ON
+ | KeyEvent.META_SHIFT_LEFT_ON
+ | KeyEvent.META_SHIFT_RIGHT_ON | KeyEvent.META_SYM_ON;
+ getCurrentInputConnection().clearMetaKeyStates ( allMetaState );
+ return true;
+ }
+ // If HKB is on to input English, by-pass the key event so that
+ // default key listener will handle it.
+ if ( mInputModeSwitcher.isEnglishWithHkb() ) {
+ return false;
+ }
+ if ( mInputModeSwitcher.isChineseTextWithHkb() ) {
+ return false;
+ }
+ if ( mSkbContainer != null && mSkbContainer.hasFocus() && isInputViewShown() ) {
+ Log.d ( TAG, "processKeys: processChooseSoftKeys" );
+ if ( processChooseSoftKeys ( keyCode, realAction ) ) {
+ return true;
+ }
+ }
+ if ( processFunctionKeys ( keyCode, realAction ) ) {
+ return true;
+ }
+ if ( !realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT ) {
+ mShiftTag = true;
+ }
+ int keyChar = 0;
+ if ( keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z ) {
+ keyChar = keyCode - KeyEvent.KEYCODE_A + 'a';
+ } else if ( keyCode >= KeyEvent.KEYCODE_0
+ && keyCode <= KeyEvent.KEYCODE_9 ) {
+ keyChar = keyCode - KeyEvent.KEYCODE_0 + '0';
+ } else if ( keyCode == KeyEvent.KEYCODE_COMMA ) {
+ keyChar = ',';
+ } else if ( keyCode == KeyEvent.KEYCODE_PERIOD ) {
+ keyChar = '.';
+ } else if ( keyCode == KeyEvent.KEYCODE_SPACE ) {
+ keyChar = ' ';
+ } else if ( keyCode == KeyEvent.KEYCODE_APOSTROPHE ) {
+ keyChar = '\'';
+ }
+ if ( mShiftTag ) {
+ keyChar = 0;
+ }
+ if ( realAction && keyCode == KeyEvent.KEYCODE_SHIFT_LEFT ) {
+ mShiftTag = false;
+ }
+ if ( mInputModeSwitcher.isEnglishWithSkb() ) {
+ Log.d ( TAG, "processKeys: isEnglishWithSkb" );
+ return mImEn.processKey ( getCurrentInputConnection(), event,
+ mInputModeSwitcher.isEnglishUpperCaseWithSkb(), realAction );
+ } else if ( mInputModeSwitcher.isChineseText() ) {
+ if ( mImeState == ImeState.STATE_IDLE ||
+ mImeState == ImeState.STATE_APP_COMPLETION ) {
+ mImeState = ImeState.STATE_IDLE;
+ Log.d ( TAG, "processKeys: processStateIdle" );
+ return processStateIdle ( keyChar, keyCode, event, realAction );
+ } else if ( mImeState == ImeState.STATE_INPUT ) {
+ Log.d ( TAG, "processKeys: processStateInput" );
+ return processStateInput ( keyChar, keyCode, event, realAction );
+ } else if ( mImeState == ImeState.STATE_PREDICT ) {
+ Log.d ( TAG, "processKeys: processStatePredict" );
+ return processStatePredict ( keyChar, keyCode, event, realAction );
+ } else if ( mImeState == ImeState.STATE_COMPOSING ) {
+ Log.d ( TAG, "processKeys: processStateEditComposing" );
+ return processStateEditComposing ( keyChar, keyCode, event,
+ realAction );
+ }
+ } else {
+ if ( 0 != keyChar ) {
+ if ( realAction ) {
+ commitResultText ( String.valueOf ( ( char ) keyChar ) );
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean processChooseSoftKeys ( int keyCode, boolean realAction ) {
+ Log.d ( TAG, "ChooseSoftKeys: " + keyCode );
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_CENTER ) {
+ if ( !realAction ) { return true; }
+ SoftKey key = mSkbContainer.processFunctionKey ( keyCode );
+ if ( key != null ) {
+ // if(key.getKeyCode()==KeyEvent.KEYCODE_ENTER)
+ // return false;
+ responseSoftKeyEvent ( key );
+ return true;
+ }
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
+ if ( !realAction ) { return true; }
+ {
+ SoftKey key = mSkbContainer.processFunctionKey ( keyCode );
+ if ( key == null ) {
+ mSkbContainer.clearKeyFocus();
+ }
+ return true;
+ }
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ if ( !realAction ) { return true; }
+ {
+ mSkbContainer.processFunctionKey ( keyCode );
+ return true;
+ }
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_UP ) {
+ if ( !realAction ) {
+ return true;
+ }
+ {
+ SoftKey key = mSkbContainer.processFunctionKey ( keyCode );
+ if ( key == null ) {
+ mSkbContainer.clearKeyFocus();
+ if ( null != mCandidatesContainer && mCandidatesContainer.isShown()
+ && !mDecInfo.isCandidatesListEmpty() ) {
+ boolean ret = mCandidatesContainer.requestFocus();
+ Log.d ( TAG, "Candidate request focus: " + ret );
+ }
+ }
+ return true;
+ }
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
+ if ( !realAction ) {
+ return true;
+ }
+ {
+ SoftKey key = mSkbContainer.processFunctionKey ( keyCode );
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // keyCode can be from both hard key or soft key.
+ private boolean processFunctionKeys ( int keyCode, boolean realAction ) {
+ // Back key is used to dismiss all popup UI in a soft keyboard.
+ if ( keyCode == KeyEvent.KEYCODE_BACK ) {
+ if ( isInputViewShown() ) {
+ mSkbContainer.clearKeyFocus();
+ if ( mSkbContainer.handleBack ( realAction ) ) { return true; }
+ }
+ }
+ // Chinese related input is handle separately.
+ if ( mInputModeSwitcher.isChineseText() ) {
+ return false;
+ }
+ if ( null != mCandidatesContainer && mCandidatesContainer.isShown()
+ && !mDecInfo.isCandidatesListEmpty() ) {
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_CENTER ) {
+ if ( !realAction ) { return true; }
+ chooseCandidate ( -1 );
+ return true;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
+ if ( !realAction ) { return true; }
+ mCandidatesContainer.activeCurseBackward();
+ return true;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ if ( !realAction ) { return true; }
+ mCandidatesContainer.activeCurseForward();
+ return true;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_UP ) {
+ if ( !realAction ) { return true; }
+ mCandidatesContainer.pageBackward ( false, true );
+ return true;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
+ if ( !realAction ) { return true; }
+ mCandidatesContainer.pageForward ( false, true );
+ return true;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DEL &&
+ ImeState.STATE_PREDICT == mImeState ) {
+ if ( !realAction ) { return true; }
+ resetToIdleState ( false );
+ return true;
+ }
+ } else {
+ if ( keyCode == KeyEvent.KEYCODE_DEL ) {
+ if ( !realAction ) { return true; }
+ if ( SIMULATE_KEY_DELETE ) {
+ simulateKeyEventDownUp ( keyCode );
+ } else {
+ getCurrentInputConnection().deleteSurroundingText ( 1, 0 );
+ }
+ return true;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_ENTER ) {
+ if ( !realAction ) { return true; }
+ sendKeyChar ( '\n' );
+ return true;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_SPACE ) {
+ if ( !realAction ) { return true; }
+ sendKeyChar ( ' ' );
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean processStateIdle ( int keyChar, int keyCode, KeyEvent event,
+ boolean realAction ) {
+ // In this status, when user presses keys in [a..z], the status will
+ // change to input state.
+ if ( keyChar >= 'a' && keyChar <= 'z' && !event.isAltPressed() ) {
+ if ( !realAction ) { return true; }
+ mDecInfo.addSplChar ( ( char ) keyChar, true );
+ chooseAndUpdate ( -1 );
+ return true;
+ } else if ( keyCode == KeyEvent.KEYCODE_DEL ) {
+ if ( !realAction ) { return true; }
+ if ( SIMULATE_KEY_DELETE ) {
+ simulateKeyEventDownUp ( keyCode );
+ } else {
+ getCurrentInputConnection().deleteSurroundingText ( 1, 0 );
+ }
+ return true;
+ } else if ( keyCode == KeyEvent.KEYCODE_ENTER ) {
+ if ( !realAction ) { return true; }
+ sendKeyChar ( '\n' );
+ return true;
+ } else if ( keyCode == KeyEvent.KEYCODE_ALT_LEFT
+ || keyCode == KeyEvent.KEYCODE_ALT_RIGHT
+ || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
+ || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT ) {
+ return true;
+ } else if ( event.isAltPressed() ) {
+ char fullwidth_char = KeyMapDream.getChineseLabel ( keyCode );
+ if ( 0 != fullwidth_char ) {
+ if ( realAction ) {
+ String result = String.valueOf ( fullwidth_char );
+ commitResultText ( result );
+ }
+ return true;
+ } else {
+ if ( keyCode >= KeyEvent.KEYCODE_A
+ && keyCode <= KeyEvent.KEYCODE_Z ) {
+ return true;
+ }
+ }
+ } else if ( keyChar != 0 && keyChar != '\t' ) {
+ if ( realAction ) {
+ if ( keyChar == ',' || keyChar == '.' ) {
+ inputCommaPeriod ( "", keyChar, false, ImeState.STATE_IDLE );
+ } else {
+ if ( 0 != keyChar ) {
+ String result = String.valueOf ( ( char ) keyChar );
+ commitResultText ( result );
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private boolean processStateInput ( int keyChar, int keyCode, KeyEvent event,
+ boolean realAction ) {
+ // If ALT key is pressed, input alternative key. But if the
+ // alternative key is quote key, it will be used for input a splitter
+ // in Pinyin string.
+ if ( event.isAltPressed() ) {
+ if ( '\'' != event.getUnicodeChar ( event.getMetaState() ) ) {
+ if ( realAction ) {
+ char fullwidth_char = KeyMapDream.getChineseLabel ( keyCode );
+ if ( 0 != fullwidth_char ) {
+ commitResultText ( mDecInfo
+ .getCurrentFullSent ( mCandidatesContainer
+ .getActiveCandiatePos() ) +
+ String.valueOf ( fullwidth_char ) );
+ resetToIdleState ( false );
+ }
+ }
+ return true;
+ } else {
+ keyChar = '\'';
+ }
+ }
+ if ( keyChar >= 'a' && keyChar <= 'z' || keyChar == '\''
+ && !mDecInfo.charBeforeCursorIsSeparator()
+ || keyCode == KeyEvent.KEYCODE_DEL ) {
+ if ( !realAction ) { return true; }
+ return processSurfaceChange ( keyChar, keyCode );
+ } else if ( keyChar == ',' || keyChar == '.' ) {
+ if ( !realAction ) { return true; }
+ inputCommaPeriod ( mDecInfo.getCurrentFullSent ( mCandidatesContainer
+ .getActiveCandiatePos() ), keyChar, true,
+ ImeState.STATE_IDLE );
+ return true;
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_UP
+ || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
+ || keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+ || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ if ( !realAction ) { return true; }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
+ mCandidatesContainer.activeCurseBackward();
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ mCandidatesContainer.activeCurseForward();
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_UP ) {
+ // If it has been the first page, a up key will shift
+ // the state to edit composing string.
+ if ( !mCandidatesContainer.pageBackward ( false, true ) ) {
+ mCandidatesContainer.enableActiveHighlight ( false );
+ changeToStateComposing ( true );
+ updateComposingText ( true );
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
+ // mCandidatesContainer.pageForward(false, true);
+ mSkbContainer.requestFocus();
+ }
+ return true;
+ } else if ( keyCode >= KeyEvent.KEYCODE_1
+ && keyCode <= KeyEvent.KEYCODE_9 ) {
+ if ( !realAction ) { return true; }
+ int activePos = keyCode - KeyEvent.KEYCODE_1;
+ int currentPage = mCandidatesContainer.getCurrentPage();
+ if ( activePos < mDecInfo.getCurrentPageSize ( currentPage ) ) {
+ activePos = activePos
+ + mDecInfo.getCurrentPageStart ( currentPage );
+ if ( activePos >= 0 ) {
+ chooseAndUpdate ( activePos );
+ }
+ }
+ return true;
+ } else if ( keyCode == KeyEvent.KEYCODE_ENTER ) {
+ if ( !realAction ) { return true; }
+ if ( mInputModeSwitcher.isEnterNoramlState() ) {
+ commitResultText ( mDecInfo.getOrigianlSplStr().toString() );
+ resetToIdleState ( false );
+ } else {
+ commitResultText ( mDecInfo
+ .getCurrentFullSent ( mCandidatesContainer
+ .getActiveCandiatePos() ) );
+ sendKeyChar ( '\n' );
+ resetToIdleState ( false );
+ }
+ return true;
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+ || keyCode == KeyEvent.KEYCODE_SPACE ) {
+ if ( !realAction ) { return true; }
+ chooseCandidate ( -1 );
+ return true;
+ } else if ( keyCode == KeyEvent.KEYCODE_BACK ) {
+ if ( !realAction ) { return true; }
+ resetToIdleState ( false );
+ requestHideSelf ( 0 );
+ return true;
+ }
+ return false;
+ }
+
+ private boolean processStatePredict ( int keyChar, int keyCode,
+ KeyEvent event, boolean realAction ) {
+ if ( KeyEvent.isGamepadButton ( keyCode ) ) { return false; }
+ if ( !realAction ) { return true; }
+ // If ALT key is pressed, input alternative key.
+ if ( event.isAltPressed() ) {
+ char fullwidth_char = KeyMapDream.getChineseLabel ( keyCode );
+ if ( 0 != fullwidth_char ) {
+ commitResultText ( mDecInfo.getCandidate ( mCandidatesContainer
+ .getActiveCandiatePos() ) +
+ String.valueOf ( fullwidth_char ) );
+ resetToIdleState ( false );
+ }
+ return true;
+ }
+ // In this status, when user presses keys in [a..z], the status will
+ // change to input state.
+ if ( keyChar >= 'a' && keyChar <= 'z' ) {
+ changeToStateInput ( true );
+ mDecInfo.addSplChar ( ( char ) keyChar, true );
+ chooseAndUpdate ( -1 );
+ } else if ( keyChar == ',' || keyChar == '.' ) {
+ inputCommaPeriod ( "", keyChar, true, ImeState.STATE_IDLE );
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_UP
+ || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
+ || keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+ || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
+ mCandidatesContainer.activeCurseBackward();
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ mCandidatesContainer.activeCurseForward();
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_UP ) {
+ mCandidatesContainer.pageBackward ( false, true );
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
+ // mCandidatesContainer.pageForward(false, true);
+ mSkbContainer.requestFocus();
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_DEL ) {
+ resetToIdleState ( false );
+ } else if ( keyCode == KeyEvent.KEYCODE_BACK ) {
+ resetToIdleState ( false );
+ requestHideSelf ( 0 );
+ } else if ( keyCode >= KeyEvent.KEYCODE_1
+ && keyCode <= KeyEvent.KEYCODE_9 ) {
+ int activePos = keyCode - KeyEvent.KEYCODE_1;
+ int currentPage = mCandidatesContainer.getCurrentPage();
+ if ( activePos < mDecInfo.getCurrentPageSize ( currentPage ) ) {
+ activePos = activePos
+ + mDecInfo.getCurrentPageStart ( currentPage );
+ if ( activePos >= 0 ) {
+ chooseAndUpdate ( activePos );
+ }
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_ENTER ) {
+ sendKeyChar ( '\n' );
+ resetToIdleState ( false );
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+ || keyCode == KeyEvent.KEYCODE_SPACE ) {
+ chooseCandidate ( -1 );
+ }
+ return true;
+ }
+
+ private boolean processStateEditComposing ( int keyChar, int keyCode,
+ KeyEvent event, boolean realAction ) {
+ if ( !realAction ) { return true; }
+ ComposingView.ComposingStatus cmpsvStatus =
+ mComposingView.getComposingStatus();
+ // If ALT key is pressed, input alternative key. But if the
+ // alternative key is quote key, it will be used for input a splitter
+ // in Pinyin string.
+ if ( event.isAltPressed() ) {
+ if ( '\'' != event.getUnicodeChar ( event.getMetaState() ) ) {
+ char fullwidth_char = KeyMapDream.getChineseLabel ( keyCode );
+ if ( 0 != fullwidth_char ) {
+ String retStr;
+ if ( ComposingView.ComposingStatus.SHOW_STRING_LOWERCASE ==
+ cmpsvStatus ) {
+ retStr = mDecInfo.getOrigianlSplStr().toString();
+ } else {
+ retStr = mDecInfo.getComposingStr();
+ }
+ commitResultText ( retStr + String.valueOf ( fullwidth_char ) );
+ resetToIdleState ( false );
+ }
+ return true;
+ } else {
+ keyChar = '\'';
+ }
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
+ if ( !mDecInfo.selectionFinished() ) {
+ changeToStateInput ( true );
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+ || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ mComposingView.moveCursor ( keyCode );
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+ || keyCode == KeyEvent.KEYCODE_SPACE ) {
+ if ( ComposingView.ComposingStatus.SHOW_STRING_LOWERCASE == cmpsvStatus ) {
+ String str = mDecInfo.getOrigianlSplStr().toString();
+ if ( !tryInputRawUnicode ( str ) ) {
+ commitResultText ( str );
+ }
+ } else if ( ComposingView.ComposingStatus.EDIT_PINYIN == cmpsvStatus ) {
+ String str = mDecInfo.getComposingStr();
+ if ( !tryInputRawUnicode ( str ) ) {
+ commitResultText ( str );
+ }
+ } else {
+ commitResultText ( mDecInfo.getComposingStr() );
+ }
+ resetToIdleState ( false );
+ } else if ( keyCode == KeyEvent.KEYCODE_ENTER
+ && !mInputModeSwitcher.isEnterNoramlState() ) {
+ String retStr;
+ if ( !mDecInfo.isCandidatesListEmpty() ) {
+ retStr = mDecInfo.getCurrentFullSent ( mCandidatesContainer
+ .getActiveCandiatePos() );
+ } else {
+ retStr = mDecInfo.getComposingStr();
+ }
+ commitResultText ( retStr );
+ sendKeyChar ( '\n' );
+ resetToIdleState ( false );
+ } else if ( keyCode == KeyEvent.KEYCODE_BACK ) {
+ resetToIdleState ( false );
+ requestHideSelf ( 0 );
+ return true;
+ } else {
+ return processSurfaceChange ( keyChar, keyCode );
+ }
+ return true;
+ }
+
+ private boolean tryInputRawUnicode ( String str ) {
+ if ( str.length() > 7 ) {
+ if ( str.substring ( 0, 7 ).compareTo ( "unicode" ) == 0 ) {
+ try {
+ String digitStr = str.substring ( 7 );
+ int startPos = 0;
+ int radix = 10;
+ if ( digitStr.length() > 2 && digitStr.charAt ( 0 ) == '0'
+ && digitStr.charAt ( 1 ) == 'x' ) {
+ startPos = 2;
+ radix = 16;
+ }
+ digitStr = digitStr.substring ( startPos );
+ int unicode = Integer.parseInt ( digitStr, radix );
+ if ( unicode > 0 ) {
+ char low = ( char ) ( unicode & 0x0000ffff );
+ char high = ( char ) ( ( unicode & 0xffff0000 ) >> 16 );
+ commitResultText ( String.valueOf ( low ) );
+ if ( 0 != high ) {
+ commitResultText ( String.valueOf ( high ) );
+ }
+ }
+ return true;
+ } catch ( NumberFormatException e ) {
+ return false;
+ }
+ } else if ( str.substring ( str.length() - 7, str.length() ).compareTo (
+ "unicode" ) == 0 ) {
+ String resultStr = "";
+ for ( int pos = 0; pos < str.length() - 7; pos++ ) {
+ if ( pos > 0 ) {
+ resultStr += " ";
+ }
+ resultStr += "0x" + Integer.toHexString ( str.charAt ( pos ) );
+ }
+ commitResultText ( String.valueOf ( resultStr ) );
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean processSurfaceChange ( int keyChar, int keyCode ) {
+ if ( mDecInfo.isSplStrFull() && KeyEvent.KEYCODE_DEL != keyCode ) {
+ return true;
+ }
+ if ( ( keyChar >= 'a' && keyChar <= 'z' )
+ || ( keyChar == '\'' && !mDecInfo.charBeforeCursorIsSeparator() )
+ || ( ( ( keyChar >= '0' && keyChar <= '9' ) || keyChar == ' ' ) && ImeState.STATE_COMPOSING == mImeState ) ) {
+ mDecInfo.addSplChar ( ( char ) keyChar, false );
+ chooseAndUpdate ( -1 );
+ } else if ( keyCode == KeyEvent.KEYCODE_DEL ) {
+ mDecInfo.prepareDeleteBeforeCursor();
+ chooseAndUpdate ( -1 );
+ }
+ return true;
+ }
+
+ private void changeToStateComposing ( boolean updateUi ) {
+ mImeState = ImeState.STATE_COMPOSING;
+ if ( !updateUi ) { return; }
+ if ( null != mSkbContainer && mSkbContainer.isShown() ) {
+ mSkbContainer.toggleCandidateMode ( true );
+ }
+ }
+
+ private void changeToStateInput ( boolean updateUi ) {
+ mImeState = ImeState.STATE_INPUT;
+ if ( !updateUi ) { return; }
+ if ( null != mSkbContainer && mSkbContainer.isShown() ) {
+ mSkbContainer.toggleCandidateMode ( true );
+ }
+ showCandidateWindow ( true );
+ }
+
+ private void simulateKeyEventDownUp ( int keyCode ) {
+ InputConnection ic = getCurrentInputConnection();
+ if ( null == ic ) { return; }
+ ic.sendKeyEvent ( new KeyEvent ( KeyEvent.ACTION_DOWN, keyCode ) );
+ ic.sendKeyEvent ( new KeyEvent ( KeyEvent.ACTION_UP, keyCode ) );
+ }
+
+ private void commitResultText ( String resultText ) {
+ InputConnection ic = getCurrentInputConnection();
+ if ( null != ic ) { ic.commitText ( resultText, 1 ); }
+ if ( null != mComposingView ) {
+ mComposingView.setVisibility ( View.INVISIBLE );
+ mComposingView.invalidate();
+ }
+ }
+
+ private void updateComposingText ( boolean visible ) {
+ if ( !visible ) {
+ mComposingView.setVisibility ( View.INVISIBLE );
+ } else {
+ mComposingView.setDecodingInfo ( mDecInfo, mImeState );
+ mComposingView.setVisibility ( View.VISIBLE );
+ }
+ mComposingView.invalidate();
+ }
+
+ private void inputCommaPeriod ( String preEdit, int keyChar,
+ boolean dismissCandWindow, ImeState nextState ) {
+ if ( keyChar == ',' ) {
+ preEdit += '\uff0c';
+ } else if ( keyChar == '.' ) {
+ preEdit += '\u3002';
+ } else {
+ return;
+ }
+ commitResultText ( preEdit );
+ if ( dismissCandWindow ) { resetCandidateWindow(); }
+ mImeState = nextState;
+ }
+
+ private void resetToIdleState ( boolean resetInlineText ) {
+ if ( ImeState.STATE_IDLE == mImeState ) { return; }
+ mImeState = ImeState.STATE_IDLE;
+ mDecInfo.reset();
+ if ( null != mComposingView ) { mComposingView.reset(); }
+ if ( resetInlineText ) { commitResultText ( "" ); }
+ resetCandidateWindow();
+ setCandidatesViewShown ( false );
+ // boolean ret = mSkbContainer.requestFocus();
+ // Log.d(TAG, "reset to idle:" + ret + ", hasFocus:"+mSkbContainer.hasFocus());
+ }
+
+ private void chooseAndUpdate ( int candId ) {
+ if ( !mInputModeSwitcher.isChineseText() ) {
+ String choice = mDecInfo.getCandidate ( candId );
+ if ( null != choice ) {
+ commitResultText ( choice );
+ }
+ resetToIdleState ( false );
+ return;
+ }
+ if ( ImeState.STATE_PREDICT != mImeState ) {
+ // Get result candidate list, if choice_id < 0, do a new decoding.
+ // If choice_id >=0, select the candidate, and get the new candidate
+ // list.
+ mDecInfo.chooseDecodingCandidate ( candId );
+ } else {
+ // Choose a prediction item.
+ mDecInfo.choosePredictChoice ( candId );
+ }
+ if ( mDecInfo.getComposingStr().length() > 0 ) {
+ String resultStr;
+ resultStr = mDecInfo.getComposingStrActivePart();
+ // choiceId >= 0 means user finishes a choice selection.
+ if ( candId >= 0 && mDecInfo.canDoPrediction() ) {
+ commitResultText ( resultStr );
+ mImeState = ImeState.STATE_PREDICT;
+ if ( null != mSkbContainer && mSkbContainer.isShown() ) {
+ mSkbContainer.toggleCandidateMode ( false );
+ }
+ // Try to get the prediction list.
+ if ( Settings.getPrediction() ) {
+ InputConnection ic = getCurrentInputConnection();
+ if ( null != ic ) {
+ CharSequence cs = ic.getTextBeforeCursor ( 3, 0 );
+ if ( null != cs ) {
+ mDecInfo.preparePredicts ( cs );
+ }
+ }
+ } else {
+ mDecInfo.resetCandidates();
+ }
+ if ( mDecInfo.mCandidatesList.size() > 0 ) {
+ showCandidateWindow ( false );
+ } else {
+ resetToIdleState ( false );
+ }
+ } else {
+ if ( ImeState.STATE_IDLE == mImeState ) {
+ if ( mDecInfo.getSplStrDecodedLen() == 0 ) {
+ changeToStateComposing ( true );
+ } else {
+ changeToStateInput ( true );
+ }
+ } else {
+ if ( mDecInfo.selectionFinished() ) {
+ changeToStateComposing ( true );
+ }
+ }
+ showCandidateWindow ( true );
+ }
+ } else {
+ resetToIdleState ( false );
+ }
+ }
+
+ // If activeCandNo is less than 0, get the current active candidate number
+ // from candidate view, otherwise use activeCandNo.
+ private void chooseCandidate ( int activeCandNo ) {
+ if ( activeCandNo < 0 ) {
+ activeCandNo = mCandidatesContainer.getActiveCandiatePos();
+ }
+ if ( activeCandNo >= 0 ) {
+ chooseAndUpdate ( activeCandNo );
+ }
+ }
+
+ private boolean startPinyinDecoderService() {
+ if ( null == mDecInfo.mIPinyinDecoderService ) {
+ Intent serviceIntent = new Intent();
+ serviceIntent.setClass ( this, PinyinDecoderService.class );
+ if ( null == mPinyinDecoderServiceConnection ) {
+ mPinyinDecoderServiceConnection = new PinyinDecoderServiceConnection();
+ }
+ // Bind service
+ if ( bindService ( serviceIntent, mPinyinDecoderServiceConnection,
+ Context.BIND_AUTO_CREATE ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public View onCreateCandidatesView() {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onCreateCandidatesView." );
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ // Inflate the floating container view
+ mFloatingContainer = ( LinearLayout ) inflater.inflate (
+ R.layout.floating_container, null );
+ // The first child is the composing view.
+ mComposingView = ( ComposingView ) mFloatingContainer.getChildAt ( 0 );
+ mCandidatesContainer = ( CandidatesContainer ) inflater.inflate (
+ R.layout.candidates_container, null );
+ // Create balloon hint for candidates view.
+ mCandidatesBalloon = new BalloonHint ( this, mCandidatesContainer,
+ MeasureSpec.UNSPECIFIED );
+ mCandidatesBalloon.setBalloonBackground ( getResources().getDrawable (
+ R.drawable.candidate_balloon_bg ) );
+ mCandidatesContainer.initialize ( mChoiceNotifier, mCandidatesBalloon,
+ mGestureDetectorCandidates );
+ // The floating window
+ if ( null != mFloatingWindow && mFloatingWindow.isShowing() ) {
+ mFloatingWindowTimer.cancelShowing();
+ mFloatingWindow.dismiss();
+ }
+ mFloatingWindow = new PopupWindow ( this );
+ mFloatingWindow.setClippingEnabled ( false );
+ mFloatingWindow.setBackgroundDrawable ( null );
+ mFloatingWindow.setInputMethodMode ( PopupWindow.INPUT_METHOD_NOT_NEEDED );
+ mFloatingWindow.setContentView ( mFloatingContainer );
+ setCandidatesViewShown ( true );
+ return mCandidatesContainer;
+ }
+
+
+ @Override
+ public boolean onEvaluateFullscreenMode() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void responseSoftKeyEvent ( SoftKey sKey ) {
+ if ( null == sKey ) { return; }
+ InputConnection ic = getCurrentInputConnection();
+ if ( ic == null ) { return; }
+ int keyCode = sKey.getKeyCode();
+ // Process some general keys, including KEYCODE_DEL, KEYCODE_SPACE,
+ // KEYCODE_ENTER and KEYCODE_DPAD_CENTER.
+ if ( sKey.isKeyCodeKey() ) {
+ if ( processFunctionKeys ( keyCode, true ) ) { return; }
+ }
+ if ( sKey.isUserDefKey() ) {
+ updateIcon ( mInputModeSwitcher.switchModeForUserKey ( keyCode ) );
+ resetToIdleState ( false );
+ mSkbContainer.updateInputMode ( true );
+ } else {
+ if ( sKey.isKeyCodeKey() ) {
+ KeyEvent eDown = new KeyEvent ( 0, 0, KeyEvent.ACTION_DOWN,
+ keyCode, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD );
+ KeyEvent eUp = new KeyEvent ( 0, 0, KeyEvent.ACTION_UP, keyCode,
+ 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD );
+ onKeyDown ( keyCode, eDown );
+ onKeyUp ( keyCode, eUp );
+ } else if ( sKey.isUniStrKey() ) {
+ boolean kUsed = false;
+ String keyLabel = sKey.getKeyLabel();
+ if ( mInputModeSwitcher.isChineseTextWithSkb()
+ && ( ImeState.STATE_INPUT == mImeState || ImeState.STATE_COMPOSING == mImeState ) ) {
+ if ( mDecInfo.length() > 0 && keyLabel.length() == 1
+ && keyLabel.charAt ( 0 ) == '\'' ) {
+ processSurfaceChange ( '\'', 0 );
+ kUsed = true;
+ }
+ }
+ if ( !kUsed ) {
+ if ( ImeState.STATE_INPUT == mImeState ) {
+ commitResultText ( mDecInfo
+ .getCurrentFullSent ( mCandidatesContainer
+ .getActiveCandiatePos() ) );
+ } else if ( ImeState.STATE_COMPOSING == mImeState ) {
+ commitResultText ( mDecInfo.getComposingStr() );
+ }
+ commitResultText ( keyLabel );
+ resetToIdleState ( false );
+ }
+ }
+ // If the current soft keyboard is not sticky, IME needs to go
+ // back to the previous soft keyboard automatically.
+ if ( !mSkbContainer.isCurrentSkbSticky() ) {
+ updateIcon ( mInputModeSwitcher.requestBackToPreviousSkb() );
+ resetToIdleState ( false );
+ mSkbContainer.updateInputMode();
+ }
+ }
+ }
+
+ private void showCandidateWindow ( boolean showComposingView ) {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "Candidates window is shown. Parent = "
+ + mCandidatesContainer );
+ }
+ setCandidatesViewShown ( true );
+ if ( null != mSkbContainer ) { mSkbContainer.requestLayout(); }
+ if ( null == mCandidatesContainer ) {
+ resetToIdleState ( false );
+ return;
+ }
+ updateComposingText ( showComposingView );
+ mCandidatesContainer.showCandidates ( mDecInfo,
+ ImeState.STATE_COMPOSING != mImeState );
+ mFloatingWindowTimer.postShowFloatingWindow();
+ }
+
+ private void dismissCandidateWindow() {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "Candidates window is to be dismissed" );
+ }
+ if ( null == mCandidatesContainer ) { return; }
+ try {
+ mFloatingWindowTimer.cancelShowing();
+ mFloatingWindow.dismiss();
+ } catch ( Exception e ) {
+ Log.e ( TAG, "Fail to show the PopupWindow." );
+ }
+ setCandidatesViewShown ( false );
+ if ( null != mSkbContainer && mSkbContainer.isShown() ) {
+ mSkbContainer.toggleCandidateMode ( false );
+ }
+ }
+
+ private void resetCandidateWindow() {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "Candidates window is to be reset" );
+ }
+ if ( null == mCandidatesContainer ) { return; }
+ try {
+ mFloatingWindowTimer.cancelShowing();
+ mFloatingWindow.dismiss();
+ } catch ( Exception e ) {
+ Log.e ( TAG, "Fail to show the PopupWindow." );
+ }
+ if ( null != mSkbContainer && mSkbContainer.isShown() ) {
+ mSkbContainer.toggleCandidateMode ( false );
+ }
+ mDecInfo.resetCandidates();
+ if ( null != mCandidatesContainer && mCandidatesContainer.isShown() ) {
+ showCandidateWindow ( false );
+ }
+ }
+
+ private void updateIcon ( int iconId ) {
+ if ( iconId > 0 ) {
+ showStatusIcon ( iconId );
+ } else {
+ hideStatusIcon();
+ }
+ }
+
+ @Override
+ public View onCreateInputView() {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onCreateInputView." );
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ mSkbContainer = ( SkbContainer ) inflater.inflate ( R.layout.skb_container,
+ null );
+ mSkbContainer.setService ( this );
+ mSkbContainer.setInputModeSwitcher ( mInputModeSwitcher );
+ mSkbContainer.setGestureDetector ( mGestureDetectorSkb );
+ return mSkbContainer;
+ }
+
+ @Override
+ public void onStartInput ( EditorInfo editorInfo, boolean restarting ) {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onStartInput " + " ccontentType: "
+ + String.valueOf ( editorInfo.inputType ) + " Restarting:"
+ + String.valueOf ( restarting ) );
+ }
+ updateIcon ( mInputModeSwitcher.requestInputWithHkb ( editorInfo ) );
+ resetToIdleState ( false );
+ }
+
+ @Override
+ public void onStartInputView ( EditorInfo editorInfo, boolean restarting ) {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onStartInputView " + " contentType: "
+ + String.valueOf ( editorInfo.inputType ) + " Restarting:"
+ + String.valueOf ( restarting ) );
+ }
+ updateIcon ( mInputModeSwitcher.requestInputWithSkb ( editorInfo ) );
+ resetToIdleState ( false );
+ mSkbContainer.updateInputMode ( true );
+ setCandidatesViewShown ( false );
+ mSkbContainer.requestFocus();
+ mSkbContainer.clearKeyFocus();
+ }
+
+ @Override
+ public void onFinishInputView ( boolean finishingInput ) {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onFinishInputView." );
+ }
+ resetToIdleState ( false );
+ super.onFinishInputView ( finishingInput );
+ }
+
+ @Override
+ public void onFinishInput() {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onFinishInput." );
+ }
+ resetToIdleState ( false );
+ super.onFinishInput();
+ }
+
+ @Override
+ public void onFinishCandidatesView ( boolean finishingInput ) {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "onFinishCandidateView." );
+ }
+ resetToIdleState ( false );
+ super.onFinishCandidatesView ( finishingInput );
+ }
+
+ @Override public void onDisplayCompletions ( CompletionInfo[] completions ) {
+ if ( !isFullscreenMode() ) { return; }
+ if ( null == completions || completions.length <= 0 ) { return; }
+ if ( null == mSkbContainer || !mSkbContainer.isShown() ) { return; }
+ if ( !mInputModeSwitcher.isChineseText() ||
+ ImeState.STATE_IDLE == mImeState ||
+ ImeState.STATE_PREDICT == mImeState ) {
+ mImeState = ImeState.STATE_APP_COMPLETION;
+ mDecInfo.prepareAppCompletions ( completions );
+ showCandidateWindow ( false );
+ }
+ }
+
+ private void onChoiceTouched ( int activeCandNo ) {
+ if ( mImeState == ImeState.STATE_COMPOSING ) {
+ changeToStateInput ( true );
+ } else if ( mImeState == ImeState.STATE_INPUT
+ || mImeState == ImeState.STATE_PREDICT ) {
+ chooseCandidate ( activeCandNo );
+ } else if ( mImeState == ImeState.STATE_APP_COMPLETION ) {
+ if ( null != mDecInfo.mAppCompletions && activeCandNo >= 0 &&
+ activeCandNo < mDecInfo.mAppCompletions.length ) {
+ CompletionInfo ci = mDecInfo.mAppCompletions[activeCandNo];
+ if ( null != ci ) {
+ InputConnection ic = getCurrentInputConnection();
+ ic.commitCompletion ( ci );
+ }
+ }
+ resetToIdleState ( false );
+ }
+ }
+
+ @Override
+ public void requestHideSelf ( int flags ) {
+ if ( mEnvironment.needDebug() ) {
+ Log.d ( TAG, "DimissSoftInput." );
+ }
+ dismissCandidateWindow();
+ if ( null != mSkbContainer && mSkbContainer.isShown() ) {
+ mSkbContainer.dismissPopups();
+ }
+ super.requestHideSelf ( flags );
+ }
+
+ public void showOptionsMenu() {
+ AlertDialog.Builder builder = new AlertDialog.Builder ( this );
+ builder.setCancelable ( true );
+ builder.setIcon ( R.drawable.app_icon );
+ builder.setNegativeButton ( android.R.string.cancel, null );
+ CharSequence itemSettings = getString ( R.string.ime_settings_activity_name );
+ CharSequence itemInputMethod = getString ( com.android.internal.R.string.inputMethod );
+ builder.setItems ( new CharSequence[] {itemSettings, itemInputMethod},
+ new DialogInterface.OnClickListener() {
+ public void onClick ( DialogInterface di, int position ) {
+ di.dismiss();
+ switch ( position ) {
+ case 0:
+ launchSettings();
+ break;
+ case 1:
+ //InputMethodManager.getInstance(RemoteIME.this)
+ // .showInputMethodPicker();
+ InputMethodManager.getInstance()
+ .showInputMethodPicker();
+ break;
+ }
+ }
+ } );
+ builder.setTitle ( getString ( R.string.ime_name ) );
+ mOptionsDialog = builder.create();
+ Window window = mOptionsDialog.getWindow();
+ WindowManager.LayoutParams lp = window.getAttributes();
+ lp.token = mSkbContainer.getWindowToken();
+ lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+ window.setAttributes ( lp );
+ window.addFlags ( WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM );
+ mOptionsDialog.show();
+ }
+
+ private void launchSettings() {
+ Intent intent = new Intent();
+ intent.setClass ( RemoteIME.this, SettingsActivity.class );
+ intent.setFlags ( Intent.FLAG_ACTIVITY_NEW_TASK );
+ startActivity ( intent );
+ }
+
+ private class PopupTimer extends Handler implements Runnable {
+ private int mParentLocation[] = new int[2];
+
+ void postShowFloatingWindow() {
+ mFloatingContainer.measure ( LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT );
+ mFloatingWindow.setWidth ( mFloatingContainer.getMeasuredWidth() );
+ mFloatingWindow.setHeight ( mFloatingContainer.getMeasuredHeight() );
+ post ( this );
+ }
+
+ void cancelShowing() {
+ if ( mFloatingWindow.isShowing() ) {
+ mFloatingWindow.dismiss();
+ }
+ removeCallbacks ( this );
+ }
+
+ public void run() {
+ mCandidatesContainer.getLocationInWindow ( mParentLocation );
+ if ( !mFloatingWindow.isShowing() ) {
+ mFloatingWindow.showAtLocation ( mCandidatesContainer,
+ Gravity.LEFT | Gravity.TOP, mParentLocation[0],
+ mParentLocation[1] - mFloatingWindow.getHeight() );
+ } else {
+ mFloatingWindow
+ .update ( mParentLocation[0],
+ mParentLocation[1] - mFloatingWindow.getHeight(),
+ mFloatingWindow.getWidth(),
+ mFloatingWindow.getHeight() );
+ }
+ }
+ }
+
+ /**
+ * Used to notify IME that the user selects a candidate or performs an
+ * gesture.
+ */
+ public class ChoiceNotifier extends Handler implements
+ CandidateViewListener {
+ RemoteIME mIme;
+
+ ChoiceNotifier ( RemoteIME ime ) {
+ mIme = ime;
+ }
+
+ public void onClickChoice ( int choiceId ) {
+ if ( choiceId >= 0 ) {
+ mIme.onChoiceTouched ( choiceId );
+ }
+ }
+
+ public void onToLeftGesture() {
+ if ( ImeState.STATE_COMPOSING == mImeState ) {
+ changeToStateInput ( true );
+ }
+ mCandidatesContainer.pageForward ( true, false );
+ }
+
+ public void onToRightGesture() {
+ if ( ImeState.STATE_COMPOSING == mImeState ) {
+ changeToStateInput ( true );
+ }
+ mCandidatesContainer.pageBackward ( true, false );
+ }
+
+ public void onToTopGesture() {
+ }
+
+ public void onToBottomGesture() {
+ }
+ }
+
+ public class OnGestureListener extends
+ GestureDetector.SimpleOnGestureListener {
+ /**
+ * When user presses and drags, the minimum x-distance to make a
+ * response to the drag event.
+ */
+ private static final int MIN_X_FOR_DRAG = 60;
+
+ /**
+ * When user presses and drags, the minimum y-distance to make a
+ * response to the drag event.
+ */
+ private static final int MIN_Y_FOR_DRAG = 40;
+
+ /**
+ * Velocity threshold for a screen-move gesture. If the minimum
+ * x-velocity is less than it, no gesture.
+ */
+ static private final float VELOCITY_THRESHOLD_X1 = 0.3f;
+
+ /**
+ * Velocity threshold for a screen-move gesture. If the maximum
+ * x-velocity is less than it, no gesture.
+ */
+ static private final float VELOCITY_THRESHOLD_X2 = 0.7f;
+
+ /**
+ * Velocity threshold for a screen-move gesture. If the minimum
+ * y-velocity is less than it, no gesture.
+ */
+ static private final float VELOCITY_THRESHOLD_Y1 = 0.2f;
+
+ /**
+ * Velocity threshold for a screen-move gesture. If the maximum
+ * y-velocity is less than it, no gesture.
+ */
+ static private final float VELOCITY_THRESHOLD_Y2 = 0.45f;
+
+ /** If it false, we will not response detected gestures. */
+ private boolean mReponseGestures;
+
+ /** The minimum X velocity observed in the gesture. */
+ private float mMinVelocityX = Float.MAX_VALUE;
+
+ /** The minimum Y velocity observed in the gesture. */
+ private float mMinVelocityY = Float.MAX_VALUE;
+
+ /** The first down time for the series of touch events for an action. */
+ private long mTimeDown;
+
+ /** The last time when onScroll() is called. */
+ private long mTimeLastOnScroll;
+
+ /** This flag used to indicate that this gesture is not a gesture. */
+ private boolean mNotGesture;
+
+ /** This flag used to indicate that this gesture has been recognized. */
+ private boolean mGestureRecognized;
+
+ public OnGestureListener ( boolean reponseGestures ) {
+ mReponseGestures = reponseGestures;
+ }
+
+ @Override
+ public boolean onDown ( MotionEvent e ) {
+ mMinVelocityX = Integer.MAX_VALUE;
+ mMinVelocityY = Integer.MAX_VALUE;
+ mTimeDown = e.getEventTime();
+ mTimeLastOnScroll = mTimeDown;
+ mNotGesture = false;
+ mGestureRecognized = false;
+ return false;
+ }
+
+ @Override
+ public boolean onScroll ( MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY ) {
+ if ( mNotGesture ) { return false; }
+ if ( mGestureRecognized ) { return true; }
+ if ( Math.abs ( e1.getX() - e2.getX() ) < MIN_X_FOR_DRAG
+ && Math.abs ( e1.getY() - e2.getY() ) < MIN_Y_FOR_DRAG ) {
+ return false;
+ }
+ long timeNow = e2.getEventTime();
+ long spanTotal = timeNow - mTimeDown;
+ long spanThis = timeNow - mTimeLastOnScroll;
+ if ( 0 == spanTotal ) { spanTotal = 1; }
+ if ( 0 == spanThis ) { spanThis = 1; }
+ float vXTotal = ( e2.getX() - e1.getX() ) / spanTotal;
+ float vYTotal = ( e2.getY() - e1.getY() ) / spanTotal;
+ // The distances are from the current point to the previous one.
+ float vXThis = -distanceX / spanThis;
+ float vYThis = -distanceY / spanThis;
+ float kX = vXTotal * vXThis;
+ float kY = vYTotal * vYThis;
+ float k1 = kX + kY;
+ float k2 = Math.abs ( kX ) + Math.abs ( kY );
+ if ( k1 / k2 < 0.8 ) {
+ mNotGesture = true;
+ return false;
+ }
+ float absVXTotal = Math.abs ( vXTotal );
+ float absVYTotal = Math.abs ( vYTotal );
+ if ( absVXTotal < mMinVelocityX ) {
+ mMinVelocityX = absVXTotal;
+ }
+ if ( absVYTotal < mMinVelocityY ) {
+ mMinVelocityY = absVYTotal;
+ }
+ if ( mMinVelocityX < VELOCITY_THRESHOLD_X1
+ && mMinVelocityY < VELOCITY_THRESHOLD_Y1 ) {
+ mNotGesture = true;
+ return false;
+ }
+ if ( vXTotal > VELOCITY_THRESHOLD_X2
+ && absVYTotal < VELOCITY_THRESHOLD_Y2 ) {
+ if ( mReponseGestures ) { onDirectionGesture ( Gravity.RIGHT ); }
+ mGestureRecognized = true;
+ } else if ( vXTotal < -VELOCITY_THRESHOLD_X2
+ && absVYTotal < VELOCITY_THRESHOLD_Y2 ) {
+ if ( mReponseGestures ) { onDirectionGesture ( Gravity.LEFT ); }
+ mGestureRecognized = true;
+ } else if ( vYTotal > VELOCITY_THRESHOLD_Y2
+ && absVXTotal < VELOCITY_THRESHOLD_X2 ) {
+ if ( mReponseGestures ) { onDirectionGesture ( Gravity.BOTTOM ); }
+ mGestureRecognized = true;
+ } else if ( vYTotal < -VELOCITY_THRESHOLD_Y2
+ && absVXTotal < VELOCITY_THRESHOLD_X2 ) {
+ if ( mReponseGestures ) { onDirectionGesture ( Gravity.TOP ); }
+ mGestureRecognized = true;
+ }
+ mTimeLastOnScroll = timeNow;
+ return mGestureRecognized;
+ }
+
+ @Override
+ public boolean onFling ( MotionEvent me1, MotionEvent me2,
+ float velocityX, float velocityY ) {
+ return mGestureRecognized;
+ }
+
+ public void onDirectionGesture ( int gravity ) {
+ if ( Gravity.NO_GRAVITY == gravity ) {
+ return;
+ }
+ if ( Gravity.LEFT == gravity || Gravity.RIGHT == gravity ) {
+ if ( mCandidatesContainer.isShown() ) {
+ if ( Gravity.LEFT == gravity ) {
+ mCandidatesContainer.pageForward ( true, true );
+ } else {
+ mCandidatesContainer.pageBackward ( true, true );
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Connection used for binding to the Pinyin decoding service.
+ */
+ public class PinyinDecoderServiceConnection implements ServiceConnection {
+ public void onServiceConnected ( ComponentName name, IBinder service ) {
+ mDecInfo.mIPinyinDecoderService = IPinyinDecoderService.Stub
+ .asInterface ( service );
+ }
+
+ public void onServiceDisconnected ( ComponentName name ) {
+ }
+ }
+
+ public enum ImeState {
+ STATE_BYPASS, STATE_IDLE, STATE_INPUT, STATE_COMPOSING, STATE_PREDICT,
+ STATE_APP_COMPLETION
+ }
+
+ public class DecodingInfo {
+ /**
+ * Maximum length of the Pinyin string
+ */
+ private static final int PY_STRING_MAX = 28;
+
+ /**
+ * Maximum number of candidates to display in one page.
+ */
+ private static final int MAX_PAGE_SIZE_DISPLAY = 10;
+
+ /**
+ * Spelling (Pinyin) string.
+ */
+ private StringBuffer mSurface;
+
+ /**
+ * Byte buffer used as the Pinyin string parameter for native function
+ * call.
+ */
+ private byte mPyBuf[];
+
+ /**
+ * The length of surface string successfully decoded by engine.
+ */
+ private int mSurfaceDecodedLen;
+
+ /**
+ * Composing string.
+ */
+ private String mComposingStr;
+
+ /**
+ * Length of the active composing string.
+ */
+ private int mActiveCmpsLen;
+
+ /**
+ * Composing string for display, it is copied from mComposingStr, and
+ * add spaces between spellings.
+ **/
+ private String mComposingStrDisplay;
+
+ /**
+ * Length of the active composing string for display.
+ */
+ private int mActiveCmpsDisplayLen;
+
+ /**
+ * The first full sentence choice.
+ */
+ private String mFullSent;
+
+ /**
+ * Number of characters which have been fixed.
+ */
+ private int mFixedLen;
+
+ /**
+ * If this flag is true, selection is finished.
+ */
+ private boolean mFinishSelection;
+
+ /**
+ * The starting position for each spelling. The first one is the number
+ * of the real starting position elements.
+ */
+ private int mSplStart[];
+
+ /**
+ * Editing cursor in mSurface.
+ */
+ private int mCursorPos;
+
+ /**
+ * Remote Pinyin-to-Hanzi decoding engine service.
+ */
+ private IPinyinDecoderService mIPinyinDecoderService;
+
+ /**
+ * The complication information suggested by application.
+ */
+ private CompletionInfo[] mAppCompletions;
+
+ /**
+ * The total number of choices for display. The list may only contains
+ * the first part. If user tries to navigate to next page which is not
+ * in the result list, we need to get these items.
+ **/
+ public int mTotalChoicesNum;
+
+ /**
+ * Candidate list. The first one is the full-sentence candidate.
+ */
+ public List<String> mCandidatesList = new Vector<String>();
+
+ /**
+ * Element i stores the starting position of page i.
+ */
+ public Vector<Integer> mPageStart = new Vector<Integer>();
+
+ /**
+ * Element i stores the number of characters to page i.
+ */
+ public Vector<Integer> mCnToPage = new Vector<Integer>();
+
+ /**
+ * The position to delete in Pinyin string. If it is less than 0, IME
+ * will do an incremental search, otherwise IME will do a deletion
+ * operation. if {@link #mIsPosInSpl} is true, IME will delete the whole
+ * string for mPosDelSpl-th spelling, otherwise it will only delete
+ * mPosDelSpl-th character in the Pinyin string.
+ */
+ public int mPosDelSpl = -1;
+
+ /**
+ * If {@link #mPosDelSpl} is big than or equal to 0, this member is used
+ * to indicate that whether the postion is counted in spelling id or
+ * character.
+ */
+ public boolean mIsPosInSpl;
+
+ public DecodingInfo() {
+ mSurface = new StringBuffer();
+ mSurfaceDecodedLen = 0;
+ }
+
+ public void reset() {
+ mSurface.delete ( 0, mSurface.length() );
+ mSurfaceDecodedLen = 0;
+ mCursorPos = 0;
+ mFullSent = "";
+ mFixedLen = 0;
+ mFinishSelection = false;
+ mComposingStr = "";
+ mComposingStrDisplay = "";
+ mActiveCmpsLen = 0;
+ mActiveCmpsDisplayLen = 0;
+ resetCandidates();
+ }
+
+ public boolean isCandidatesListEmpty() {
+ return mCandidatesList.size() == 0;
+ }
+
+ public boolean isSplStrFull() {
+ if ( mSurface.length() >= PY_STRING_MAX - 1 ) { return true; }
+ return false;
+ }
+
+ public void addSplChar ( char ch, boolean reset ) {
+ if ( reset ) {
+ mSurface.delete ( 0, mSurface.length() );
+ mSurfaceDecodedLen = 0;
+ mCursorPos = 0;
+ try {
+ mIPinyinDecoderService.imResetSearch();
+ } catch ( RemoteException e ) {
+ }
+ }
+ mSurface.insert ( mCursorPos, ch );
+ mCursorPos++;
+ }
+
+ // Prepare to delete before cursor. We may delete a spelling char if
+ // the cursor is in the range of unfixed part, delete a whole spelling
+ // if the cursor in inside the range of the fixed part.
+ // This function only marks the position used to delete.
+ public void prepareDeleteBeforeCursor() {
+ if ( mCursorPos > 0 ) {
+ int pos;
+ for ( pos = 0; pos < mFixedLen; pos++ ) {
+ if ( mSplStart[pos + 2] >= mCursorPos
+ && mSplStart[pos + 1] < mCursorPos ) {
+ mPosDelSpl = pos;
+ mCursorPos = mSplStart[pos + 1];
+ mIsPosInSpl = true;
+ break;
+ }
+ }
+ if ( mPosDelSpl < 0 ) {
+ mPosDelSpl = mCursorPos - 1;
+ mCursorPos--;
+ mIsPosInSpl = false;
+ }
+ }
+ }
+
+ public int length() {
+ return mSurface.length();
+ }
+
+ public char charAt ( int index ) {
+ return mSurface.charAt ( index );
+ }
+
+ public StringBuffer getOrigianlSplStr() {
+ return mSurface;
+ }
+
+ public int getSplStrDecodedLen() {
+ return mSurfaceDecodedLen;
+ }
+
+ public int[] getSplStart() {
+ return mSplStart;
+ }
+
+ public String getComposingStr() {
+ return mComposingStr;
+ }
+
+ public String getComposingStrActivePart() {
+ assert ( mActiveCmpsLen <= mComposingStr.length() );
+ return mComposingStr.substring ( 0, mActiveCmpsLen );
+ }
+
+ public int getActiveCmpsLen() {
+ return mActiveCmpsLen;
+ }
+
+ public String getComposingStrForDisplay() {
+ return mComposingStrDisplay;
+ }
+
+ public int getActiveCmpsDisplayLen() {
+ return mActiveCmpsDisplayLen;
+ }
+
+ public String getFullSent() {
+ return mFullSent;
+ }
+
+ public String getCurrentFullSent ( int activeCandPos ) {
+ try {
+ String retStr = mFullSent.substring ( 0, mFixedLen );
+ retStr += mCandidatesList.get ( activeCandPos );
+ return retStr;
+ } catch ( Exception e ) {
+ return "";
+ }
+ }
+
+ public void resetCandidates() {
+ mCandidatesList.clear();
+ mTotalChoicesNum = 0;
+ mPageStart.clear();
+ mPageStart.add ( 0 );
+ mCnToPage.clear();
+ mCnToPage.add ( 0 );
+ }
+
+ public boolean candidatesFromApp() {
+ return ImeState.STATE_APP_COMPLETION == mImeState;
+ }
+
+ public boolean canDoPrediction() {
+ return mComposingStr.length() == mFixedLen;
+ }
+
+ public boolean selectionFinished() {
+ return mFinishSelection;
+ }
+
+ // After the user chooses a candidate, input method will do a
+ // re-decoding and give the new candidate list.
+ // If candidate id is less than 0, means user is inputting Pinyin,
+ // not selecting any choice.
+ private void chooseDecodingCandidate ( int candId ) {
+ if ( mImeState != ImeState.STATE_PREDICT ) {
+ resetCandidates();
+ int totalChoicesNum = 0;
+ try {
+ if ( candId < 0 ) {
+ if ( length() == 0 ) {
+ totalChoicesNum = 0;
+ } else {
+ if ( mPyBuf == null ) {
+ mPyBuf = new byte[PY_STRING_MAX];
+ }
+ for ( int i = 0; i < length(); i++ ) {
+ mPyBuf[i] = ( byte ) charAt ( i );
+ }
+ mPyBuf[length()] = 0;
+ if ( mPosDelSpl < 0 ) {
+ totalChoicesNum = mIPinyinDecoderService
+ .imSearch ( mPyBuf, length() );
+ } else {
+ boolean clear_fixed_this_step = true;
+ if ( ImeState.STATE_COMPOSING == mImeState ) {
+ clear_fixed_this_step = false;
+ }
+ totalChoicesNum = mIPinyinDecoderService
+ .imDelSearch ( mPosDelSpl, mIsPosInSpl,
+ clear_fixed_this_step );
+ mPosDelSpl = -1;
+ }
+ }
+ } else {
+ totalChoicesNum = mIPinyinDecoderService
+ .imChoose ( candId );
+ }
+ } catch ( RemoteException e ) {
+ }
+ updateDecInfoForSearch ( totalChoicesNum );
+ }
+ }
+
+ private void updateDecInfoForSearch ( int totalChoicesNum ) {
+ mTotalChoicesNum = totalChoicesNum;
+ if ( mTotalChoicesNum < 0 ) {
+ mTotalChoicesNum = 0;
+ return;
+ }
+ try {
+ String pyStr;
+ mSplStart = mIPinyinDecoderService.imGetSplStart();
+ pyStr = mIPinyinDecoderService.imGetPyStr ( false );
+ mSurfaceDecodedLen = mIPinyinDecoderService.imGetPyStrLen ( true );
+ assert ( mSurfaceDecodedLen <= pyStr.length() );
+ mFullSent = mIPinyinDecoderService.imGetChoice ( 0 );
+ mFixedLen = mIPinyinDecoderService.imGetFixedLen();
+ // Update the surface string to the one kept by engine.
+ mSurface.replace ( 0, mSurface.length(), pyStr );
+ if ( mCursorPos > mSurface.length() ) {
+ mCursorPos = mSurface.length();
+ }
+ mComposingStr = mFullSent.substring ( 0, mFixedLen )
+ + mSurface.substring ( mSplStart[mFixedLen + 1] );
+ mActiveCmpsLen = mComposingStr.length();
+ if ( mSurfaceDecodedLen > 0 ) {
+ mActiveCmpsLen = mActiveCmpsLen
+ - ( mSurface.length() - mSurfaceDecodedLen );
+ }
+ // Prepare the display string.
+ if ( 0 == mSurfaceDecodedLen ) {
+ mComposingStrDisplay = mComposingStr;
+ mActiveCmpsDisplayLen = mComposingStr.length();
+ } else {
+ mComposingStrDisplay = mFullSent.substring ( 0, mFixedLen );
+ for ( int pos = mFixedLen + 1; pos < mSplStart.length - 1; pos++ ) {
+ mComposingStrDisplay += mSurface.substring (
+ mSplStart[pos], mSplStart[pos + 1] );
+ if ( mSplStart[pos + 1] < mSurfaceDecodedLen ) {
+ mComposingStrDisplay += " ";
+ }
+ }
+ mActiveCmpsDisplayLen = mComposingStrDisplay.length();
+ if ( mSurfaceDecodedLen < mSurface.length() ) {
+ mComposingStrDisplay += mSurface
+ .substring ( mSurfaceDecodedLen );
+ }
+ }
+ if ( mSplStart.length == mFixedLen + 2 ) {
+ mFinishSelection = true;
+ } else {
+ mFinishSelection = false;
+ }
+ } catch ( RemoteException e ) {
+ Log.w ( TAG, "PinyinDecoderService died", e );
+ } catch ( Exception e ) {
+ mTotalChoicesNum = 0;
+ mComposingStr = "";
+ }
+ // Prepare page 0.
+ if ( !mFinishSelection ) {
+ preparePage ( 0 );
+ }
+ }
+
+ private void choosePredictChoice ( int choiceId ) {
+ if ( ImeState.STATE_PREDICT != mImeState || choiceId < 0
+ || choiceId >= mTotalChoicesNum ) {
+ return;
+ }
+ String tmp = mCandidatesList.get ( choiceId );
+ resetCandidates();
+ mCandidatesList.add ( tmp );
+ mTotalChoicesNum = 1;
+ mSurface.replace ( 0, mSurface.length(), "" );
+ mCursorPos = 0;
+ mFullSent = tmp;
+ mFixedLen = tmp.length();
+ mComposingStr = mFullSent;
+ mActiveCmpsLen = mFixedLen;
+ mFinishSelection = true;
+ }
+
+ public String getCandidate ( int candId ) {
+ // Only loaded items can be gotten, so we use mCandidatesList.size()
+ // instead mTotalChoiceNum.
+ if ( candId < 0 || candId > mCandidatesList.size() ) {
+ return null;
+ }
+ return mCandidatesList.get ( candId );
+ }
+
+ private void getCandiagtesForCache() {
+ int fetchStart = mCandidatesList.size();
+ int fetchSize = mTotalChoicesNum - fetchStart;
+ if ( fetchSize > MAX_PAGE_SIZE_DISPLAY ) {
+ fetchSize = MAX_PAGE_SIZE_DISPLAY;
+ }
+ try {
+ List<String> newList = null;
+ if ( ImeState.STATE_INPUT == mImeState ||
+ ImeState.STATE_IDLE == mImeState ||
+ ImeState.STATE_COMPOSING == mImeState ) {
+ newList = mIPinyinDecoderService.imGetChoiceList (
+ fetchStart, fetchSize, mFixedLen );
+ } else if ( ImeState.STATE_PREDICT == mImeState ) {
+ newList = mIPinyinDecoderService.imGetPredictList (
+ fetchStart, fetchSize );
+ } else if ( ImeState.STATE_APP_COMPLETION == mImeState ) {
+ newList = new ArrayList<String>();
+ if ( null != mAppCompletions ) {
+ for ( int pos = fetchStart; pos < fetchSize; pos++ ) {
+ CompletionInfo ci = mAppCompletions[pos];
+ if ( null != ci ) {
+ CharSequence s = ci.getText();
+ if ( null != s ) { newList.add ( s.toString() ); }
+ }
+ }
+ }
+ }
+ mCandidatesList.addAll ( newList );
+ } catch ( RemoteException e ) {
+ Log.w ( TAG, "PinyinDecoderService died", e );
+ }
+ }
+
+ public boolean pageReady ( int pageNo ) {
+ // If the page number is less than 0, return false
+ if ( pageNo < 0 ) { return false; }
+ // Page pageNo's ending information is not ready.
+ if ( mPageStart.size() <= pageNo + 1 ) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean preparePage ( int pageNo ) {
+ // If the page number is less than 0, return false
+ if ( pageNo < 0 ) { return false; }
+ // Make sure the starting information for page pageNo is ready.
+ if ( mPageStart.size() <= pageNo ) {
+ return false;
+ }
+ // Page pageNo's ending information is also ready.
+ if ( mPageStart.size() > pageNo + 1 ) {
+ return true;
+ }
+ // If cached items is enough for page pageNo.
+ if ( mCandidatesList.size() - mPageStart.elementAt ( pageNo ) >= MAX_PAGE_SIZE_DISPLAY ) {
+ return true;
+ }
+ // Try to get more items from engine
+ getCandiagtesForCache();
+ // Try to find if there are available new items to display.
+ // If no new item, return false;
+ if ( mPageStart.elementAt ( pageNo ) >= mCandidatesList.size() ) {
+ return false;
+ }
+ // If there are new items, return true;
+ return true;
+ }
+
+ public void preparePredicts ( CharSequence history ) {
+ if ( null == history ) { return; }
+ resetCandidates();
+ if ( Settings.getPrediction() ) {
+ String preEdit = history.toString();
+ int predictNum = 0;
+ if ( null != preEdit ) {
+ try {
+ mTotalChoicesNum = mIPinyinDecoderService
+ .imGetPredictsNum ( preEdit );
+ } catch ( RemoteException e ) {
+ return;
+ }
+ }
+ }
+ preparePage ( 0 );
+ mFinishSelection = false;
+ }
+
+ private void prepareAppCompletions ( CompletionInfo completions[] ) {
+ resetCandidates();
+ mAppCompletions = completions;
+ mTotalChoicesNum = completions.length;
+ preparePage ( 0 );
+ mFinishSelection = false;
+ return;
+ }
+
+ public int getCurrentPageSize ( int currentPage ) {
+ if ( mPageStart.size() <= currentPage + 1 ) { return 0; }
+ return mPageStart.elementAt ( currentPage + 1 )
+ - mPageStart.elementAt ( currentPage );
+ }
+
+ public int getCurrentPageStart ( int currentPage ) {
+ if ( mPageStart.size() < currentPage + 1 ) { return mTotalChoicesNum; }
+ return mPageStart.elementAt ( currentPage );
+ }
+
+ public boolean pageForwardable ( int currentPage ) {
+ if ( mPageStart.size() <= currentPage + 1 ) { return false; }
+ if ( mPageStart.elementAt ( currentPage + 1 ) >= mTotalChoicesNum ) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean pageBackwardable ( int currentPage ) {
+ if ( currentPage > 0 ) { return true; }
+ return false;
+ }
+
+ public boolean charBeforeCursorIsSeparator() {
+ int len = mSurface.length();
+ if ( mCursorPos > len ) { return false; }
+ if ( mCursorPos > 0 && mSurface.charAt ( mCursorPos - 1 ) == '\'' ) {
+ return true;
+ }
+ return false;
+ }
+
+ public int getCursorPos() {
+ return mCursorPos;
+ }
+
+ public int getCursorPosInCmps() {
+ int cursorPos = mCursorPos;
+ int fixedLen = 0;
+ for ( int hzPos = 0; hzPos < mFixedLen; hzPos++ ) {
+ if ( mCursorPos >= mSplStart[hzPos + 2] ) {
+ cursorPos -= mSplStart[hzPos + 2] - mSplStart[hzPos + 1];
+ cursorPos += 1;
+ }
+ }
+ return cursorPos;
+ }
+
+ public int getCursorPosInCmpsDisplay() {
+ int cursorPos = getCursorPosInCmps();
+ // +2 is because: one for mSplStart[0], which is used for other
+ // purpose(The length of the segmentation string), and another
+ // for the first spelling which does not need a space before it.
+ for ( int pos = mFixedLen + 2; pos < mSplStart.length - 1; pos++ ) {
+ if ( mCursorPos <= mSplStart[pos] ) {
+ break;
+ } else {
+ cursorPos++;
+ }
+ }
+ return cursorPos;
+ }
+
+ public void moveCursorToEdge ( boolean left ) {
+ if ( left ) {
+ mCursorPos = 0;
+ } else {
+ mCursorPos = mSurface.length();
+ }
+ }
+
+ // Move cursor. If offset is 0, this function can be used to adjust
+ // the cursor into the bounds of the string.
+ public void moveCursor ( int offset ) {
+ if ( offset > 1 || offset < -1 ) { return; }
+ if ( offset != 0 ) {
+ int hzPos = 0;
+ for ( hzPos = 0; hzPos <= mFixedLen; hzPos++ ) {
+ if ( mCursorPos == mSplStart[hzPos + 1] ) {
+ if ( offset < 0 ) {
+ if ( hzPos > 0 ) {
+ offset = mSplStart[hzPos]
+ - mSplStart[hzPos + 1];
+ }
+ } else {
+ if ( hzPos < mFixedLen ) {
+ offset = mSplStart[hzPos + 2]
+ - mSplStart[hzPos + 1];
+ }
+ }
+ break;
+ }
+ }
+ }
+ mCursorPos += offset;
+ if ( mCursorPos < 0 ) {
+ mCursorPos = 0;
+ } else if ( mCursorPos > mSurface.length() ) {
+ mCursorPos = mSurface.length();
+ }
+ }
+
+ public int getSplNum() {
+ return mSplStart[0];
+ }
+
+ public int getFixedLen() {
+ return mFixedLen;
+ }
+ }
+
+}
diff --git a/src/com/droidlogic/inputmethod/remote/Settings.java b/src/com/droidlogic/inputmethod/remote/Settings.java
new file mode 100644
index 0000000..4011e2b
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/Settings.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+
+/**
+ * Class used to maintain settings.
+ */
+public class Settings {
+ private static final String ANDPY_CONFS_KEYSOUND_KEY = "Sound";
+ private static final String ANDPY_CONFS_VIBRATE_KEY = "Vibrate";
+ private static final String ANDPY_CONFS_PREDICTION_KEY = "Prediction";
+
+ private static boolean mKeySound;
+ private static boolean mVibrate;
+ private static boolean mPrediction;
+
+ private static Settings mInstance = null;
+
+ private static int mRefCount = 0;
+
+ private static SharedPreferences mSharedPref = null;
+
+ protected Settings ( SharedPreferences pref ) {
+ mSharedPref = pref;
+ initConfs();
+ }
+
+ public static Settings getInstance ( SharedPreferences pref ) {
+ if ( mInstance == null ) {
+ mInstance = new Settings ( pref );
+ }
+ assert ( pref == mSharedPref );
+ mRefCount++;
+ return mInstance;
+ }
+
+ public static void writeBack() {
+ Editor editor = mSharedPref.edit();
+ editor.putBoolean ( ANDPY_CONFS_VIBRATE_KEY, mVibrate );
+ editor.putBoolean ( ANDPY_CONFS_KEYSOUND_KEY, mKeySound );
+ editor.putBoolean ( ANDPY_CONFS_PREDICTION_KEY, mPrediction );
+ editor.commit();
+ }
+
+ public static void releaseInstance() {
+ mRefCount--;
+ if ( mRefCount == 0 ) {
+ mInstance = null;
+ }
+ }
+
+ private void initConfs() {
+ mKeySound = mSharedPref.getBoolean ( ANDPY_CONFS_KEYSOUND_KEY, true );
+ mVibrate = mSharedPref.getBoolean ( ANDPY_CONFS_VIBRATE_KEY, false );
+ mPrediction = mSharedPref.getBoolean ( ANDPY_CONFS_PREDICTION_KEY, true );
+ }
+
+ public static boolean getKeySound() {
+ return mKeySound;
+ }
+
+ public static void setKeySound ( boolean v ) {
+ if ( mKeySound == v ) { return; }
+ mKeySound = v;
+ }
+
+ public static boolean getVibrate() {
+ return mVibrate;
+ }
+
+ public static void setVibrate ( boolean v ) {
+ if ( mVibrate == v ) { return; }
+ mVibrate = v;
+ }
+
+ public static boolean getPrediction() {
+ return mPrediction;
+ }
+
+ public static void setPrediction ( boolean v ) {
+ if ( mPrediction == v ) { return; }
+ mPrediction = v;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SettingsActivity.java b/src/com/droidlogic/inputmethod/remote/SettingsActivity.java
new file mode 100644
index 0000000..6b6df21
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SettingsActivity.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import java.util.List;
+
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
+import android.preference.PreferenceScreen;
+
+import com.droidlogic.inputmethod.remote.Settings;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+/**
+ * Setting activity of Pinyin IME.
+ */
+public class SettingsActivity extends PreferenceActivity implements
+ Preference.OnPreferenceChangeListener {
+
+ private static String TAG = "SettingsActivity";
+
+ private CheckBoxPreference mKeySoundPref;
+ private CheckBoxPreference mVibratePref;
+ private CheckBoxPreference mPredictionPref;
+
+ @Override
+ protected void onCreate ( Bundle savedInstanceState ) {
+ super.onCreate ( savedInstanceState );
+ addPreferencesFromResource ( R.xml.settings );
+ PreferenceScreen prefSet = getPreferenceScreen();
+ mKeySoundPref = ( CheckBoxPreference ) prefSet
+ .findPreference ( getString ( R.string.setting_sound_key ) );
+ mVibratePref = ( CheckBoxPreference ) prefSet
+ .findPreference ( getString ( R.string.setting_vibrate_key ) );
+ mPredictionPref = ( CheckBoxPreference ) prefSet
+ .findPreference ( getString ( R.string.setting_prediction_key ) );
+ prefSet.setOnPreferenceChangeListener ( this );
+ Settings.getInstance ( PreferenceManager
+ .getDefaultSharedPreferences ( getApplicationContext() ) );
+ updatePreference ( prefSet, getString ( R.string.setting_advanced_key ) );
+ updateWidgets();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateWidgets();
+ }
+
+ @Override
+ protected void onDestroy() {
+ Settings.releaseInstance();
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ Settings.setKeySound ( mKeySoundPref.isChecked() );
+ Settings.setVibrate ( mVibratePref.isChecked() );
+ Settings.setPrediction ( mPredictionPref.isChecked() );
+ Settings.writeBack();
+ }
+
+ public boolean onPreferenceChange ( Preference preference, Object newValue ) {
+ return true;
+ }
+
+ private void updateWidgets() {
+ mKeySoundPref.setChecked ( Settings.getKeySound() );
+ mVibratePref.setChecked ( Settings.getVibrate() );
+ mPredictionPref.setChecked ( Settings.getPrediction() );
+ }
+
+ public void updatePreference ( PreferenceGroup parentPref, String prefKey ) {
+ Preference preference = parentPref.findPreference ( prefKey );
+ if ( preference == null ) {
+ return;
+ }
+ Intent intent = preference.getIntent();
+ if ( intent != null ) {
+ PackageManager pm = getPackageManager();
+ List<ResolveInfo> list = pm.queryIntentActivities ( intent, 0 );
+ int listSize = list.size();
+ if ( listSize == 0 ) {
+ parentPref.removePreference ( preference );
+ }
+ }
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SkbContainer.java b/src/com/droidlogic/inputmethod/remote/SkbContainer.java
new file mode 100644
index 0000000..6c49af9
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SkbContainer.java
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.inputmethodservice.InputMethodService;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.widget.PopupWindow;
+import android.widget.RelativeLayout;
+import android.widget.ViewFlipper;
+
+/**
+ * The top container to host soft keyboard view(s).
+ */
+public class SkbContainer extends RelativeLayout implements OnTouchListener {
+ /**
+ * For finger touch, user tends to press the bottom part of the target key,
+ * or he/she even presses the area out of it, so it is necessary to make a
+ * simple bias correction. If the input method runs on emulator, no bias
+ * correction will be used.
+ */
+ private static final int Y_BIAS_CORRECTION = 5;
+
+ /**
+ * For finger touch, user tends to press the right part of the target key,
+ * or he/she even presses the area out of it, so it is necessary to make a
+ * simple bias correction. If the input method runs on emulator, no bias
+ * correction will be used.
+ */
+ private static final int X_BIAS_CORRECTION = 5;
+
+ /**
+ * Used to skip these move events whose position is too close to the
+ * previous touch events.
+ */
+ private static final int MOVE_TOLERANCE = 6;
+
+ /**
+ * If this member is true, PopupWindow is used to show on-key highlight
+ * effect.
+ */
+ private static boolean POPUPWINDOW_FOR_PRESSED_UI = false;
+
+ /**
+ * The current soft keyboard layout.
+ *
+ * @see com.droidlogic.inputmethod.remote.InputModeSwitcher for detailed layout
+ * definitions.
+ */
+ private int mSkbLayout = 0;
+
+ /**
+ * The input method service.
+ */
+ private InputMethodService mService;
+
+ /**
+ * Input mode switcher used to switch between different modes like Chinese,
+ * English, etc.
+ */
+ private InputModeSwitcher mInputModeSwitcher;
+
+ /**
+ * The gesture detector.
+ */
+ private GestureDetector mGestureDetector;
+
+ private Environment mEnvironment;
+
+ private ViewFlipper mSkbFlipper;
+
+ /**
+ * The popup balloon hint for key press/release.
+ */
+ private BalloonHint mBalloonPopup;
+
+ /**
+ * The on-key balloon hint for key press/release.
+ */
+ private BalloonHint mBalloonOnKey = null;
+
+ /** The major sub soft keyboard. */
+ private SoftKeyboardView mMajorView;
+
+ /**
+ * The last parameter when function {@link #toggleCandidateMode(boolean)}
+ * was called.
+ */
+ private boolean mLastCandidatesShowing;
+
+ /** Used to indicate whether a popup soft keyboard is shown. */
+ private boolean mPopupSkbShow = false;
+
+ /**
+ * Used to indicate whether a popup soft keyboard is just shown, and waits
+ * for the touch event to release. After the release, the popup window can
+ * response to touch events.
+ **/
+ private boolean mPopupSkbNoResponse = false;
+
+ /** Popup sub keyboard. */
+ private PopupWindow mPopupSkb;
+
+ /** The view of the popup sub soft keyboard. */
+ private SoftKeyboardView mPopupSkbView;
+
+ private int mPopupX;
+
+ private int mPopupY;
+
+ /**
+ * When user presses a key, a timer is started, when it times out, it is
+ * necessary to detect whether user still holds the key.
+ */
+ private volatile boolean mWaitForTouchUp = false;
+
+ /**
+ * When user drags on the soft keyboard and the distance is enough, this
+ * drag will be recognized as a gesture and a gesture-based action will be
+ * taken, in this situation, ignore the consequent events.
+ */
+ private volatile boolean mDiscardEvent = false;
+
+ /**
+ * For finger touch, user tends to press the bottom part of the target key,
+ * or he/she even presses the area out of it, so it is necessary to make a
+ * simple bias correction in Y.
+ */
+ private int mYBiasCorrection = 0;
+
+ /**
+ * For finger touch, user tends to press the bottom part of the target key,
+ * or he/she even presses the area out of it, so it is necessary to make a
+ * simple bias correction in x.
+ */
+ private int mXBiasCorrection = 0;
+
+ /**
+ * The x coordination of the last touch event.
+ */
+ private int mXLast;
+
+ /**
+ * The y coordination of the last touch event.
+ */
+ private int mYLast;
+
+ /**
+ * The soft keyboard view.
+ */
+ private SoftKeyboardView mSkv;
+
+ /**
+ * The position of the soft keyboard view in the container.
+ */
+ private int mSkvPosInContainer[] = new int[2];
+
+ /**
+ * The key pressed by user.
+ */
+ private SoftKey mSoftKeyDown = null;
+
+ /**
+ * Add by lyra: The key focused on.
+ */
+ private SoftKey mSoftKeyFocus = null;
+
+ /**
+ * Used to timeout a press if user holds the key for a long time.
+ */
+ private LongPressTimer mLongPressTimer;
+
+ /**
+ * For temporary use.
+ */
+ private int mXyPosTmp[] = new int[2];
+
+ public SkbContainer ( Context context, AttributeSet attrs ) {
+ super ( context, attrs );
+ mEnvironment = Environment.getInstance();
+ mLongPressTimer = new LongPressTimer ( this );
+ // If it runs on an emulator, no bias correction
+ if ( "1".equals ( SystemProperties.get ( "ro.kernel.qemu" ) ) ) {
+ mYBiasCorrection = 0;
+ mYBiasCorrection = 0;
+ } else {
+ mYBiasCorrection = Y_BIAS_CORRECTION;
+ mXBiasCorrection = X_BIAS_CORRECTION;
+ }
+ mBalloonPopup = new BalloonHint ( context, this, MeasureSpec.AT_MOST );
+ if ( POPUPWINDOW_FOR_PRESSED_UI ) {
+ mBalloonOnKey = new BalloonHint ( context, this, MeasureSpec.AT_MOST );
+ }
+ mPopupSkb = new PopupWindow ( mContext );
+ mPopupSkb.setBackgroundDrawable ( null );
+ mPopupSkb.setClippingEnabled ( false );
+ }
+
+ public void setService ( InputMethodService service ) {
+ mService = service;
+ }
+
+ public void setInputModeSwitcher ( InputModeSwitcher inputModeSwitcher ) {
+ mInputModeSwitcher = inputModeSwitcher;
+ }
+
+ public void setGestureDetector ( GestureDetector gestureDetector ) {
+ mGestureDetector = gestureDetector;
+ }
+
+ public boolean isCurrentSkbSticky() {
+ if ( null == mMajorView ) { return true; }
+ SoftKeyboard skb = mMajorView.getSoftKeyboard();
+ if ( null != skb ) {
+ return skb.getStickyFlag();
+ }
+ return true;
+ }
+
+ public void toggleCandidateMode ( boolean candidatesShowing ) {
+ if ( null == mMajorView || !mInputModeSwitcher.isChineseText()
+ || mLastCandidatesShowing == candidatesShowing ) { return; }
+ mLastCandidatesShowing = candidatesShowing;
+ SoftKeyboard skb = mMajorView.getSoftKeyboard();
+ if ( null == skb ) { return; }
+ int state = mInputModeSwitcher.getTooggleStateForCnCand();
+ if ( !candidatesShowing ) {
+ skb.disableToggleState ( state, false );
+ skb.enableToggleStates ( mInputModeSwitcher.getToggleStates() );
+ } else {
+ skb.enableToggleState ( state, false );
+ }
+ mMajorView.invalidate();
+ }
+
+ public void updateInputMode() {
+ updateInputMode ( false );
+ }
+
+ /*@hide*/
+ public void updateInputMode ( boolean force ) {
+ int skbLayout = mInputModeSwitcher.getSkbLayout();
+ if ( mSkbLayout != skbLayout || force ) {
+ mSkbLayout = skbLayout;
+ updateSkbLayout ( force );
+ }
+ mLastCandidatesShowing = false;
+ if ( null == mMajorView ) { return; }
+ SoftKeyboard skb = mMajorView.getSoftKeyboard();
+ if ( null == skb ) { return; }
+ skb.enableToggleStates ( mInputModeSwitcher.getToggleStates() );
+ invalidate();
+ return;
+ }
+
+ private void updateSkbLayout ( boolean force ) {
+ int screenWidth = mEnvironment.getScreenWidth();
+ int keyHeight = mEnvironment.getKeyHeight();
+ int skbHeight = mEnvironment.getSkbHeight();
+ Resources r = mContext.getResources();
+ if ( null == mSkbFlipper ) {
+ mSkbFlipper = ( ViewFlipper ) findViewById ( R.id.alpha_floatable );
+ }
+ mMajorView = ( SoftKeyboardView ) mSkbFlipper.getChildAt ( 0 );
+ SoftKeyboard majorSkb = null;
+ SkbPool skbPool = SkbPool.getInstance();
+ switch ( mSkbLayout ) {
+ case R.xml.skb_qwerty:
+ majorSkb = skbPool.getSoftKeyboard ( R.xml.skb_qwerty,
+ R.xml.skb_qwerty, screenWidth, skbHeight, mContext, force );
+ break;
+ case R.xml.skb_sym1:
+ majorSkb = skbPool.getSoftKeyboard ( R.xml.skb_sym1, R.xml.skb_sym1,
+ screenWidth, skbHeight, mContext, force );
+ break;
+ case R.xml.skb_sym2:
+ majorSkb = skbPool.getSoftKeyboard ( R.xml.skb_sym2, R.xml.skb_sym2,
+ screenWidth, skbHeight, mContext, force );
+ break;
+ case R.xml.skb_smiley:
+ majorSkb = skbPool.getSoftKeyboard ( R.xml.skb_smiley,
+ R.xml.skb_smiley, screenWidth, skbHeight, mContext, force );
+ break;
+ case R.xml.skb_phone:
+ majorSkb = skbPool.getSoftKeyboard ( R.xml.skb_phone,
+ R.xml.skb_phone, screenWidth, skbHeight, mContext, force );
+ break;
+ default:
+ }
+ if ( null == majorSkb || !mMajorView.setSoftKeyboard ( majorSkb ) ) {
+ return;
+ }
+ mMajorView.setBalloonHint ( mBalloonOnKey, mBalloonPopup, false );
+ mMajorView.invalidate();
+ }
+
+ private void responseKeyEvent ( SoftKey sKey ) {
+ if ( null == sKey ) { return; }
+ ( ( RemoteIME ) mService ).responseSoftKeyEvent ( sKey );
+ return;
+ }
+
+ private SoftKeyboardView inKeyboardView ( int x, int y,
+ int positionInParent[] ) {
+ if ( mPopupSkbShow ) {
+ if ( mPopupX <= x && mPopupX + mPopupSkb.getWidth() > x
+ && mPopupY <= y && mPopupY + mPopupSkb.getHeight() > y ) {
+ positionInParent[0] = mPopupX;
+ positionInParent[1] = mPopupY;
+ mPopupSkbView.setOffsetToSkbContainer ( positionInParent );
+ return mPopupSkbView;
+ }
+ return null;
+ }
+ return mMajorView;
+ }
+
+ private void popupSymbols() {
+ int popupResId = mSoftKeyDown.getPopupResId();
+ if ( popupResId > 0 ) {
+ int skbContainerWidth = getWidth();
+ int skbContainerHeight = getHeight();
+ // The paddings of the background are not included.
+ int miniSkbWidth = ( int ) ( skbContainerWidth * 0.8 );
+ int miniSkbHeight = ( int ) ( skbContainerHeight * 0.23 );
+ SkbPool skbPool = SkbPool.getInstance();
+ SoftKeyboard skb = skbPool.getSoftKeyboard ( popupResId, popupResId,
+ miniSkbWidth, miniSkbHeight, mContext );
+ if ( null == skb ) { return; }
+ mPopupX = ( skbContainerWidth - skb.getSkbTotalWidth() ) / 2;
+ mPopupY = ( skbContainerHeight - skb.getSkbTotalHeight() ) / 2;
+ if ( null == mPopupSkbView ) {
+ mPopupSkbView = new SoftKeyboardView ( mContext, null );
+ mPopupSkbView.onMeasure ( LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT );
+ }
+ mPopupSkbView.setOnTouchListener ( this );
+ mPopupSkbView.setSoftKeyboard ( skb );
+ mPopupSkbView.setBalloonHint ( mBalloonOnKey, mBalloonPopup, true );
+ mPopupSkb.setContentView ( mPopupSkbView );
+ mPopupSkb.setWidth ( skb.getSkbCoreWidth()
+ + mPopupSkbView.getPaddingLeft()
+ + mPopupSkbView.getPaddingRight() );
+ mPopupSkb.setHeight ( skb.getSkbCoreHeight()
+ + mPopupSkbView.getPaddingTop()
+ + mPopupSkbView.getPaddingBottom() );
+ getLocationInWindow ( mXyPosTmp );
+ mPopupSkb.showAtLocation ( this, Gravity.NO_GRAVITY, mPopupX, mPopupY
+ + mXyPosTmp[1] );
+ mPopupSkbShow = true;
+ mPopupSkbNoResponse = true;
+ // Invalidate itself to dim the current soft keyboards.
+ dimSoftKeyboard ( true );
+ resetKeyPress ( 0 );
+ }
+ }
+
+ private void dimSoftKeyboard ( boolean dimSkb ) {
+ mMajorView.dimSoftKeyboard ( dimSkb );
+ }
+
+ private void dismissPopupSkb() {
+ mPopupSkb.dismiss();
+ mPopupSkbShow = false;
+ dimSoftKeyboard ( false );
+ resetKeyPress ( 0 );
+ }
+
+ private void resetKeyPress ( long delay ) {
+ mLongPressTimer.removeTimer();
+ if ( null != mSkv ) {
+ mSkv.resetKeyPress ( delay );
+ }
+ }
+
+ public boolean handleBack ( boolean realAction ) {
+ if ( mPopupSkbShow ) {
+ if ( !realAction ) { return true; }
+ dismissPopupSkb();
+ mDiscardEvent = true;
+ return true;
+ }
+ return false;
+ }
+
+ public void dismissPopups() {
+ handleBack ( true );
+ resetKeyPress ( 0 );
+ }
+
+ @Override
+ protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) {
+ Environment env = Environment.getInstance();
+ int measuredWidth = env.getScreenWidth();
+ int measuredHeight = getPaddingTop();
+ measuredHeight += env.getSkbHeight();
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec ( measuredWidth,
+ MeasureSpec.EXACTLY );
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec ( measuredHeight,
+ MeasureSpec.EXACTLY );
+ super.onMeasure ( widthMeasureSpec, heightMeasureSpec );
+ }
+
+ @Override
+ public boolean onTouchEvent ( MotionEvent event ) {
+ super.onTouchEvent ( event );
+ if ( mSkbFlipper.isFlipping() ) {
+ resetKeyPress ( 0 );
+ return true;
+ }
+ int x = ( int ) event.getX();
+ int y = ( int ) event.getY();
+ // Bias correction
+ y = y + mYBiasCorrection;
+ x = x + mXBiasCorrection;
+ // Ignore short-distance movement event to get better performance.
+ if ( event.getAction() == MotionEvent.ACTION_MOVE ) {
+ if ( Math.abs ( x - mXLast ) <= MOVE_TOLERANCE
+ && Math.abs ( y - mYLast ) <= MOVE_TOLERANCE ) {
+ return true;
+ }
+ }
+ mXLast = x;
+ mYLast = y;
+ if ( !mPopupSkbShow ) {
+ if ( mGestureDetector.onTouchEvent ( event ) ) {
+ resetKeyPress ( 0 );
+ mDiscardEvent = true;
+ return true;
+ }
+ }
+ switch ( event.getAction() ) {
+ case MotionEvent.ACTION_DOWN:
+ resetKeyPress ( 0 );
+ mWaitForTouchUp = true;
+ mDiscardEvent = false;
+ mSkv = null;
+ mSoftKeyDown = null;
+ mSkv = inKeyboardView ( x, y, mSkvPosInContainer );
+ if ( null != mSkv ) {
+ mSoftKeyDown = mSkv.onKeyPress ( x - mSkvPosInContainer[0], y
+ - mSkvPosInContainer[1], mLongPressTimer, false );
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if ( x < 0 || x >= getWidth() || y < 0 || y >= getHeight() ) {
+ break;
+ }
+ if ( mDiscardEvent ) {
+ resetKeyPress ( 0 );
+ break;
+ }
+ if ( mPopupSkbShow && mPopupSkbNoResponse ) {
+ break;
+ }
+ SoftKeyboardView skv = inKeyboardView ( x, y, mSkvPosInContainer );
+ if ( null != skv ) {
+ if ( skv != mSkv ) {
+ mSkv = skv;
+ mSoftKeyDown = mSkv.onKeyPress ( x - mSkvPosInContainer[0], y
+ - mSkvPosInContainer[1], mLongPressTimer, true );
+ } else if ( null != skv ) {
+ if ( null != mSkv ) {
+ mSoftKeyDown = mSkv.onKeyMove (
+ x - mSkvPosInContainer[0], y
+ - mSkvPosInContainer[1] );
+ if ( null == mSoftKeyDown ) {
+ mDiscardEvent = true;
+ }
+ }
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if ( mDiscardEvent ) {
+ resetKeyPress ( 0 );
+ break;
+ }
+ mWaitForTouchUp = false;
+ // The view which got the {@link MotionEvent#ACTION_DOWN} event is
+ // always used to handle this event.
+ if ( null != mSkv ) {
+ mSkv.onKeyRelease ( x - mSkvPosInContainer[0], y
+ - mSkvPosInContainer[1] );
+ }
+ if ( !mPopupSkbShow || !mPopupSkbNoResponse ) {
+ responseKeyEvent ( mSoftKeyDown );
+ requestFocus();
+ mSoftKeyFocus = mSoftKeyDown;
+ mMajorView.changeFocusKey ( mSoftKeyFocus );
+ }
+ if ( mSkv == mPopupSkbView && !mPopupSkbNoResponse ) {
+ dismissPopupSkb();
+ }
+ mPopupSkbNoResponse = false;
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ break;
+ }
+ if ( null == mSkv ) {
+ return false;
+ }
+ return true;
+ }
+
+ // Function for interface OnTouchListener, it is used to handle touch events
+ // which will be delivered to the popup soft keyboard view.
+ public boolean onTouch ( View v, MotionEvent event ) {
+ // Translate the event to fit to the container.
+ MotionEvent newEv = MotionEvent.obtain ( event.getDownTime(), event
+ .getEventTime(), event.getAction(), event.getX() + mPopupX,
+ event.getY() + mPopupY, event.getPressure(), event.getSize(),
+ event.getMetaState(), event.getXPrecision(), event
+ .getYPrecision(), event.getDeviceId(), event
+ .getEdgeFlags() );
+ boolean ret = onTouchEvent ( newEv );
+ return ret;
+ }
+
+ class LongPressTimer extends Handler implements Runnable {
+ /**
+ * When user presses a key for a long time, the timeout interval to
+ * generate first {@link #LONG_PRESS_KEYNUM1} key events.
+ */
+ public static final int LONG_PRESS_TIMEOUT1 = 500;
+
+ /**
+ * When user presses a key for a long time, after the first
+ * {@link #LONG_PRESS_KEYNUM1} key events, this timeout interval will be
+ * used.
+ */
+ private static final int LONG_PRESS_TIMEOUT2 = 100;
+
+ /**
+ * When user presses a key for a long time, after the first
+ * {@link #LONG_PRESS_KEYNUM2} key events, this timeout interval will be
+ * used.
+ */
+ private static final int LONG_PRESS_TIMEOUT3 = 100;
+
+ /**
+ * When user presses a key for a long time, after the first
+ * {@link #LONG_PRESS_KEYNUM1} key events, timeout interval
+ * {@link #LONG_PRESS_TIMEOUT2} will be used instead.
+ */
+ public static final int LONG_PRESS_KEYNUM1 = 1;
+
+ /**
+ * When user presses a key for a long time, after the first
+ * {@link #LONG_PRESS_KEYNUM2} key events, timeout interval
+ * {@link #LONG_PRESS_TIMEOUT3} will be used instead.
+ */
+ public static final int LONG_PRESS_KEYNUM2 = 3;
+
+ SkbContainer mSkbContainer;
+
+ private int mResponseTimes = 0;
+
+ public LongPressTimer ( SkbContainer skbContainer ) {
+ mSkbContainer = skbContainer;
+ }
+
+ public void startTimer() {
+ postAtTime ( this, SystemClock.uptimeMillis() + LONG_PRESS_TIMEOUT1 );
+ mResponseTimes = 0;
+ }
+
+ public boolean removeTimer() {
+ removeCallbacks ( this );
+ return true;
+ }
+
+ public void run() {
+ if ( mWaitForTouchUp ) {
+ mResponseTimes++;
+ if ( mSoftKeyDown.repeatable() ) {
+ if ( mSoftKeyDown.isUserDefKey() ) {
+ if ( 1 == mResponseTimes ) {
+ if ( mInputModeSwitcher
+ .tryHandleLongPressSwitch ( mSoftKeyDown.mKeyCode ) ) {
+ mDiscardEvent = true;
+ resetKeyPress ( 0 );
+ }
+ }
+ } else {
+ responseKeyEvent ( mSoftKeyDown );
+ long timeout;
+ if ( mResponseTimes < LONG_PRESS_KEYNUM1 ) {
+ timeout = LONG_PRESS_TIMEOUT1;
+ } else if ( mResponseTimes < LONG_PRESS_KEYNUM2 ) {
+ timeout = LONG_PRESS_TIMEOUT2;
+ } else {
+ timeout = LONG_PRESS_TIMEOUT3;
+ }
+ postAtTime ( this, SystemClock.uptimeMillis() + timeout );
+ }
+ } else {
+ if ( 1 == mResponseTimes ) {
+ popupSymbols();
+ }
+ }
+ }
+ }
+ }
+
+ //Add by lyra, return value: lose keyboard focus
+ public SoftKey processFunctionKey ( int keyCode ) {
+ // TODO Auto-generated method stub
+ SoftKeyboard skb = mMajorView.getSoftKeyboard();
+ if ( null == skb ) { return null; }
+ if ( !this.hasFocus() ) {
+ Log.d ( "SoftKeyboard", "keyboard no focus" );
+ return null;
+ }
+ if ( keyCode == KeyEvent.KEYCODE_DPAD_CENTER ) {
+ return mSoftKeyFocus;
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
+ if ( mSoftKeyFocus == null ) {
+ mSoftKeyFocus = skb.getKey ( 0, 0 );
+ } else {
+ if ( mSoftKeyFocus.mLocation > 0 ) {
+ int x = mSoftKeyFocus.mLeft - skb.getKeyXMargin() - 10;
+ int y = mSoftKeyFocus.mTop + mSoftKeyFocus.height() / 2;
+ mSoftKeyFocus = skb.mapToKey ( x, y );
+ } else {
+ mSoftKeyFocus = skb.getKey ( mSoftKeyFocus.mRow, -1 );
+ }
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
+ if ( mSoftKeyFocus == null ) {
+ mSoftKeyFocus = skb.getKey ( 0, 0 );
+ } else {
+ int keyNum = skb.getLocNum ( mSoftKeyFocus.mRow );
+ if ( mSoftKeyFocus.mLocation < keyNum - 1 ) {
+ int x = mSoftKeyFocus.mRight + skb.getKeyXMargin();
+ int y = mSoftKeyFocus.mTop + mSoftKeyFocus.height() / 2;
+ mSoftKeyFocus = skb.mapToKey ( x, y );
+ } else {
+ mSoftKeyFocus = skb.getKey ( mSoftKeyFocus.mRow, 0 );
+ }
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_UP ) {
+ if ( mSoftKeyFocus == null ) {
+ mSoftKeyFocus = skb.getKey ( 0, 0 );
+ } else if ( mSoftKeyFocus.mRow == 0 ) {
+ return null;
+ } else {
+ int x = mSoftKeyFocus.mLeft + mSoftKeyFocus.width() / 2;
+ int y = mSoftKeyFocus.mTop - mSoftKeyFocus.height() / 2;
+ mSoftKeyFocus = skb.mapToKey ( x, y );
+ //mSoftKeyFocus = skb.getKey(mSoftKeyFocus.mRow-1,mSoftKeyFocus.mLocation);
+ }
+ } else if ( keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
+ if ( mSoftKeyFocus == null ) {
+ mSoftKeyFocus = skb.getKey ( 0, 0 );
+ } else {
+ int x = mSoftKeyFocus.mLeft + mSoftKeyFocus.width() / 2;
+ int y = mSoftKeyFocus.mBottom + mSoftKeyFocus.height() / 2;
+ mSoftKeyFocus = skb.mapToKey ( x, y );
+ //skb.getKey(mSoftKeyFocus.mRow+1,mSoftKeyFocus.mLocation);
+ }
+ }
+ if ( mSoftKeyFocus != null ) {
+ Log.d ( "SkbContainer", "focus Key code: " + mSoftKeyFocus.mKeyCode + ", row=" + mSoftKeyFocus.mRow + ", loc=" + mSoftKeyFocus.mLocation );
+ }
+ // mMajorView.mSoftKeyFocus = mSoftKeyFocus;
+ // mMajorView.invalidate();
+ mMajorView.changeFocusKey ( mSoftKeyFocus );
+ return mSoftKeyFocus;
+ }
+
+ public void clearKeyFocus() {
+ mSoftKeyFocus = null;
+ if ( mMajorView != null ) {
+ mMajorView.mSoftKeyFocus = null;
+ }
+ clearFocus();
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SkbPool.java b/src/com/droidlogic/inputmethod/remote/SkbPool.java
new file mode 100644
index 0000000..9682f88
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SkbPool.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import java.util.Vector;
+
+import android.content.Context;
+
+/**
+ * Class used to cache previously loaded soft keyboard layouts.
+ */
+public class SkbPool {
+ private static SkbPool mInstance = null;
+
+ private Vector<SkbTemplate> mSkbTemplates = new Vector<SkbTemplate>();
+ private Vector<SoftKeyboard> mSoftKeyboards = new Vector<SoftKeyboard>();
+
+ private SkbPool() {
+ }
+
+ public static SkbPool getInstance() {
+ if ( null == mInstance ) { mInstance = new SkbPool(); }
+ return mInstance;
+ }
+
+ public void resetCachedSkb() {
+ mSoftKeyboards.clear();
+ }
+
+ public SkbTemplate getSkbTemplate ( int skbTemplateId, Context context, boolean force ) {
+ for ( int i = 0; i < mSkbTemplates.size() && ( !force ); i++ ) {
+ SkbTemplate t = mSkbTemplates.elementAt ( i );
+ if ( t.getSkbTemplateId() == skbTemplateId ) {
+ return t;
+ }
+ }
+ if ( null != context || ( force && ( null != context ) ) ) {
+ XmlKeyboardLoader xkbl = new XmlKeyboardLoader ( context );
+ SkbTemplate t = xkbl.loadSkbTemplate ( skbTemplateId );
+ if ( null != t ) {
+ mSkbTemplates.add ( t );
+ return t;
+ }
+ }
+ return null;
+ }
+
+ public SoftKeyboard getSoftKeyboard ( int skbCacheId, int skbXmlId,
+ int skbWidth, int skbHeight, Context context ) {
+ return getSoftKeyboard ( skbCacheId, skbXmlId, skbWidth, skbHeight, context, false );
+ }
+ /*@hide*/
+ // Try to find the keyboard in the pool with the cache id. If there is no
+ // keyboard found, try to load it with the given xml id.
+ public SoftKeyboard getSoftKeyboard ( int skbCacheId, int skbXmlId,
+ int skbWidth, int skbHeight, Context context, boolean force ) {
+ for ( int i = 0; i < mSoftKeyboards.size() && ( !force ); i++ ) {
+ SoftKeyboard skb = mSoftKeyboards.elementAt ( i );
+ if ( skb.getCacheId() == skbCacheId && skb.getSkbXmlId() == skbXmlId ) {
+ skb.setSkbCoreSize ( skbWidth, skbHeight );
+ skb.setNewlyLoadedFlag ( false );
+ return skb;
+ }
+ }
+ if ( null != context || ( ( null != context ) && force ) ) {
+ XmlKeyboardLoader xkbl = new XmlKeyboardLoader ( context );
+ SoftKeyboard skb = xkbl.loadKeyboard ( skbXmlId, skbWidth, skbHeight, force );
+ if ( skb != null ) {
+ if ( skb.getCacheFlag() ) {
+ skb.setCacheId ( skbCacheId );
+ mSoftKeyboards.add ( skb );
+ }
+ }
+ return skb;
+ }
+ return null;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SkbTemplate.java b/src/com/droidlogic/inputmethod/remote/SkbTemplate.java
new file mode 100644
index 0000000..92cd6bc
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SkbTemplate.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.graphics.drawable.Drawable;
+
+import java.util.Vector;
+
+/**
+ * Key icon definition. It is defined in soft keyboard template. A soft keyboard
+ * can refer to such an icon in its xml file directly to improve performance.
+ */
+class KeyIconRecord {
+ int keyCode;
+ Drawable icon;
+ Drawable iconPopup;
+}
+
+
+/**
+ * Default definition for a certain key. It is defined in soft keyboard
+ * template. A soft keyboard can refer to a default key in its xml file. Nothing
+ * of the key can be overwritten, including the size.
+ */
+class KeyRecord {
+ int keyId;
+ SoftKey softKey;
+}
+
+
+/**
+ * Soft keyboard template used by soft keyboards to share common resources. In
+ * this way, memory cost is reduced.
+ */
+public class SkbTemplate {
+ private int mSkbTemplateId;
+ private Drawable mSkbBg;
+ private Drawable mBalloonBg;
+ private Drawable mPopupBg;
+ private float mXMargin = 0;
+ private float mYMargin = 0;
+ /** Key type list. */
+ private Vector<SoftKeyType> mKeyTypeList = new Vector<SoftKeyType>();
+
+ /**
+ * Default key icon list. It is only for keys which do not have popup icons.
+ */
+ private Vector<KeyIconRecord> mKeyIconRecords = new Vector<KeyIconRecord>();
+
+ /**
+ * Default key list.
+ */
+ private Vector<KeyRecord> mKeyRecords = new Vector<KeyRecord>();
+
+ public SkbTemplate ( int skbTemplateId ) {
+ mSkbTemplateId = skbTemplateId;
+ }
+
+ public int getSkbTemplateId() {
+ return mSkbTemplateId;
+ }
+
+ public void setBackgrounds ( Drawable skbBg, Drawable balloonBg,
+ Drawable popupBg ) {
+ mSkbBg = skbBg;
+ mBalloonBg = balloonBg;
+ mPopupBg = popupBg;
+ }
+
+ public Drawable getSkbBackground() {
+ return mSkbBg;
+ }
+
+ public Drawable getBalloonBackground() {
+ return mBalloonBg;
+ }
+
+ public Drawable getPopupBackground() {
+ return mPopupBg;
+ }
+
+ public void setMargins ( float xMargin, float yMargin ) {
+ mXMargin = xMargin;
+ mYMargin = yMargin;
+ }
+
+ public float getXMargin() {
+ return mXMargin;
+ }
+
+ public float getYMargin() {
+ return mYMargin;
+ }
+
+ public SoftKeyType createKeyType ( int id, Drawable bg, Drawable hlBg ) {
+ return new SoftKeyType ( id, bg, hlBg );
+ }
+
+ public boolean addKeyType ( SoftKeyType keyType ) {
+ // The newly added item should have the right id.
+ if ( mKeyTypeList.size() != keyType.mKeyTypeId ) { return false; }
+ mKeyTypeList.add ( keyType );
+ return true;
+ }
+
+ public SoftKeyType getKeyType ( int typeId ) {
+ if ( typeId < 0 || typeId > mKeyTypeList.size() ) { return null; }
+ return mKeyTypeList.elementAt ( typeId );
+ }
+
+ public void addDefaultKeyIcons ( int keyCode, Drawable icon,
+ Drawable iconPopup ) {
+ if ( null == icon || null == iconPopup ) { return; }
+ KeyIconRecord iconRecord = new KeyIconRecord();
+ iconRecord.icon = icon;
+ iconRecord.iconPopup = iconPopup;
+ iconRecord.keyCode = keyCode;
+ int size = mKeyIconRecords.size();
+ int pos = 0;
+ while ( pos < size ) {
+ if ( mKeyIconRecords.get ( pos ).keyCode >= keyCode ) { break; }
+ pos++;
+ }
+ mKeyIconRecords.add ( pos, iconRecord );
+ }
+
+ public Drawable getDefaultKeyIcon ( int keyCode ) {
+ int size = mKeyIconRecords.size();
+ int pos = 0;
+ while ( pos < size ) {
+ KeyIconRecord iconRecord = mKeyIconRecords.get ( pos );
+ if ( iconRecord.keyCode < keyCode ) {
+ pos++;
+ continue;
+ }
+ if ( iconRecord.keyCode == keyCode ) {
+ return iconRecord.icon;
+ }
+ return null;
+ }
+ return null;
+ }
+
+ public Drawable getDefaultKeyIconPopup ( int keyCode ) {
+ int size = mKeyIconRecords.size();
+ int pos = 0;
+ while ( pos < size ) {
+ KeyIconRecord iconRecord = mKeyIconRecords.get ( pos );
+ if ( iconRecord.keyCode < keyCode ) {
+ pos++;
+ continue;
+ }
+ if ( iconRecord.keyCode == keyCode ) {
+ return iconRecord.iconPopup;
+ }
+ return null;
+ }
+ return null;
+ }
+
+ public void addDefaultKey ( int keyId, SoftKey softKey ) {
+ if ( null == softKey ) { return; }
+ KeyRecord keyRecord = new KeyRecord();
+ keyRecord.keyId = keyId;
+ keyRecord.softKey = softKey;
+ int size = mKeyRecords.size();
+ int pos = 0;
+ while ( pos < size ) {
+ if ( mKeyRecords.get ( pos ).keyId >= keyId ) { break; }
+ pos++;
+ }
+ mKeyRecords.add ( pos, keyRecord );
+ }
+
+ public SoftKey getDefaultKey ( int keyId ) {
+ int size = mKeyRecords.size();
+ int pos = 0;
+ while ( pos < size ) {
+ KeyRecord keyRecord = mKeyRecords.get ( pos );
+ if ( keyRecord.keyId < keyId ) {
+ pos++;
+ continue;
+ }
+ if ( keyRecord.keyId == keyId ) {
+ return keyRecord.softKey;
+ }
+ return null;
+ }
+ return null;
+ }
+}
+
+
+class SoftKeyType {
+ public static final int KEYTYPE_ID_NORMAL_KEY = 0;
+
+ public int mKeyTypeId;
+ public Drawable mKeyBg;
+ public Drawable mKeyHlBg;
+ public int mColor;
+ public int mColorHl;
+ public int mColorBalloon;
+
+ SoftKeyType ( int id, Drawable bg, Drawable hlBg ) {
+ mKeyTypeId = id;
+ mKeyBg = bg;
+ mKeyHlBg = hlBg;
+ }
+
+ public void setColors ( int color, int colorHl, int colorBalloon ) {
+ mColor = color;
+ mColorHl = colorHl;
+ mColorBalloon = colorBalloon;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SoftKey.java b/src/com/droidlogic/inputmethod/remote/SoftKey.java
new file mode 100644
index 0000000..350681f
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SoftKey.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Class for soft keys which defined in the keyboard xml file. A soft key can be
+ * a basic key or a toggling key.
+ *
+ * @see com.droidlogic.inputmethod.remote.SoftKeyToggle
+ */
+public class SoftKey {
+ protected static final int KEYMASK_REPEAT = 0x10000000;
+ protected static final int KEYMASK_BALLOON = 0x20000000;
+
+ /**
+ * For a finger touch device, after user presses a key, there will be some
+ * consequent moving events because of the changing in touching pressure. If
+ * the moving distance in x is within this threshold, the moving events will
+ * be ignored.
+ */
+ public static final int MAX_MOVE_TOLERANCE_X = 0;
+
+ /**
+ * For a finger touch device, after user presses a key, there will be some
+ * consequent moving events because of the changing in touching pressure. If
+ * the moving distance in y is within this threshold, the moving events will
+ * be ignored.
+ */
+ public static final int MAX_MOVE_TOLERANCE_Y = 0;
+
+ /**
+ * Used to indicate the type and attributes of this key. the lowest 8 bits
+ * should be reserved for SoftkeyToggle.
+ */
+ protected int mKeyMask;
+
+ protected SoftKeyType mKeyType;
+
+ protected Drawable mKeyIcon;
+
+ protected Drawable mKeyIconPopup;
+
+ protected String mKeyLabel;
+
+ protected int mKeyCode;
+
+ /**
+ * If this value is not 0, this key can be used to popup a sub soft keyboard
+ * when user presses it for some time.
+ */
+ public int mPopupSkbId;
+
+ public float mLeftF;
+ public float mRightF;
+ public float mTopF;
+ public float mBottomF;
+ public int mLeft;
+ public int mRight;
+ public int mTop;
+ public int mBottom;
+
+ public int mRow;
+ public int mLocation;
+
+ public void setKeyType ( SoftKeyType keyType, Drawable keyIcon,
+ Drawable keyIconPopup ) {
+ mKeyType = keyType;
+ mKeyIcon = keyIcon;
+ mKeyIconPopup = keyIconPopup;
+ }
+
+ // The caller guarantees that all parameters are in [0, 1]
+ public void setKeyDimensions ( float left, float top, float right,
+ float bottom ) {
+ mLeftF = left;
+ mTopF = top;
+ mRightF = right;
+ mBottomF = bottom;
+ }
+
+ public void setKeyAttribute ( int keyCode, String label, boolean repeat,
+ boolean balloon ) {
+ mKeyCode = keyCode;
+ mKeyLabel = label;
+ if ( repeat ) {
+ mKeyMask |= KEYMASK_REPEAT;
+ } else {
+ mKeyMask &= ( ~KEYMASK_REPEAT );
+ }
+ if ( balloon ) {
+ mKeyMask |= KEYMASK_BALLOON;
+ } else {
+ mKeyMask &= ( ~KEYMASK_BALLOON );
+ }
+ }
+
+ public void setPopupSkbId ( int popupSkbId ) {
+ mPopupSkbId = popupSkbId;
+ }
+
+ // Call after setKeyDimensions(). The caller guarantees that the
+ // keyboard with and height are valid.
+ public void setSkbCoreSize ( int skbWidth, int skbHeight ) {
+ mLeft = ( int ) ( mLeftF * skbWidth );
+ mRight = ( int ) ( mRightF * skbWidth );
+ mTop = ( int ) ( mTopF * skbHeight );
+ mBottom = ( int ) ( mBottomF * skbHeight );
+ }
+
+ public Drawable getKeyIcon() {
+ return mKeyIcon;
+ }
+
+ public Drawable getKeyIconPopup() {
+ if ( null != mKeyIconPopup ) {
+ return mKeyIconPopup;
+ }
+ return mKeyIcon;
+ }
+
+ public int getKeyCode() {
+ return mKeyCode;
+ }
+
+ public String getKeyLabel() {
+ return mKeyLabel;
+ }
+
+ public void changeCase ( boolean upperCase ) {
+ if ( null != mKeyLabel ) {
+ if ( upperCase ) {
+ mKeyLabel = mKeyLabel.toUpperCase();
+ } else {
+ mKeyLabel = mKeyLabel.toLowerCase();
+ }
+ }
+ }
+
+ public Drawable getKeyBg() {
+ return mKeyType.mKeyBg;
+ }
+
+ public Drawable getKeyHlBg() {
+ return mKeyType.mKeyHlBg;
+ }
+
+ public int getColor() {
+ return mKeyType.mColor;
+ }
+
+ public int getColorHl() {
+ return mKeyType.mColorHl;
+ }
+
+ public int getColorBalloon() {
+ return mKeyType.mColorBalloon;
+ }
+
+ public boolean isKeyCodeKey() {
+ if ( mKeyCode > 0 ) { return true; }
+ return false;
+ }
+
+ public boolean isUserDefKey() {
+ if ( mKeyCode < 0 ) { return true; }
+ return false;
+ }
+
+ public boolean isUniStrKey() {
+ if ( null != mKeyLabel && mKeyCode == 0 ) { return true; }
+ return false;
+ }
+
+ public boolean needBalloon() {
+ return ( mKeyMask & KEYMASK_BALLOON ) != 0;
+ }
+
+ public boolean repeatable() {
+ return ( mKeyMask & KEYMASK_REPEAT ) != 0;
+ }
+
+ public int getPopupResId() {
+ return mPopupSkbId;
+ }
+
+ public int width() {
+ return mRight - mLeft;
+ }
+
+ public int height() {
+ return mBottom - mTop;
+ }
+
+ public boolean moveWithinKey ( int x, int y ) {
+ if ( mLeft - MAX_MOVE_TOLERANCE_X <= x
+ && mTop - MAX_MOVE_TOLERANCE_Y <= y
+ && mRight + MAX_MOVE_TOLERANCE_X > x
+ && mBottom + MAX_MOVE_TOLERANCE_Y > y ) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ String str = "\n";
+ str += " keyCode: " + String.valueOf ( mKeyCode ) + "\n";
+ str += " keyMask: " + String.valueOf ( mKeyMask ) + "\n";
+ str += " keyLabel: " + ( mKeyLabel == null ? "null" : mKeyLabel ) + "\n";
+ str += " popupResId: " + String.valueOf ( mPopupSkbId ) + "\n";
+ str += " Position: " + String.valueOf ( mLeftF ) + ", "
+ + String.valueOf ( mTopF ) + ", " + String.valueOf ( mRightF ) + ", "
+ + String.valueOf ( mBottomF ) + "\n";
+ return str;
+ }
+
+ public void setKeyPos ( int row, int location ) {
+ mRow = row;
+ mLocation = location;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SoftKeyToggle.java b/src/com/droidlogic/inputmethod/remote/SoftKeyToggle.java
new file mode 100644
index 0000000..c879bd5
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SoftKeyToggle.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Class for soft keys which defined in the keyboard xml file. A soft key can be
+ * a basic key or a toggling key.
+ *
+ * @see com.droidlogic.inputmethod.remote.SoftKey
+ */
+public class SoftKeyToggle extends SoftKey {
+ /**
+ * The current state number is stored in the lowest 8 bits of mKeyMask, this
+ * mask is used to get the state number. If the current state is 0, the
+ * normal state is enabled; if the current state is more than 0, a toggle
+ * state in the toggle state chain will be enabled.
+ */
+ private static final int KEYMASK_TOGGLE_STATE = 0x000000ff;
+
+ private ToggleState mToggleState;
+
+ public int getToggleStateId() {
+ return ( mKeyMask & KEYMASK_TOGGLE_STATE );
+ }
+
+ // The state id should be valid, and less than 255.
+ // If resetIfNotFound is true and there is no such toggle state with the
+ // given id, the key state will be reset.
+ // If the key state is newly changed (enabled to the given state, or
+ // reseted) and needs re-draw, return true.
+ public boolean enableToggleState ( int stateId, boolean resetIfNotFound ) {
+ int oldStateId = ( mKeyMask & KEYMASK_TOGGLE_STATE );
+ if ( oldStateId == stateId ) { return false; }
+ mKeyMask &= ( ~KEYMASK_TOGGLE_STATE );
+ if ( stateId > 0 ) {
+ mKeyMask |= ( KEYMASK_TOGGLE_STATE & stateId );
+ if ( getToggleState() == null ) {
+ mKeyMask &= ( ~KEYMASK_TOGGLE_STATE );
+ if ( !resetIfNotFound && oldStateId > 0 ) {
+ mKeyMask |= ( KEYMASK_TOGGLE_STATE & oldStateId );
+ }
+ return resetIfNotFound;
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ // The state id should be valid, and less than 255.
+ // If resetIfNotFound is true and there is no such toggle state with the
+ // given id, the key state will be reset.
+ // If the key state is newly changed and needs re-draw, return true.
+ public boolean disableToggleState ( int stateId, boolean resetIfNotFound ) {
+ int oldStateId = ( mKeyMask & KEYMASK_TOGGLE_STATE );
+ if ( oldStateId == stateId ) {
+ mKeyMask &= ( ~KEYMASK_TOGGLE_STATE );
+ return stateId != 0;
+ }
+ if ( resetIfNotFound ) {
+ mKeyMask &= ( ~KEYMASK_TOGGLE_STATE );
+ return oldStateId != 0;
+ }
+ return false;
+ }
+
+ // Clear any toggle state. If the key needs re-draw, return true.
+ public boolean disableAllToggleStates() {
+ int oldStateId = ( mKeyMask & KEYMASK_TOGGLE_STATE );
+ mKeyMask &= ( ~KEYMASK_TOGGLE_STATE );
+ return oldStateId != 0;
+ }
+
+ @Override
+ public Drawable getKeyIcon() {
+ ToggleState state = getToggleState();
+ if ( null != state ) { return state.mKeyIcon; }
+ return super.getKeyIcon();
+ }
+
+ @Override
+ public Drawable getKeyIconPopup() {
+ ToggleState state = getToggleState();
+ if ( null != state ) {
+ if ( null != state.mKeyIconPopup ) {
+ return state.mKeyIconPopup;
+ } else {
+ return state.mKeyIcon;
+ }
+ }
+ return super.getKeyIconPopup();
+ }
+
+ @Override
+ public int getKeyCode() {
+ ToggleState state = getToggleState();
+ if ( null != state ) { return state.mKeyCode; }
+ return mKeyCode;
+ }
+
+ @Override
+ public String getKeyLabel() {
+ ToggleState state = getToggleState();
+ if ( null != state ) { return state.mKeyLabel; }
+ return mKeyLabel;
+ }
+
+ @Override
+ public Drawable getKeyBg() {
+ ToggleState state = getToggleState();
+ if ( null != state && null != state.mKeyType ) {
+ return state.mKeyType.mKeyBg;
+ }
+ return mKeyType.mKeyBg;
+ }
+
+ @Override
+ public Drawable getKeyHlBg() {
+ ToggleState state = getToggleState();
+ if ( null != state && null != state.mKeyType ) {
+ return state.mKeyType.mKeyHlBg;
+ }
+ return mKeyType.mKeyHlBg;
+ }
+
+ @Override
+ public int getColor() {
+ ToggleState state = getToggleState();
+ if ( null != state && null != state.mKeyType ) {
+ return state.mKeyType.mColor;
+ }
+ return mKeyType.mColor;
+ }
+
+ @Override
+ public int getColorHl() {
+ ToggleState state = getToggleState();
+ if ( null != state && null != state.mKeyType ) {
+ return state.mKeyType.mColorHl;
+ }
+ return mKeyType.mColorHl;
+ }
+
+ @Override
+ public int getColorBalloon() {
+ ToggleState state = getToggleState();
+ if ( null != state && null != state.mKeyType ) {
+ return state.mKeyType.mColorBalloon;
+ }
+ return mKeyType.mColorBalloon;
+ }
+
+ @Override
+ public boolean isKeyCodeKey() {
+ ToggleState state = getToggleState();
+ if ( null != state ) {
+ if ( state.mKeyCode > 0 ) { return true; }
+ return false;
+ }
+ return super.isKeyCodeKey();
+ }
+
+ @Override
+ public boolean isUserDefKey() {
+ ToggleState state = getToggleState();
+ if ( null != state ) {
+ if ( state.mKeyCode < 0 ) { return true; }
+ return false;
+ }
+ return super.isUserDefKey();
+ }
+
+ @Override
+ public boolean isUniStrKey() {
+ ToggleState state = getToggleState();
+ if ( null != state ) {
+ if ( null != state.mKeyLabel && state.mKeyCode == 0 ) {
+ return true;
+ }
+ return false;
+ }
+ return super.isUniStrKey();
+ }
+
+ @Override
+ public boolean needBalloon() {
+ ToggleState state = getToggleState();
+ if ( null != state ) {
+ return ( state.mIdAndFlags & KEYMASK_BALLOON ) != 0;
+ }
+ return super.needBalloon();
+ }
+
+ @Override
+ public boolean repeatable() {
+ ToggleState state = getToggleState();
+ if ( null != state ) {
+ return ( state.mIdAndFlags & KEYMASK_REPEAT ) != 0;
+ }
+ return super.repeatable();
+ }
+
+ @Override
+ public void changeCase ( boolean lowerCase ) {
+ ToggleState state = getToggleState();
+ if ( null != state && null != state.mKeyLabel ) {
+ if ( lowerCase ) {
+ state.mKeyLabel = state.mKeyLabel.toLowerCase();
+ } else {
+ state.mKeyLabel = state.mKeyLabel.toUpperCase();
+ }
+ }
+ }
+
+ public ToggleState createToggleState() {
+ return new ToggleState();
+ }
+
+ public boolean setToggleStates ( ToggleState rootState ) {
+ if ( null == rootState ) { return false; }
+ mToggleState = rootState;
+ return true;
+ }
+
+ private ToggleState getToggleState() {
+ int stateId = ( mKeyMask & KEYMASK_TOGGLE_STATE );
+ if ( 0 == stateId ) { return null; }
+ ToggleState state = mToggleState;
+ while ( ( null != state )
+ && ( state.mIdAndFlags & KEYMASK_TOGGLE_STATE ) != stateId ) {
+ state = state.mNextState;
+ }
+ return state;
+ }
+
+ public class ToggleState {
+ // The id should be bigger than 0;
+ private int mIdAndFlags;
+ public SoftKeyType mKeyType;
+ public int mKeyCode;
+ public Drawable mKeyIcon;
+ public Drawable mKeyIconPopup;
+ public String mKeyLabel;
+ public ToggleState mNextState;
+
+ public void setStateId ( int stateId ) {
+ mIdAndFlags |= ( stateId & KEYMASK_TOGGLE_STATE );
+ }
+
+ public void setStateFlags ( boolean repeat, boolean balloon ) {
+ if ( repeat ) {
+ mIdAndFlags |= KEYMASK_REPEAT;
+ } else {
+ mIdAndFlags &= ( ~KEYMASK_REPEAT );
+ }
+ if ( balloon ) {
+ mIdAndFlags |= KEYMASK_BALLOON;
+ } else {
+ mIdAndFlags &= ( ~KEYMASK_BALLOON );
+ }
+ }
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SoftKeyboard.java b/src/com/droidlogic/inputmethod/remote/SoftKeyboard.java
new file mode 100644
index 0000000..ca7ec14
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SoftKeyboard.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import com.droidlogic.inputmethod.remote.InputModeSwitcher.ToggleStates;
+
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class used to represent a soft keyboard definition, including the height, the
+ * background image, the image for high light, the keys, etc.
+ */
+public class SoftKeyboard {
+ /** The XML resource id for this soft keyboard. */
+ private int mSkbXmlId;
+
+ /** Do we need to cache this soft keyboard? */
+ private boolean mCacheFlag;
+
+ /**
+ * After user switches to this soft keyboard, if this flag is true, this
+ * soft keyboard will be kept unless explicit switching operation is
+ * performed, otherwise IME will switch back to the previous keyboard layout
+ * whenever user clicks on any none-function key.
+ **/
+ private boolean mStickyFlag;
+
+ /**
+ * The cache id for this soft keyboard. It is used to identify it in the
+ * soft keyboard pool.
+ */
+ private int mCacheId;
+
+ /**
+ * Used to indicate whether this soft keyboard is newly loaded from an XML
+ * file or is just gotten from the soft keyboard pool.
+ */
+ private boolean mNewlyLoadedFlag = true;
+
+ /** The width of the soft keyboard. */
+ private int mSkbCoreWidth;
+
+ /** The height of the soft keyboard. */
+ private int mSkbCoreHeight;
+
+ /** The soft keyboard template for this soft keyboard. */
+ private SkbTemplate mSkbTemplate;
+
+ /** Used to indicate whether this soft keyboard is a QWERTY keyboard. */
+ private boolean mIsQwerty;
+
+ /**
+ * When {@link #mIsQwerty} is true, this member is Used to indicate that the
+ * soft keyboard should be displayed in uppercase.
+ */
+ private boolean mIsQwertyUpperCase;
+
+ /**
+ * The id of the rows which are enabled. Rows with id
+ * {@link KeyRow#ALWAYS_SHOW_ROW_ID} are always enabled.
+ */
+ private int mEnabledRowId;
+
+ /**
+ * Rows in this soft keyboard. Each row has a id. Only matched rows will be
+ * enabled.
+ */
+ private List<KeyRow> mKeyRows;
+
+ /**
+ * Background of the soft keyboard. If it is null, the one in the soft
+ * keyboard template will be used.
+ **/
+ public Drawable mSkbBg;
+
+ /**
+ * Background for key balloon. If it is null, the one in the soft keyboard
+ * template will be used.
+ **/
+ private Drawable mBalloonBg;
+
+ /**
+ * Background for popup mini soft keyboard. If it is null, the one in the
+ * soft keyboard template will be used.
+ **/
+ private Drawable mPopupBg;
+
+ /** The left and right margin of a key. */
+ private float mKeyXMargin = 0;
+
+ /** The top and bottom margin of a key. */
+ private float mKeyYMargin = 0;
+
+ private Rect mTmpRect = new Rect();
+
+ public SoftKeyboard ( int skbXmlId, SkbTemplate skbTemplate, int skbWidth,
+ int skbHeight ) {
+ mSkbXmlId = skbXmlId;
+ mSkbTemplate = skbTemplate;
+ mSkbCoreWidth = skbWidth;
+ mSkbCoreHeight = skbHeight;
+ }
+
+ public void setFlags ( boolean cacheFlag, boolean stickyFlag,
+ boolean isQwerty, boolean isQwertyUpperCase ) {
+ mCacheFlag = cacheFlag;
+ mStickyFlag = stickyFlag;
+ mIsQwerty = isQwerty;
+ mIsQwertyUpperCase = isQwertyUpperCase;
+ }
+
+ public boolean getCacheFlag() {
+ return mCacheFlag;
+ }
+
+ public void setCacheId ( int cacheId ) {
+ mCacheId = cacheId;
+ }
+
+ public boolean getStickyFlag() {
+ return mStickyFlag;
+ }
+
+ public void setSkbBackground ( Drawable skbBg ) {
+ mSkbBg = skbBg;
+ }
+
+ public void setPopupBackground ( Drawable popupBg ) {
+ mPopupBg = popupBg;
+ }
+
+ public void setKeyBalloonBackground ( Drawable balloonBg ) {
+ mBalloonBg = balloonBg;
+ }
+
+ public void setKeyMargins ( float xMargin, float yMargin ) {
+ mKeyXMargin = xMargin;
+ mKeyYMargin = yMargin;
+ }
+
+ public int getCacheId() {
+ return mCacheId;
+ }
+
+ public void reset() {
+ if ( null != mKeyRows ) { mKeyRows.clear(); }
+ }
+
+ public void setNewlyLoadedFlag ( boolean newlyLoadedFlag ) {
+ mNewlyLoadedFlag = newlyLoadedFlag;
+ }
+
+ public boolean getNewlyLoadedFlag() {
+ return mNewlyLoadedFlag;
+ }
+
+ public void beginNewRow ( int rowId, float yStartingPos ) {
+ if ( null == mKeyRows ) { mKeyRows = new ArrayList<KeyRow>(); }
+ KeyRow keyRow = new KeyRow();
+ keyRow.mRowId = rowId;
+ keyRow.mTopF = yStartingPos;
+ keyRow.mBottomF = yStartingPos;
+ keyRow.mSoftKeys = new ArrayList<SoftKey>();
+ mKeyRows.add ( keyRow );
+ }
+
+ public boolean addSoftKey ( SoftKey softKey ) {
+ if ( mKeyRows.size() == 0 ) { return false; }
+ KeyRow keyRow = mKeyRows.get ( mKeyRows.size() - 1 );
+ if ( null == keyRow ) { return false; }
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ softKey.setSkbCoreSize ( mSkbCoreWidth, mSkbCoreHeight );
+ softKeys.add ( softKey );
+ softKey.setKeyPos ( mKeyRows.size() - 1, softKeys.size() - 1 );
+ if ( softKey.mTopF < keyRow.mTopF ) {
+ keyRow.mTopF = softKey.mTopF;
+ }
+ if ( softKey.mBottomF > keyRow.mBottomF ) {
+ keyRow.mBottomF = softKey.mBottomF;
+ }
+ return true;
+ }
+
+ public int getSkbXmlId() {
+ return mSkbXmlId;
+ }
+
+ // Set the size of the soft keyboard core. In other words, the background's
+ // padding are not counted.
+ public void setSkbCoreSize ( int skbCoreWidth, int skbCoreHeight ) {
+ if ( null == mKeyRows
+ || ( skbCoreWidth == mSkbCoreWidth && skbCoreHeight == mSkbCoreHeight ) ) {
+ return;
+ }
+ for ( int row = 0; row < mKeyRows.size(); row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ keyRow.mBottom = ( int ) ( skbCoreHeight * keyRow.mBottomF );
+ keyRow.mTop = ( int ) ( skbCoreHeight * keyRow.mTopF );
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ for ( int i = 0; i < softKeys.size(); i++ ) {
+ SoftKey softKey = softKeys.get ( i );
+ softKey.setSkbCoreSize ( skbCoreWidth, skbCoreHeight );
+ }
+ }
+ mSkbCoreWidth = skbCoreWidth;
+ mSkbCoreHeight = skbCoreHeight;
+ }
+
+ public int getSkbCoreWidth() {
+ return mSkbCoreWidth;
+ }
+
+ public int getSkbCoreHeight() {
+ return mSkbCoreHeight;
+ }
+
+ public int getSkbTotalWidth() {
+ Rect padding = getPadding();
+ return mSkbCoreWidth + padding.left + padding.right;
+ }
+
+ public int getSkbTotalHeight() {
+ Rect padding = getPadding();
+ return mSkbCoreHeight + padding.top + padding.bottom;
+ }
+
+ public int getKeyXMargin() {
+ Environment env = Environment.getInstance();
+ return ( int ) ( mKeyXMargin * mSkbCoreWidth * env.getKeyXMarginFactor() );
+ }
+
+ public int getKeyYMargin() {
+ Environment env = Environment.getInstance();
+ return ( int ) ( mKeyYMargin * mSkbCoreHeight * env.getKeyYMarginFactor() );
+ }
+
+ public Drawable getSkbBackground() {
+ if ( null != mSkbBg ) { return mSkbBg; }
+ return mSkbTemplate.getSkbBackground();
+ }
+
+ public Drawable getBalloonBackground() {
+ if ( null != mBalloonBg ) { return mBalloonBg; }
+ return mSkbTemplate.getBalloonBackground();
+ }
+
+ public Drawable getPopupBackground() {
+ if ( null != mPopupBg ) { return mPopupBg; }
+ return mSkbTemplate.getPopupBackground();
+ }
+
+ public int getRowNum() {
+ if ( null != mKeyRows ) {
+ return mKeyRows.size();
+ }
+ return 0;
+ }
+
+ public int getLocNum ( int row ) {
+ if ( null == mKeyRows ) {
+ return 0;
+ }
+ if ( mKeyRows.size() <= row ) {
+ row = mKeyRows.size() - 1;
+ } else if ( row < 0 ) {
+ row = 0;
+ }
+ List<SoftKey> softKeys = mKeyRows.get ( row ).mSoftKeys;
+ return softKeys.size();
+ }
+
+ public KeyRow getKeyRowForDisplay ( int row ) {
+ if ( null != mKeyRows && mKeyRows.size() > row ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ if ( KeyRow.ALWAYS_SHOW_ROW_ID == keyRow.mRowId
+ || keyRow.mRowId == mEnabledRowId ) {
+ return keyRow;
+ }
+ }
+ return null;
+ }
+
+ public SoftKey getKey ( int row, int location ) {
+ if ( null != mKeyRows ) {
+ if ( mKeyRows.size() <= row ) {
+ row = mKeyRows.size() - 1;
+ } else if ( row < 0 ) {
+ row = 0;
+ }
+ List<SoftKey> softKeys = mKeyRows.get ( row ).mSoftKeys;
+ if ( location < 0 ) {
+ location = softKeys.size() - 1;
+ }
+ if ( softKeys.size() > location ) {
+ return softKeys.get ( location );
+ }
+ }
+ return null;
+ }
+
+ public SoftKey mapToKey ( int x, int y ) {
+ if ( null == mKeyRows ) {
+ return null;
+ }
+ // If the position is inside the rectangle of a certain key, return that
+ // key.
+ int rowNum = mKeyRows.size();
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ if ( KeyRow.ALWAYS_SHOW_ROW_ID != keyRow.mRowId
+ && keyRow.mRowId != mEnabledRowId ) { continue; }
+ if ( keyRow.mTop > y && keyRow.mBottom <= y ) { continue; }
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int i = 0; i < keyNum; i++ ) {
+ SoftKey sKey = softKeys.get ( i );
+ if ( sKey.mLeft <= x && sKey.mTop <= y && sKey.mRight > x
+ && sKey.mBottom > y ) {
+ return sKey;
+ }
+ }
+ }
+ // If the position is outside the rectangles of all keys, find the
+ // nearest one.
+ SoftKey nearestKey = null;
+ float nearestDis = Float.MAX_VALUE;
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ if ( KeyRow.ALWAYS_SHOW_ROW_ID != keyRow.mRowId
+ && keyRow.mRowId != mEnabledRowId ) { continue; }
+ if ( keyRow.mTop > y && keyRow.mBottom <= y ) { continue; }
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int i = 0; i < keyNum; i++ ) {
+ SoftKey sKey = softKeys.get ( i );
+ int disx = ( sKey.mLeft + sKey.mRight ) / 2 - x;
+ int disy = ( sKey.mTop + sKey.mBottom ) / 2 - y;
+ float dis = disx * disx + disy * disy;
+ if ( dis < nearestDis ) {
+ nearestDis = dis;
+ nearestKey = sKey;
+ }
+ }
+ }
+ return nearestKey;
+ }
+
+ public void switchQwertyMode ( int toggle_state_id, boolean upperCase ) {
+ if ( !mIsQwerty ) { return; }
+ int rowNum = mKeyRows.size();
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int i = 0; i < keyNum; i++ ) {
+ SoftKey sKey = softKeys.get ( i );
+ if ( sKey instanceof SoftKeyToggle ) {
+ ( ( SoftKeyToggle ) sKey ).enableToggleState ( toggle_state_id,
+ true );
+ }
+ if ( sKey.mKeyCode >= KeyEvent.KEYCODE_A
+ && sKey.mKeyCode <= KeyEvent.KEYCODE_Z ) {
+ sKey.changeCase ( upperCase );
+ }
+ }
+ }
+ }
+
+ public void enableToggleState ( int toggleStateId, boolean resetIfNotFound ) {
+ int rowNum = mKeyRows.size();
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int i = 0; i < keyNum; i++ ) {
+ SoftKey sKey = softKeys.get ( i );
+ if ( sKey instanceof SoftKeyToggle ) {
+ ( ( SoftKeyToggle ) sKey ).enableToggleState ( toggleStateId,
+ resetIfNotFound );
+ }
+ }
+ }
+ }
+
+ public void disableToggleState ( int toggleStateId, boolean resetIfNotFound ) {
+ int rowNum = mKeyRows.size();
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int i = 0; i < keyNum; i++ ) {
+ SoftKey sKey = softKeys.get ( i );
+ if ( sKey instanceof SoftKeyToggle ) {
+ ( ( SoftKeyToggle ) sKey ).disableToggleState ( toggleStateId,
+ resetIfNotFound );
+ }
+ }
+ }
+ }
+
+ public void enableToggleStates ( ToggleStates toggleStates ) {
+ if ( null == toggleStates ) { return; }
+ enableRow ( toggleStates.mRowIdToEnable );
+ boolean isQwerty = toggleStates.mQwerty;
+ boolean isQwertyUpperCase = toggleStates.mQwertyUpperCase;
+ boolean needUpdateQwerty = ( isQwerty && mIsQwerty && ( mIsQwertyUpperCase != isQwertyUpperCase ) );
+ int states[] = toggleStates.mKeyStates;
+ int statesNum = toggleStates.mKeyStatesNum;
+ int rowNum = mKeyRows.size();
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ if ( KeyRow.ALWAYS_SHOW_ROW_ID != keyRow.mRowId
+ && keyRow.mRowId != mEnabledRowId ) {
+ continue;
+ }
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int keyPos = 0; keyPos < keyNum; keyPos++ ) {
+ SoftKey sKey = softKeys.get ( keyPos );
+ if ( sKey instanceof SoftKeyToggle ) {
+ for ( int statePos = 0; statePos < statesNum; statePos++ ) {
+ ( ( SoftKeyToggle ) sKey ).enableToggleState (
+ states[statePos], statePos == 0 );
+ }
+ if ( 0 == statesNum ) {
+ ( ( SoftKeyToggle ) sKey ).disableAllToggleStates();
+ }
+ }
+ if ( needUpdateQwerty ) {
+ if ( sKey.mKeyCode >= KeyEvent.KEYCODE_A
+ && sKey.mKeyCode <= KeyEvent.KEYCODE_Z ) {
+ sKey.changeCase ( isQwertyUpperCase );
+ }
+ }
+ }
+ }
+ mIsQwertyUpperCase = isQwertyUpperCase;
+ }
+
+ private Rect getPadding() {
+ mTmpRect.set ( 0, 0, 0, 0 );
+ Drawable skbBg = getSkbBackground();
+ if ( null == skbBg ) { return mTmpRect; }
+ skbBg.getPadding ( mTmpRect );
+ return mTmpRect;
+ }
+
+ /**
+ * Enable a row with the give toggle Id. Rows with other toggle ids (except
+ * the id {@link KeyRow#ALWAYS_SHOW_ROW_ID}) will be disabled.
+ *
+ * @param rowId The row id to enable.
+ * @return True if the soft keyboard requires redrawing.
+ */
+ private boolean enableRow ( int rowId ) {
+ if ( KeyRow.ALWAYS_SHOW_ROW_ID == rowId ) { return false; }
+ boolean enabled = false;
+ int rowNum = mKeyRows.size();
+ for ( int row = rowNum - 1; row >= 0; row-- ) {
+ if ( mKeyRows.get ( row ).mRowId == rowId ) {
+ enabled = true;
+ break;
+ }
+ }
+ if ( enabled ) {
+ mEnabledRowId = rowId;
+ }
+ return enabled;
+ }
+
+ @Override
+ public String toString() {
+ String str = "------------------SkbInfo----------------------\n";
+ String endStr = "-----------------------------------------------\n";
+ str += "Width: " + String.valueOf ( mSkbCoreWidth ) + "\n";
+ str += "Height: " + String.valueOf ( mSkbCoreHeight ) + "\n";
+ str += "KeyRowNum: " + mKeyRows == null ? "0" : String.valueOf ( mKeyRows
+ .size() )
+ + "\n";
+ if ( null == mKeyRows ) { return str + endStr; }
+ int rowNum = mKeyRows.size();
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mKeyRows.get ( row );
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int i = 0; i < softKeys.size(); i++ ) {
+ str += "-key " + String.valueOf ( i ) + ":"
+ + softKeys.get ( i ).toString();
+ }
+ }
+ return str + endStr;
+ }
+
+ public String toShortString() {
+ return super.toString();
+ }
+
+ class KeyRow {
+ static final int ALWAYS_SHOW_ROW_ID = -1;
+ static final int DEFAULT_ROW_ID = 0;
+
+ List<SoftKey> mSoftKeys;
+ /**
+ * If the row id is {@link #ALWAYS_SHOW_ROW_ID}, this row will always be
+ * enabled.
+ */
+ int mRowId;
+ float mTopF;
+ float mBottomF;
+ int mTop;
+ int mBottom;
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SoftKeyboardView.java b/src/com/droidlogic/inputmethod/remote/SoftKeyboardView.java
new file mode 100644
index 0000000..3309fc5
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SoftKeyboardView.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import com.droidlogic.inputmethod.remote.SoftKeyboard.KeyRow;
+
+import java.util.List;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.drawable.Drawable;
+/*import android.os.Vibrator;*/
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Class used to show a soft keyboard.
+ *
+ * A soft keyboard view should not handle touch event itself, because we do bias
+ * correction, need a global strategy to map an event into a proper view to
+ * achieve better user experience.
+ */
+public class SoftKeyboardView extends View {
+ /**
+ * The definition of the soft keyboard for the current this soft keyboard
+ * view.
+ */
+ private SoftKeyboard mSoftKeyboard;
+
+ /**
+ * The popup balloon hint for key press/release.
+ */
+ private BalloonHint mBalloonPopup;
+
+ /**
+ * The on-key balloon hint for key press/release. If it is null, on-key
+ * highlight will be drawn on th soft keyboard view directly.
+ */
+ private BalloonHint mBalloonOnKey;
+
+ /** Used to play key sounds. */
+ private SoundManager mSoundManager;
+
+ /** The last key pressed. */
+ private SoftKey mSoftKeyDown;
+
+ /** Used to indicate whether the user is holding on a key. */
+ private boolean mKeyPressed = false;
+
+ /**
+ * The location offset of the view to the keyboard container.
+ */
+ private int mOffsetToSkbContainer[] = new int[2];
+
+ /**
+ * The location of the desired hint view to the keyboard container.
+ */
+ private int mHintLocationToSkbContainer[] = new int[2];
+
+ /**
+ * Text size for normal key.
+ */
+ private int mNormalKeyTextSize;
+
+ /**
+ * Text size for function key.
+ */
+ private int mFunctionKeyTextSize;
+
+ /**
+ * Long press timer used to response long-press.
+ */
+ private SkbContainer.LongPressTimer mLongPressTimer;
+
+ /**
+ * Repeated events for long press
+ */
+ private boolean mRepeatForLongPress = false;
+
+ /**
+ * If this parameter is true, the balloon will never be dismissed even if
+ * user moves a lot from the pressed point.
+ */
+ private boolean mMovingNeverHidePopupBalloon = false;
+
+ /** Vibration for key press. */
+ private Vibrator mVibrator;
+
+ /** Vibration pattern for key press. */
+ protected long[] mVibratePattern = new long[] {1, 20};
+
+ /**
+ * The dirty rectangle used to mark the area to re-draw during key press and
+ * release. Currently, whenever we can invalidate(Rect), view will call
+ * onDraw() and we MUST draw the whole view. This dirty information is for
+ * future use.
+ */
+ private Rect mDirtyRect = new Rect();
+
+ private Paint mPaint;
+ private FontMetricsInt mFmi;
+ private boolean mDimSkb;
+
+ /** Add by lyra:The last key pressed. */
+ public SoftKey mSoftKeyFocus;
+
+ public SoftKeyboardView ( Context context, AttributeSet attrs ) {
+ super ( context, attrs );
+ mSoundManager = SoundManager.getInstance ( mContext );
+ mPaint = new Paint();
+ mPaint.setAntiAlias ( true );
+ mFmi = mPaint.getFontMetricsInt();
+ }
+
+ public boolean setSoftKeyboard ( SoftKeyboard softSkb ) {
+ if ( null == softSkb ) {
+ return false;
+ }
+ mSoftKeyboard = softSkb;
+ Drawable bg = softSkb.getSkbBackground();
+ if ( null != bg ) { setBackgroundDrawable ( bg ); }
+ return true;
+ }
+
+ public SoftKeyboard getSoftKeyboard() {
+ return mSoftKeyboard;
+ }
+
+ public void resizeKeyboard ( int skbWidth, int skbHeight ) {
+ mSoftKeyboard.setSkbCoreSize ( skbWidth, skbHeight );
+ }
+
+ public void setBalloonHint ( BalloonHint balloonOnKey,
+ BalloonHint balloonPopup, boolean movingNeverHidePopup ) {
+ mBalloonOnKey = balloonOnKey;
+ mBalloonPopup = balloonPopup;
+ mMovingNeverHidePopupBalloon = movingNeverHidePopup;
+ }
+
+ public void setOffsetToSkbContainer ( int offsetToSkbContainer[] ) {
+ mOffsetToSkbContainer[0] = offsetToSkbContainer[0];
+ mOffsetToSkbContainer[1] = offsetToSkbContainer[1];
+ }
+
+ @Override
+ protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) {
+ int measuredWidth = 0;
+ int measuredHeight = 0;
+ if ( null != mSoftKeyboard ) {
+ measuredWidth = mSoftKeyboard.getSkbCoreWidth();
+ measuredHeight = mSoftKeyboard.getSkbCoreHeight();
+ measuredWidth += mPaddingLeft + mPaddingRight;
+ measuredHeight += mPaddingTop + mPaddingBottom;
+ }
+ setMeasuredDimension ( measuredWidth, measuredHeight );
+ }
+
+ private void showBalloon ( BalloonHint balloon, int balloonLocationToSkb[],
+ boolean movePress ) {
+ long delay = BalloonHint.TIME_DELAY_SHOW;
+ if ( movePress ) { delay = 0; }
+ if ( balloon.needForceDismiss() ) {
+ balloon.delayedDismiss ( 0 );
+ }
+ if ( !balloon.isShowing() ) {
+ balloon.delayedShow ( delay, balloonLocationToSkb );
+ } else {
+ balloon.delayedUpdate ( delay, balloonLocationToSkb, balloon
+ .getWidth(), balloon.getHeight() );
+ }
+ long b = System.currentTimeMillis();
+ }
+
+ public void resetKeyPress ( long balloonDelay ) {
+ if ( !mKeyPressed ) { return; }
+ mKeyPressed = false;
+ if ( null != mBalloonOnKey ) {
+ mBalloonOnKey.delayedDismiss ( balloonDelay );
+ } else {
+ if ( null != mSoftKeyDown ) {
+ if ( mDirtyRect.isEmpty() ) {
+ mDirtyRect.set ( mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
+ mSoftKeyDown.mRight, mSoftKeyDown.mBottom );
+ }
+ invalidate ( mDirtyRect );
+ } else {
+ invalidate();
+ }
+ }
+ mBalloonPopup.delayedDismiss ( balloonDelay );
+ }
+
+ // If movePress is true, means that this function is called because user
+ // moves his finger to this button. If movePress is false, means that this
+ // function is called when user just presses this key.
+ public SoftKey onKeyPress ( int x, int y,
+ SkbContainer.LongPressTimer longPressTimer, boolean movePress ) {
+ mKeyPressed = false;
+ boolean moveWithinPreviousKey = false;
+ if ( movePress ) {
+ SoftKey newKey = mSoftKeyboard.mapToKey ( x, y );
+ if ( newKey == mSoftKeyDown ) { moveWithinPreviousKey = true; }
+ mSoftKeyDown = newKey;
+ } else {
+ mSoftKeyDown = mSoftKeyboard.mapToKey ( x, y );
+ }
+ if ( moveWithinPreviousKey || null == mSoftKeyDown ) { return mSoftKeyDown; }
+ mKeyPressed = true;
+ if ( !movePress ) {
+ tryPlayKeyDown();
+ tryVibrate();
+ }
+ mLongPressTimer = longPressTimer;
+ if ( !movePress ) {
+ if ( mSoftKeyDown.getPopupResId() > 0 || mSoftKeyDown.repeatable() ) {
+ mLongPressTimer.startTimer();
+ }
+ } else {
+ mLongPressTimer.removeTimer();
+ }
+ int desired_width;
+ int desired_height;
+ float textSize;
+ Environment env = Environment.getInstance();
+ if ( null != mBalloonOnKey ) {
+ Drawable keyHlBg = mSoftKeyDown.getKeyHlBg();
+ mBalloonOnKey.setBalloonBackground ( keyHlBg );
+ // Prepare the on-key balloon
+ int keyXMargin = mSoftKeyboard.getKeyXMargin();
+ int keyYMargin = mSoftKeyboard.getKeyYMargin();
+ desired_width = mSoftKeyDown.width() - 2 * keyXMargin;
+ desired_height = mSoftKeyDown.height() - 2 * keyYMargin;
+ textSize = env
+ .getKeyTextSize ( SoftKeyType.KEYTYPE_ID_NORMAL_KEY != mSoftKeyDown.mKeyType.mKeyTypeId );
+ Drawable icon = mSoftKeyDown.getKeyIcon();
+ if ( null != icon ) {
+ mBalloonOnKey.setBalloonConfig ( icon, desired_width,
+ desired_height );
+ } else {
+ mBalloonOnKey.setBalloonConfig ( mSoftKeyDown.getKeyLabel(),
+ textSize, true, mSoftKeyDown.getColorHl(),
+ desired_width, desired_height );
+ }
+ mHintLocationToSkbContainer[0] = mPaddingLeft + mSoftKeyDown.mLeft
+ - ( mBalloonOnKey.getWidth() - mSoftKeyDown.width() ) / 2;
+ mHintLocationToSkbContainer[0] += mOffsetToSkbContainer[0];
+ mHintLocationToSkbContainer[1] = mPaddingTop
+ + ( mSoftKeyDown.mBottom - keyYMargin )
+ - mBalloonOnKey.getHeight();
+ mHintLocationToSkbContainer[1] += mOffsetToSkbContainer[1];
+ showBalloon ( mBalloonOnKey, mHintLocationToSkbContainer, movePress );
+ } else {
+ mDirtyRect.union ( mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
+ mSoftKeyDown.mRight, mSoftKeyDown.mBottom );
+ invalidate ( mDirtyRect );
+ }
+ // Prepare the popup balloon
+ if ( mSoftKeyDown.needBalloon() ) {
+ Drawable balloonBg = mSoftKeyboard.getBalloonBackground();
+ mBalloonPopup.setBalloonBackground ( balloonBg );
+ desired_width = mSoftKeyDown.width() + env.getKeyBalloonWidthPlus();
+ desired_height = mSoftKeyDown.height()
+ + env.getKeyBalloonHeightPlus();
+ textSize = env
+ .getBalloonTextSize ( SoftKeyType.KEYTYPE_ID_NORMAL_KEY != mSoftKeyDown.mKeyType.mKeyTypeId );
+ Drawable iconPopup = mSoftKeyDown.getKeyIconPopup();
+ if ( null != iconPopup ) {
+ mBalloonPopup.setBalloonConfig ( iconPopup, desired_width,
+ desired_height );
+ } else {
+ mBalloonPopup.setBalloonConfig ( mSoftKeyDown.getKeyLabel(),
+ textSize, mSoftKeyDown.needBalloon(), mSoftKeyDown
+ .getColorBalloon(), desired_width,
+ desired_height );
+ }
+ // The position to show.
+ mHintLocationToSkbContainer[0] = mPaddingLeft + mSoftKeyDown.mLeft
+ + - ( mBalloonPopup.getWidth() - mSoftKeyDown.width() ) / 2;
+ mHintLocationToSkbContainer[0] += mOffsetToSkbContainer[0];
+ mHintLocationToSkbContainer[1] = mPaddingTop + mSoftKeyDown.mTop
+ - mBalloonPopup.getHeight();
+ mHintLocationToSkbContainer[1] += mOffsetToSkbContainer[1];
+ showBalloon ( mBalloonPopup, mHintLocationToSkbContainer, movePress );
+ } else {
+ mBalloonPopup.delayedDismiss ( 0 );
+ }
+ if ( mRepeatForLongPress ) { longPressTimer.startTimer(); }
+ return mSoftKeyDown;
+ }
+
+ public SoftKey onKeyRelease ( int x, int y ) {
+ mKeyPressed = false;
+ if ( null == mSoftKeyDown ) { return null; }
+ mLongPressTimer.removeTimer();
+ if ( null != mBalloonOnKey ) {
+ mBalloonOnKey.delayedDismiss ( BalloonHint.TIME_DELAY_DISMISS );
+ } else {
+ mDirtyRect.union ( mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
+ mSoftKeyDown.mRight, mSoftKeyDown.mBottom );
+ invalidate ( mDirtyRect );
+ }
+ if ( mSoftKeyDown.needBalloon() ) {
+ mBalloonPopup.delayedDismiss ( BalloonHint.TIME_DELAY_DISMISS );
+ }
+ if ( mSoftKeyDown.moveWithinKey ( x - mPaddingLeft, y - mPaddingTop ) ) {
+ return mSoftKeyDown;
+ }
+ return null;
+ }
+
+ public SoftKey onKeyMove ( int x, int y ) {
+ if ( null == mSoftKeyDown ) { return null; }
+ if ( mSoftKeyDown.moveWithinKey ( x - mPaddingLeft, y - mPaddingTop ) ) {
+ return mSoftKeyDown;
+ }
+ // The current key needs to be updated.
+ mDirtyRect.union ( mSoftKeyDown.mLeft, mSoftKeyDown.mTop,
+ mSoftKeyDown.mRight, mSoftKeyDown.mBottom );
+ if ( mRepeatForLongPress ) {
+ if ( mMovingNeverHidePopupBalloon ) {
+ return onKeyPress ( x, y, mLongPressTimer, true );
+ }
+ if ( null != mBalloonOnKey ) {
+ mBalloonOnKey.delayedDismiss ( 0 );
+ } else {
+ invalidate ( mDirtyRect );
+ }
+ if ( mSoftKeyDown.needBalloon() ) {
+ mBalloonPopup.delayedDismiss ( 0 );
+ }
+ if ( null != mLongPressTimer ) {
+ mLongPressTimer.removeTimer();
+ }
+ return onKeyPress ( x, y, mLongPressTimer, true );
+ } else {
+ // When user moves between keys, repeated response is disabled.
+ return onKeyPress ( x, y, mLongPressTimer, true );
+ }
+ }
+
+ private void tryVibrate() {
+ if ( !Settings.getVibrate() ) {
+ return;
+ }
+ if ( mVibrator == null ) {
+ mVibrator = new Vibrator();
+ }
+ mVibrator.vibrate ( mVibratePattern, -1 );
+ }
+
+ private void tryPlayKeyDown() {
+ if ( Settings.getKeySound() ) {
+ mSoundManager.playKeyDown();
+ }
+ }
+
+ public void dimSoftKeyboard ( boolean dimSkb ) {
+ mDimSkb = dimSkb;
+ invalidate();
+ }
+
+ public void changeFocusKey ( SoftKey key ) {
+ if ( mSoftKeyFocus != key ) {
+ mSoftKeyFocus = key;
+ invalidate();
+ }
+ }
+
+ @Override
+ protected void onDraw ( Canvas canvas ) {
+ if ( null == mSoftKeyboard ) { return; }
+ canvas.translate ( mPaddingLeft, mPaddingTop );
+ Environment env = Environment.getInstance();
+ mNormalKeyTextSize = env.getKeyTextSize ( false );
+ mFunctionKeyTextSize = env.getKeyTextSize ( true );
+ // Draw the last soft keyboard
+ int rowNum = mSoftKeyboard.getRowNum();
+ int keyXMargin = mSoftKeyboard.getKeyXMargin();
+ int keyYMargin = mSoftKeyboard.getKeyYMargin();
+ for ( int row = 0; row < rowNum; row++ ) {
+ KeyRow keyRow = mSoftKeyboard.getKeyRowForDisplay ( row );
+ if ( null == keyRow ) { continue; }
+ List<SoftKey> softKeys = keyRow.mSoftKeys;
+ int keyNum = softKeys.size();
+ for ( int i = 0; i < keyNum; i++ ) {
+ SoftKey softKey = softKeys.get ( i );
+ if ( SoftKeyType.KEYTYPE_ID_NORMAL_KEY == softKey.mKeyType.mKeyTypeId ) {
+ mPaint.setTextSize ( mNormalKeyTextSize );
+ } else {
+ mPaint.setTextSize ( mFunctionKeyTextSize );
+ }
+ drawSoftKey ( canvas, softKey, keyXMargin, keyYMargin );
+ }
+ }
+ if ( mDimSkb ) {
+ mPaint.setColor ( 0xa0000000 );
+ canvas.drawRect ( 0, 0, getWidth(), getHeight(), mPaint );
+ }
+ mDirtyRect.setEmpty();
+ }
+
+ private void drawSoftKey ( Canvas canvas, SoftKey softKey, int keyXMargin,
+ int keyYMargin ) {
+ Drawable bg;
+ int textColor;
+ if ( mKeyPressed && softKey == mSoftKeyDown ) {
+ bg = softKey.getKeyHlBg();
+ textColor = softKey.getColorHl();
+ }
+ //add focus key
+ else if ( softKey == mSoftKeyFocus ) {
+ bg = softKey.getKeyHlBg();
+ textColor = softKey.getColor();
+ } else {
+ bg = softKey.getKeyBg();
+ textColor = softKey.getColor();
+ }
+ if ( null != bg ) {
+ bg.setBounds ( softKey.mLeft + keyXMargin, softKey.mTop + keyYMargin,
+ softKey.mRight - keyXMargin, softKey.mBottom - keyYMargin );
+ bg.draw ( canvas );
+ }
+ String keyLabel = softKey.getKeyLabel();
+ Drawable keyIcon = softKey.getKeyIcon();
+ if ( null != keyIcon ) {
+ Drawable icon = keyIcon;
+ int marginLeft = ( softKey.width() - icon.getIntrinsicWidth() ) / 2;
+ int marginRight = softKey.width() - icon.getIntrinsicWidth()
+ - marginLeft;
+ int marginTop = ( softKey.height() - icon.getIntrinsicHeight() ) / 2;
+ int marginBottom = softKey.height() - icon.getIntrinsicHeight()
+ - marginTop;
+ icon.setBounds ( softKey.mLeft + marginLeft,
+ softKey.mTop + marginTop, softKey.mRight - marginRight,
+ softKey.mBottom - marginBottom );
+ icon.draw ( canvas );
+ } else if ( null != keyLabel ) {
+ mPaint.setColor ( textColor );
+ float x = softKey.mLeft
+ + ( softKey.width() - mPaint.measureText ( keyLabel ) ) / 2.0f;
+ int fontHeight = mFmi.bottom - mFmi.top;
+ float marginY = ( softKey.height() - fontHeight ) / 2.0f;
+ float y = softKey.mTop + marginY - mFmi.top + mFmi.bottom / 1.5f;
+ canvas.drawText ( keyLabel, x, y + 1, mPaint );
+ }
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/SoundManager.java b/src/com/droidlogic/inputmethod/remote/SoundManager.java
new file mode 100644
index 0000000..2abb6c3
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/SoundManager.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.content.Context;
+import android.media.AudioManager;
+
+/**
+ * Class used to manage related sound resources.
+ */
+public class SoundManager {
+ private static SoundManager mInstance = null;
+ private Context mContext;
+ private AudioManager mAudioManager;
+ // Align sound effect volume on music volume
+ private final float FX_VOLUME = -1.0f;
+ private boolean mSilentMode;
+
+ private SoundManager ( Context context ) {
+ mContext = context;
+ updateRingerMode();
+ }
+
+ public void updateRingerMode() {
+ if ( mAudioManager == null ) {
+ mAudioManager = ( AudioManager ) mContext
+ .getSystemService ( Context.AUDIO_SERVICE );
+ }
+ mSilentMode = ( mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL );
+ }
+
+ public static SoundManager getInstance ( Context context ) {
+ if ( null == mInstance ) {
+ if ( null != context ) {
+ mInstance = new SoundManager ( context );
+ }
+ }
+ return mInstance;
+ }
+
+ public void playKeyDown() {
+ if ( mAudioManager == null ) {
+ updateRingerMode();
+ }
+ if ( !mSilentMode ) {
+ int sound = AudioManager.FX_KEYPRESS_STANDARD;
+ mAudioManager.playSoundEffect ( sound, FX_VOLUME );
+ }
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/Vibrator.java b/src/com/droidlogic/inputmethod/remote/Vibrator.java
new file mode 100644
index 0000000..4b852d5
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/Vibrator.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import android.util.Log;
+import android.os.IVibratorService;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+/**
+ * Class that operates the vibrator on the device.
+ * <p>
+ * If your process exits, any vibration you started with will stop.
+ * </p>
+ */
+public class Vibrator {
+ private static final String TAG = "Vibrator";
+
+ IVibratorService mService;
+ private final Binder mToken = new Binder();
+
+ /** @hide */
+ public Vibrator() {
+ mService = IVibratorService.Stub.asInterface (
+ ServiceManager.getService ( "vibrator" ) );
+ }
+
+ /**
+ * Check whether the hardware has a vibrator. Returns true if a vibrator
+ * exists, else false.
+ */
+ public boolean hasVibrator() {
+ if ( mService == null ) {
+ Log.w ( TAG, "Failed to vibrate; no vibrator service." );
+ return false;
+ }
+ try {
+ return mService.hasVibrator();
+ } catch ( RemoteException e ) {
+ }
+ return false;
+ }
+
+ /**
+ * Turn the vibrator on.
+ *
+ * @param milliseconds The number of milliseconds to vibrate.
+ */
+ public void vibrate ( long milliseconds ) {
+ if ( mService == null ) {
+ Log.w ( TAG, "Failed to vibrate; no vibrator service." );
+ return;
+ }
+ /*
+ try {
+ mService.vibrate(milliseconds, mToken);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to vibrate.", e);
+ }*/
+ }
+
+ /**
+ * Vibrate with a given pattern.
+ *
+ * <p>
+ * Pass in an array of ints that are the durations for which to turn on or off
+ * the vibrator in milliseconds. The first value indicates the number of milliseconds
+ * to wait before turning the vibrator on. The next value indicates the number of milliseconds
+ * for which to keep the vibrator on before turning it off. Subsequent values alternate
+ * between durations in milliseconds to turn the vibrator off or to turn the vibrator on.
+ * </p><p>
+ * To cause the pattern to repeat, pass the index into the pattern array at which
+ * to start the repeat, or -1 to disable repeating.
+ * </p>
+ *
+ * @param pattern an array of longs of times for which to turn the vibrator on or off.
+ * @param repeat the index into pattern at which to repeat, or -1 if
+ * you don't want to repeat.
+ */
+ public void vibrate ( long[] pattern, int repeat ) {
+ if ( mService == null ) {
+ Log.w ( TAG, "Failed to vibrate; no vibrator service." );
+ return;
+ }
+ // catch this here because the server will do nothing. pattern may
+ // not be null, let that be checked, because the server will drop it
+ // anyway
+ if ( repeat < pattern.length ) {
+ /*
+ try {
+ mService.vibratePattern(pattern, repeat, mToken);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to vibrate.", e);
+ }*/
+ } else {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Turn the vibrator off.
+ */
+ public void cancel() {
+ if ( mService == null ) {
+ return;
+ }
+ try {
+ mService.cancelVibrate ( mToken );
+ } catch ( RemoteException e ) {
+ Log.w ( TAG, "Failed to cancel vibration.", e );
+ }
+ }
+}
diff --git a/src/com/droidlogic/inputmethod/remote/XmlKeyboardLoader.java b/src/com/droidlogic/inputmethod/remote/XmlKeyboardLoader.java
new file mode 100644
index 0000000..f5446a6
--- a/dev/null
+++ b/src/com/droidlogic/inputmethod/remote/XmlKeyboardLoader.java
@@ -0,0 +1,810 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.droidlogic.inputmethod.remote;
+
+import com.droidlogic.inputmethod.remote.SoftKeyboard.KeyRow;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Class used to load a soft keyboard or a soft keyboard template from xml
+ * files.
+ */
+public class XmlKeyboardLoader {
+ /**
+ * The tag used to define an xml-based soft keyboard template.
+ */
+ private static final String XMLTAG_SKB_TEMPLATE = "skb_template";
+
+ /**
+ * The tag used to indicate the soft key type which is defined inside the
+ * {@link #XMLTAG_SKB_TEMPLATE} element in the xml file. file.
+ */
+ private static final String XMLTAG_KEYTYPE = "key_type";
+
+ /**
+ * The tag used to define a default key icon for enter/delete/space keys. It
+ * is defined inside the {@link #XMLTAG_SKB_TEMPLATE} element in the xml
+ * file.
+ */
+ private static final String XMLTAG_KEYICON = "key_icon";
+
+ /**
+ * Attribute tag of the left and right margin for a key. A key's width
+ * should be larger than double of this value. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_KEY_XMARGIN = "key_xmargin";
+
+ /**
+ * Attribute tag of the top and bottom margin for a key. A key's height
+ * should be larger than double of this value. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_KEY_YMARGIN = "key_ymargin";
+
+ /**
+ * Attribute tag of the keyboard background image. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_SKB_BG = "skb_bg";
+
+ /**
+ * Attribute tag of the balloon background image for key press. Defined
+ * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_BALLOON_BG = "balloon_bg";
+
+ /**
+ * Attribute tag of the popup balloon background image for key press or
+ * popup mini keyboard. Defined inside {@link #XMLTAG_SKB_TEMPLATE} and
+ * {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_POPUP_BG = "popup_bg";
+
+ /**
+ * Attribute tag of the color to draw key label. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_COLOR = "color";
+
+ /**
+ * Attribute tag of the color to draw key's highlighted label. Defined
+ * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_COLOR_HIGHLIGHT = "color_highlight";
+
+ /**
+ * Attribute tag of the color to draw key's label in the popup balloon.
+ * Defined inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_COLOR_BALLOON = "color_balloon";
+
+ /**
+ * Attribute tag of the id of {@link #XMLTAG_KEYTYPE} and
+ * {@link #XMLTAG_KEY}. Key types and keys defined in a soft keyboard
+ * template should have id, because a soft keyboard needs the id to refer to
+ * these default definitions. If a key defined in {@link #XMLTAG_KEYBOARD}
+ * does not id, that means the key is newly defined; if it has id (and only
+ * has id), the id is used to find the default definition from the soft
+ * keyboard template.
+ */
+ private static final String XMLATTR_ID = "id";
+
+ /**
+ * Attribute tag of the key background for a specified key type. Defined
+ * inside {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_KEYTYPE_BG = "bg";
+
+ /**
+ * Attribute tag of the key high-light background for a specified key type.
+ * Defined inside {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_KEYTYPE_HLBG = "hlbg";
+
+ /**
+ * Attribute tag of the starting x-position of an element. It can be defined
+ * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}.
+ * If not defined, 0 will be used. For a key defined in
+ * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to
+ * calculate its own position.
+ */
+ private static final String XMLATTR_START_POS_X = "start_pos_x";
+
+ /**
+ * Attribute tag of the starting y-position of an element. It can be defined
+ * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}.
+ * If not defined, 0 will be used. For a key defined in
+ * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to
+ * calculate its own position.
+ */
+ private static final String XMLATTR_START_POS_Y = "start_pos_y";
+
+ /**
+ * Attribute tag of a row's id. Defined {@link #XMLTAG_ROW}. If not defined,
+ * -1 will be used. Rows with id -1 will be enabled always, rows with same
+ * row id will be enabled when the id is the same to the activated id of the
+ * soft keyboard.
+ */
+ private static final String XMLATTR_ROW_ID = "row_id";
+
+ /** The tag used to indicate the keyboard element in the xml file. */
+ private static final String XMLTAG_KEYBOARD = "keyboard";
+
+ /** The tag used to indicate the row element in the xml file. */
+ private static final String XMLTAG_ROW = "row";
+
+ /** The tag used to indicate key-array element in the xml file. */
+ private static final String XMLTAG_KEYS = "keys";
+
+ /**
+ * The tag used to indicate a key element in the xml file. If the element is
+ * defined in a soft keyboard template, it should have an id. If it is
+ * defined in a soft keyboard, id is not required.
+ */
+ private static final String XMLTAG_KEY = "key";
+
+ /** The tag used to indicate a key's toggle element in the xml file. */
+ private static final String XMLTAG_TOGGLE_STATE = "toggle_state";
+
+ /**
+ * Attribute tag of the toggle state id for toggle key. Defined inside
+ * {@link #XMLTAG_TOGGLE_STATE}
+ */
+ private static final String XMLATTR_TOGGLE_STATE_ID = "state_id";
+
+ /** Attribute tag of key template for the soft keyboard. */
+ private static final String XMLATTR_SKB_TEMPLATE = "skb_template";
+
+ /**
+ * Attribute tag used to indicate whether this soft keyboard needs to be
+ * cached in memory for future use. {@link #DEFAULT_SKB_CACHE_FLAG}
+ * specifies the default value.
+ */
+ private static final String XMLATTR_SKB_CACHE_FLAG = "skb_cache_flag";
+
+ /**
+ * Attribute tag used to indicate whether this soft keyboard is sticky. A
+ * sticky soft keyboard will keep the current layout unless user makes a
+ * switch explicitly. A none sticky soft keyboard will automatically goes
+ * back to the previous keyboard after click a none-function key.
+ * {@link #DEFAULT_SKB_STICKY_FLAG} specifies the default value.
+ */
+ private static final String XMLATTR_SKB_STICKY_FLAG = "skb_sticky_flag";
+
+ /** Attribute tag to indicate whether it is a QWERTY soft keyboard. */
+ private static final String XMLATTR_QWERTY = "qwerty";
+
+ /**
+ * When the soft keyboard is a QWERTY one, this attribute tag to get the
+ * information that whether it is defined in upper case.
+ */
+ private static final String XMLATTR_QWERTY_UPPERCASE = "qwerty_uppercase";
+
+ /** Attribute tag of key type. */
+ private static final String XMLATTR_KEY_TYPE = "key_type";
+
+ /** Attribute tag of key width. */
+ private static final String XMLATTR_KEY_WIDTH = "width";
+
+ /** Attribute tag of key height. */
+ private static final String XMLATTR_KEY_HEIGHT = "height";
+
+ /** Attribute tag of the key's repeating ability. */
+ private static final String XMLATTR_KEY_REPEAT = "repeat";
+
+ /** Attribute tag of the key's behavior for balloon. */
+ private static final String XMLATTR_KEY_BALLOON = "balloon";
+
+ /** Attribute tag of the key splitter in a key array. */
+ private static final String XMLATTR_KEY_SPLITTER = "splitter";
+
+ /** Attribute tag of the key labels in a key array. */
+ private static final String XMLATTR_KEY_LABELS = "labels";
+
+ /** Attribute tag of the key codes in a key array. */
+ private static final String XMLATTR_KEY_CODES = "codes";
+
+ /** Attribute tag of the key label in a key. */
+ private static final String XMLATTR_KEY_LABEL = "label";
+
+ /** Attribute tag of the key code in a key. */
+ private static final String XMLATTR_KEY_CODE = "code";
+
+ /** Attribute tag of the key icon in a key. */
+ private static final String XMLATTR_KEY_ICON = "icon";
+
+ /** Attribute tag of the key's popup icon in a key. */
+ private static final String XMLATTR_KEY_ICON_POPUP = "icon_popup";
+
+ /** The id for a mini popup soft keyboard. */
+ private static final String XMLATTR_KEY_POPUP_SKBID = "popup_skb";
+
+ private static boolean DEFAULT_SKB_CACHE_FLAG = true;
+
+ private static boolean DEFAULT_SKB_STICKY_FLAG = true;
+
+ /**
+ * The key type id for invalid key type. It is also used to generate next
+ * valid key type id by adding 1.
+ */
+ private static final int KEYTYPE_ID_LAST = -1;
+
+ private Context mContext;
+
+ private Resources mResources;
+
+ /** The event type in parsing the xml file. */
+ private int mXmlEventType;
+
+ /**
+ * The current soft keyboard template used by the current soft keyboard
+ * under loading.
+ **/
+ private SkbTemplate mSkbTemplate;
+
+ /** The x position for the next key. */
+ float mKeyXPos;
+
+ /** The y position for the next key. */
+ float mKeyYPos;
+
+ /** The width of the keyboard to load. */
+ int mSkbWidth;
+
+ /** The height of the keyboard to load. */
+ int mSkbHeight;
+
+ /** Key margin in x-way. */
+ float mKeyXMargin = 0;
+
+ /** Key margin in y-way. */
+ float mKeyYMargin = 0;
+
+ /**
+ * Used to indicate whether next event has been fetched during processing
+ * the the current event.
+ */
+ boolean mNextEventFetched = false;
+
+ String mAttrTmp;
+
+ class KeyCommonAttributes {
+ XmlResourceParser mXrp;
+ int keyType;
+ float keyWidth;
+ float keyHeight;
+ boolean repeat;
+ boolean balloon;
+
+ KeyCommonAttributes ( XmlResourceParser xrp ) {
+ mXrp = xrp;
+ balloon = true;
+ }
+
+ // Make sure the default object is not null.
+ boolean getAttributes ( KeyCommonAttributes defAttr ) {
+ keyType = getInteger ( mXrp, XMLATTR_KEY_TYPE, defAttr.keyType );
+ keyWidth = getFloat ( mXrp, XMLATTR_KEY_WIDTH, defAttr.keyWidth );
+ keyHeight = getFloat ( mXrp, XMLATTR_KEY_HEIGHT, defAttr.keyHeight );
+ repeat = getBoolean ( mXrp, XMLATTR_KEY_REPEAT, defAttr.repeat );
+ balloon = getBoolean ( mXrp, XMLATTR_KEY_BALLOON, defAttr.balloon );
+ if ( keyType < 0 || keyWidth <= 0 || keyHeight <= 0 ) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ public XmlKeyboardLoader ( Context context ) {
+ mContext = context;
+ mResources = mContext.getResources();
+ }
+
+ public SkbTemplate loadSkbTemplate ( int resourceId ) {
+ if ( null == mContext || 0 == resourceId ) {
+ return null;
+ }
+ Resources r = mResources;
+ XmlResourceParser xrp = r.getXml ( resourceId );
+ KeyCommonAttributes attrDef = new KeyCommonAttributes ( xrp );
+ KeyCommonAttributes attrKey = new KeyCommonAttributes ( xrp );
+ mSkbTemplate = new SkbTemplate ( resourceId );
+ int lastKeyTypeId = KEYTYPE_ID_LAST;
+ int globalColor = 0;
+ int globalColorHl = 0;
+ int globalColorBalloon = 0;
+ try {
+ mXmlEventType = xrp.next();
+ while ( mXmlEventType != XmlResourceParser.END_DOCUMENT ) {
+ mNextEventFetched = false;
+ if ( mXmlEventType == XmlResourceParser.START_TAG ) {
+ String attribute = xrp.getName();
+ if ( XMLTAG_SKB_TEMPLATE.compareTo ( attribute ) == 0 ) {
+ Drawable skbBg = getDrawable ( xrp, XMLATTR_SKB_BG, null );
+ Drawable balloonBg = getDrawable ( xrp,
+ XMLATTR_BALLOON_BG, null );
+ Drawable popupBg = getDrawable ( xrp, XMLATTR_POPUP_BG,
+ null );
+ if ( null == skbBg || null == balloonBg
+ || null == popupBg ) {
+ return null;
+ }
+ mSkbTemplate.setBackgrounds ( skbBg, balloonBg, popupBg );
+ float xMargin = getFloat ( xrp, XMLATTR_KEY_XMARGIN, 0 );
+ float yMargin = getFloat ( xrp, XMLATTR_KEY_YMARGIN, 0 );
+ mSkbTemplate.setMargins ( xMargin, yMargin );
+ // Get default global colors.
+ globalColor = getColor ( xrp, XMLATTR_COLOR, 0 );
+ globalColorHl = getColor ( xrp, XMLATTR_COLOR_HIGHLIGHT,
+ 0xffffffff );
+ globalColorBalloon = getColor ( xrp,
+ XMLATTR_COLOR_BALLOON, 0xffffffff );
+ } else if ( XMLTAG_KEYTYPE.compareTo ( attribute ) == 0 ) {
+ int id = getInteger ( xrp, XMLATTR_ID, KEYTYPE_ID_LAST );
+ Drawable bg = getDrawable ( xrp, XMLATTR_KEYTYPE_BG, null );
+ Drawable hlBg = getDrawable ( xrp, XMLATTR_KEYTYPE_HLBG,
+ null );
+ int color = getColor ( xrp, XMLATTR_COLOR, globalColor );
+ int colorHl = getColor ( xrp, XMLATTR_COLOR_HIGHLIGHT,
+ globalColorHl );
+ int colorBalloon = getColor ( xrp, XMLATTR_COLOR_BALLOON,
+ globalColorBalloon );
+ if ( id != lastKeyTypeId + 1 ) {
+ return null;
+ }
+ SoftKeyType keyType = mSkbTemplate.createKeyType ( id,
+ bg, hlBg );
+ keyType.setColors ( color, colorHl, colorBalloon );
+ if ( !mSkbTemplate.addKeyType ( keyType ) ) {
+ return null;
+ }
+ lastKeyTypeId = id;
+ } else if ( XMLTAG_KEYICON.compareTo ( attribute ) == 0 ) {
+ int keyCode = getInteger ( xrp, XMLATTR_KEY_CODE, 0 );
+ Drawable icon = getDrawable ( xrp, XMLATTR_KEY_ICON, null );
+ Drawable iconPopup = getDrawable ( xrp,
+ XMLATTR_KEY_ICON_POPUP, null );
+ if ( null != icon && null != iconPopup ) {
+ mSkbTemplate.addDefaultKeyIcons ( keyCode, icon,
+ iconPopup );
+ }
+ } else if ( XMLTAG_KEY.compareTo ( attribute ) == 0 ) {
+ int keyId = this.getInteger ( xrp, XMLATTR_ID, -1 );
+ if ( -1 == keyId ) { return null; }
+ if ( !attrKey.getAttributes ( attrDef ) ) {
+ return null;
+ }
+ // Update the key position for the key.
+ mKeyXPos = getFloat ( xrp, XMLATTR_START_POS_X, 0 );
+ mKeyYPos = getFloat ( xrp, XMLATTR_START_POS_Y, 0 );
+ SoftKey softKey = getSoftKey ( xrp, attrKey );
+ if ( null == softKey ) { return null; }
+ mSkbTemplate.addDefaultKey ( keyId, softKey );
+ }
+ }
+ // Get the next tag.
+ if ( !mNextEventFetched ) { mXmlEventType = xrp.next(); }
+ }
+ xrp.close();
+ return mSkbTemplate;
+ } catch ( XmlPullParserException e ) {
+ // Log.e(TAG, "Ill-formatted keyboard template resource file");
+ } catch ( IOException e ) {
+ // Log.e(TAG, "Unable to keyboard template resource file");
+ }
+ return null;
+ }
+
+ public SoftKeyboard loadKeyboard ( int resourceId, int skbWidth, int skbHeight, boolean force ) {
+ if ( null == mContext ) { return null; }
+ Resources r = mResources;
+ SkbPool skbPool = SkbPool.getInstance();
+ XmlResourceParser xrp = mContext.getResources().getXml ( resourceId );
+ mSkbTemplate = null;
+ SoftKeyboard softKeyboard = null;
+ Drawable skbBg;
+ Drawable popupBg;
+ Drawable balloonBg;
+ SoftKey softKey = null;
+ KeyCommonAttributes attrDef = new KeyCommonAttributes ( xrp );
+ KeyCommonAttributes attrSkb = new KeyCommonAttributes ( xrp );
+ KeyCommonAttributes attrRow = new KeyCommonAttributes ( xrp );
+ KeyCommonAttributes attrKeys = new KeyCommonAttributes ( xrp );
+ KeyCommonAttributes attrKey = new KeyCommonAttributes ( xrp );
+ mKeyXPos = 0;
+ mKeyYPos = 0;
+ mSkbWidth = skbWidth;
+ mSkbHeight = skbHeight;
+ try {
+ mKeyXMargin = 0;
+ mKeyYMargin = 0;
+ mXmlEventType = xrp.next();
+ while ( mXmlEventType != XmlResourceParser.END_DOCUMENT ) {
+ mNextEventFetched = false;
+ if ( mXmlEventType == XmlResourceParser.START_TAG ) {
+ String attr = xrp.getName();
+ // 1. Is it the root element, "keyboard"?
+ if ( XMLTAG_KEYBOARD.compareTo ( attr ) == 0 ) {
+ // 1.1 Get the keyboard template id.
+ int skbTemplateId = xrp.getAttributeResourceValue ( null,
+ XMLATTR_SKB_TEMPLATE, 0 );
+ // 1.2 Try to get the template from pool. If it is not
+ // in, the pool will try to load it.
+ mSkbTemplate = skbPool.getSkbTemplate ( skbTemplateId,
+ mContext, force );
+ if ( null == mSkbTemplate
+ || !attrSkb.getAttributes ( attrDef ) ) {
+ return null;
+ }
+ boolean cacheFlag = getBoolean ( xrp,
+ XMLATTR_SKB_CACHE_FLAG, DEFAULT_SKB_CACHE_FLAG );
+ boolean stickyFlag = getBoolean ( xrp,
+ XMLATTR_SKB_STICKY_FLAG,
+ DEFAULT_SKB_STICKY_FLAG );
+ boolean isQwerty = getBoolean ( xrp, XMLATTR_QWERTY,
+ false );
+ boolean isQwertyUpperCase = getBoolean ( xrp,
+ XMLATTR_QWERTY_UPPERCASE, false );
+ softKeyboard = new SoftKeyboard ( resourceId,
+ mSkbTemplate, mSkbWidth, mSkbHeight );
+ softKeyboard.setFlags ( cacheFlag, stickyFlag, isQwerty,
+ isQwertyUpperCase );
+ mKeyXMargin = getFloat ( xrp, XMLATTR_KEY_XMARGIN,
+ mSkbTemplate.getXMargin() );
+ mKeyYMargin = getFloat ( xrp, XMLATTR_KEY_YMARGIN,
+ mSkbTemplate.getYMargin() );
+ skbBg = getDrawable ( xrp, XMLATTR_SKB_BG, null );
+ popupBg = getDrawable ( xrp, XMLATTR_POPUP_BG, null );
+ balloonBg = getDrawable ( xrp, XMLATTR_BALLOON_BG, null );
+ if ( null != skbBg ) {
+ softKeyboard.setSkbBackground ( skbBg );
+ }
+ if ( null != popupBg ) {
+ softKeyboard.setPopupBackground ( popupBg );
+ }
+ if ( null != balloonBg ) {
+ softKeyboard.setKeyBalloonBackground ( balloonBg );
+ }
+ softKeyboard.setKeyMargins ( mKeyXMargin, mKeyYMargin );
+ } else if ( XMLTAG_ROW.compareTo ( attr ) == 0 ) {
+ if ( !attrRow.getAttributes ( attrSkb ) ) {
+ return null;
+ }
+ // Get the starting positions for the row.
+ mKeyXPos = getFloat ( xrp, XMLATTR_START_POS_X, 0 );
+ mKeyYPos = getFloat ( xrp, XMLATTR_START_POS_Y, mKeyYPos );
+ int rowId = getInteger ( xrp, XMLATTR_ROW_ID,
+ KeyRow.ALWAYS_SHOW_ROW_ID );
+ softKeyboard.beginNewRow ( rowId, mKeyYPos );
+ } else if ( XMLTAG_KEYS.compareTo ( attr ) == 0 ) {
+ if ( null == softKeyboard ) { return null; }
+ if ( !attrKeys.getAttributes ( attrRow ) ) {
+ return null;
+ }
+ String splitter = xrp.getAttributeValue ( null,
+ XMLATTR_KEY_SPLITTER );
+ splitter = Pattern.quote ( splitter );
+ String labels = xrp.getAttributeValue ( null,
+ XMLATTR_KEY_LABELS );
+ String codes = xrp.getAttributeValue ( null,
+ XMLATTR_KEY_CODES );
+ if ( null == splitter || null == labels ) {
+ return null;
+ }
+ String labelArr[] = labels.split ( splitter );
+ String codeArr[] = null;
+ if ( null != codes ) {
+ codeArr = codes.split ( splitter );
+ if ( labelArr.length != codeArr.length ) {
+ return null;
+ }
+ }
+ for ( int i = 0; i < labelArr.length; i++ ) {
+ softKey = new SoftKey();
+ int keyCode = 0;
+ if ( null != codeArr ) {
+ keyCode = Integer.valueOf ( codeArr[i] );
+ }
+ softKey.setKeyAttribute ( keyCode, labelArr[i],
+ attrKeys.repeat, attrKeys.balloon );
+ softKey.setKeyType ( mSkbTemplate
+ .getKeyType ( attrKeys.keyType ), null, null );
+ float left, right, top, bottom;
+ left = mKeyXPos;
+ right = left + attrKeys.keyWidth;
+ top = mKeyYPos;
+ bottom = top + attrKeys.keyHeight;
+ if ( right - left < 2 * mKeyXMargin ) { return null; }
+ if ( bottom - top < 2 * mKeyYMargin ) { return null; }
+ softKey.setKeyDimensions ( left, top, right, bottom );
+ softKeyboard.addSoftKey ( softKey );
+ mKeyXPos = right;
+ if ( ( int ) mKeyXPos * mSkbWidth > mSkbWidth ) {
+ return null;
+ }
+ }
+ } else if ( XMLTAG_KEY.compareTo ( attr ) == 0 ) {
+ if ( null == softKeyboard ) {
+ return null;
+ }
+ if ( !attrKey.getAttributes ( attrRow ) ) {
+ return null;
+ }
+ int keyId = this.getInteger ( xrp, XMLATTR_ID, -1 );
+ if ( keyId >= 0 ) {
+ softKey = mSkbTemplate.getDefaultKey ( keyId );
+ } else {
+ softKey = getSoftKey ( xrp, attrKey );
+ }
+ if ( null == softKey ) { return null; }
+ // Update the position for next key.
+ mKeyXPos = softKey.mRightF;
+ if ( ( int ) mKeyXPos * mSkbWidth > mSkbWidth ) {
+ return null;
+ }
+ // If the current xml event type becomes a starting tag,
+ // it indicates that we have parsed too much to get
+ // toggling states, and we started a new row. In this
+ // case, the row starting position information should
+ // be updated.
+ if ( mXmlEventType == XmlResourceParser.START_TAG ) {
+ attr = xrp.getName();
+ if ( XMLTAG_ROW.compareTo ( attr ) == 0 ) {
+ mKeyYPos += attrRow.keyHeight;
+ if ( ( int ) mKeyYPos * mSkbHeight > mSkbHeight ) {
+ return null;
+ }
+ }
+ }
+ softKeyboard.addSoftKey ( softKey );
+ }
+ } else if ( mXmlEventType == XmlResourceParser.END_TAG ) {
+ String attr = xrp.getName();
+ if ( XMLTAG_ROW.compareTo ( attr ) == 0 ) {
+ mKeyYPos += attrRow.keyHeight;
+ if ( ( int ) mKeyYPos * mSkbHeight > mSkbHeight ) {
+ return null;
+ }
+ }
+ }
+ // Get the next tag.
+ if ( !mNextEventFetched ) { mXmlEventType = xrp.next(); }
+ }
+ xrp.close();
+ softKeyboard.setSkbCoreSize ( mSkbWidth, mSkbHeight );
+ return softKeyboard;
+ } catch ( XmlPullParserException e ) {
+ // Log.e(TAG, "Ill-formatted keybaord resource file");
+ } catch ( IOException e ) {
+ // Log.e(TAG, "Unable to read keyboard resource file");
+ }
+ return null;
+ }
+
+ // Caller makes sure xrp and r are valid.
+ private SoftKey getSoftKey ( XmlResourceParser xrp,
+ KeyCommonAttributes attrKey ) throws XmlPullParserException,
+ IOException {
+ int keyCode = getInteger ( xrp, XMLATTR_KEY_CODE, 0 );
+ String keyLabel = getString ( xrp, XMLATTR_KEY_LABEL, null );
+ Drawable keyIcon = getDrawable ( xrp, XMLATTR_KEY_ICON, null );
+ Drawable keyIconPopup = getDrawable ( xrp, XMLATTR_KEY_ICON_POPUP, null );
+ int popupSkbId = xrp.getAttributeResourceValue ( null,
+ XMLATTR_KEY_POPUP_SKBID, 0 );
+
+ if ( null == keyLabel && null == keyIcon ) {
+ keyIcon = mSkbTemplate.getDefaultKeyIcon ( keyCode );
+ keyIconPopup = mSkbTemplate.getDefaultKeyIconPopup ( keyCode );
+ if ( null == keyIcon || null == keyIconPopup ) { return null; }
+ }
+
+ // Dimension information must been initialized before
+ // getting toggle state, because mKeyYPos may be changed
+ // to next row when trying to get toggle state.
+ float left, right, top, bottom;
+ left = mKeyXPos;
+ right = left + attrKey.keyWidth;
+ top = mKeyYPos;
+ bottom = top + attrKey.keyHeight;
+
+ if ( right - left < 2 * mKeyXMargin ) { return null; }
+ if ( bottom - top < 2 * mKeyYMargin ) { return null; }
+
+ // Try to find if the next tag is
+ // {@link #XMLTAG_TOGGLE_STATE_OF_KEY}, if yes, try to
+ // create a toggle key.
+ boolean toggleKey = false;
+ mXmlEventType = xrp.next();
+ mNextEventFetched = true;
+
+ SoftKey softKey;
+ if ( mXmlEventType == XmlResourceParser.START_TAG ) {
+ mAttrTmp = xrp.getName();
+ if ( mAttrTmp.compareTo ( XMLTAG_TOGGLE_STATE ) == 0 ) {
+ toggleKey = true;
+ }
+ }
+ if ( toggleKey ) {
+ softKey = new SoftKeyToggle();
+ if ( ! ( ( SoftKeyToggle ) softKey ).setToggleStates ( getToggleStates (
+ attrKey, ( SoftKeyToggle ) softKey, keyCode ) ) ) {
+ return null;
+ }
+ } else {
+ softKey = new SoftKey();
+ }
+
+ // Set the normal state
+ softKey.setKeyAttribute ( keyCode, keyLabel, attrKey.repeat,
+ attrKey.balloon );
+ softKey.setPopupSkbId ( popupSkbId );
+ softKey.setKeyType ( mSkbTemplate.getKeyType ( attrKey.keyType ), keyIcon,
+ keyIconPopup );
+
+ softKey.setKeyDimensions ( left, top, right, bottom );
+ return softKey;
+ }
+
+ private SoftKeyToggle.ToggleState getToggleStates (
+ KeyCommonAttributes attrKey, SoftKeyToggle softKey, int defKeyCode )
+ throws XmlPullParserException, IOException {
+ XmlResourceParser xrp = attrKey.mXrp;
+ int stateId = getInteger ( xrp, XMLATTR_TOGGLE_STATE_ID, 0 );
+ if ( 0 == stateId ) { return null; }
+
+ String keyLabel = getString ( xrp, XMLATTR_KEY_LABEL, null );
+ int keyTypeId = getInteger ( xrp, XMLATTR_KEY_TYPE, KEYTYPE_ID_LAST );
+ int keyCode;
+ if ( null == keyLabel ) {
+ keyCode = getInteger ( xrp, XMLATTR_KEY_CODE, defKeyCode );
+ } else {
+ keyCode = getInteger ( xrp, XMLATTR_KEY_CODE, 0 );
+ }
+ Drawable icon = getDrawable ( xrp, XMLATTR_KEY_ICON, null );
+ Drawable iconPopup = getDrawable ( xrp, XMLATTR_KEY_ICON_POPUP, null );
+ if ( null == icon && null == keyLabel ) {
+ return null;
+ }
+ SoftKeyToggle.ToggleState rootState = softKey.createToggleState();
+ rootState.setStateId ( stateId );
+ rootState.mKeyType = null;
+ if ( KEYTYPE_ID_LAST != keyTypeId ) {
+ rootState.mKeyType = mSkbTemplate.getKeyType ( keyTypeId );
+ }
+ rootState.mKeyCode = keyCode;
+ rootState.mKeyIcon = icon;
+ rootState.mKeyIconPopup = iconPopup;
+ rootState.mKeyLabel = keyLabel;
+
+ boolean repeat = getBoolean ( xrp, XMLATTR_KEY_REPEAT, attrKey.repeat );
+ boolean balloon = getBoolean ( xrp, XMLATTR_KEY_BALLOON, attrKey.balloon );
+ rootState.setStateFlags ( repeat, balloon );
+
+ rootState.mNextState = null;
+
+ // If there is another toggle state.
+ mXmlEventType = xrp.next();
+ while ( mXmlEventType != XmlResourceParser.START_TAG
+ && mXmlEventType != XmlResourceParser.END_DOCUMENT ) {
+ mXmlEventType = xrp.next();
+ }
+ if ( mXmlEventType == XmlResourceParser.START_TAG ) {
+ String attr = xrp.getName();
+ if ( attr.compareTo ( XMLTAG_TOGGLE_STATE ) == 0 ) {
+ SoftKeyToggle.ToggleState nextState = getToggleStates ( attrKey,
+ softKey, defKeyCode );
+ if ( null == nextState ) { return null; }
+ rootState.mNextState = nextState;
+ }
+ }
+
+ return rootState;
+ }
+
+ private int getInteger ( XmlResourceParser xrp, String name, int defValue ) {
+ int resId = xrp.getAttributeResourceValue ( null, name, 0 );
+ String s;
+ if ( resId == 0 ) {
+ s = xrp.getAttributeValue ( null, name );
+ if ( null == s ) { return defValue; }
+ try {
+ int ret = Integer.valueOf ( s );
+ return ret;
+ } catch ( NumberFormatException e ) {
+ return defValue;
+ }
+ } else {
+ return Integer.parseInt ( mContext.getResources().getString ( resId ) );
+ }
+ }
+
+ private int getColor ( XmlResourceParser xrp, String name, int defValue ) {
+ int resId = xrp.getAttributeResourceValue ( null, name, 0 );
+ String s;
+ if ( resId == 0 ) {
+ s = xrp.getAttributeValue ( null, name );
+ if ( null == s ) { return defValue; }
+ try {
+ int ret = Integer.valueOf ( s );
+ return ret;
+ } catch ( NumberFormatException e ) {
+ return defValue;
+ }
+ } else {
+ return mContext.getResources().getColor ( resId );
+ }
+ }
+
+ private String getString ( XmlResourceParser xrp, String name, String defValue ) {
+ int resId = xrp.getAttributeResourceValue ( null, name, 0 );
+ if ( resId == 0 ) {
+ return xrp.getAttributeValue ( null, name );
+ } else {
+ return mContext.getResources().getString ( resId );
+ }
+ }
+
+ private float getFloat ( XmlResourceParser xrp, String name, float defValue ) {
+ int resId = xrp.getAttributeResourceValue ( null, name, 0 );
+ if ( resId == 0 ) {
+ String s = xrp.getAttributeValue ( null, name );
+ if ( null == s ) { return defValue; }
+ try {
+ float ret;
+ if ( s.endsWith ( "%p" ) ) {
+ ret = Float.parseFloat ( s.substring ( 0, s.length() - 2 ) ) / 100;
+ } else {
+ ret = Float.parseFloat ( s );
+ }
+ return ret;
+ } catch ( NumberFormatException e ) {
+ return defValue;
+ }
+ } else {
+ return mContext.getResources().getDimension ( resId );
+ }
+ }
+
+ private boolean getBoolean ( XmlResourceParser xrp, String name,
+ boolean defValue ) {
+ String s = xrp.getAttributeValue ( null, name );
+ if ( null == s ) { return defValue; }
+ try {
+ boolean ret = Boolean.parseBoolean ( s );
+ return ret;
+ } catch ( NumberFormatException e ) {
+ return defValue;
+ }
+ }
+
+ private Drawable getDrawable ( XmlResourceParser xrp, String name,
+ Drawable defValue ) {
+ int resId = xrp.getAttributeResourceValue ( null, name, 0 );
+ if ( 0 == resId ) { return defValue; }
+ return mResources.getDrawable ( resId );
+ }
+}