aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java31
-rw-r--r--java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java10
-rw-r--r--java/src/com/android/inputmethod/latin/StringUtils.java31
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java6
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java2
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java11
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java16
-rw-r--r--java/src/com/android/inputmethod/research/Statistics.java18
-rw-r--r--native/jni/src/additional_proximity_chars.h4
-rw-r--r--native/jni/src/proximity_info.cpp108
-rw-r--r--native/jni/src/proximity_info.h25
-rw-r--r--native/jni/src/proximity_info_state.cpp28
-rw-r--r--native/jni/src/proximity_info_state.h12
-rw-r--r--native/jni/src/proximity_info_utils.h192
14 files changed, 330 insertions, 164 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d02c4df7e..f4b7a1708 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -773,7 +773,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// to the user dictionary.
if (null != mPositionalInfoForUserDictPendingAddition
&& mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord(
- mConnection, editorInfo, mLastSelectionEnd)) {
+ mConnection, editorInfo, mLastSelectionEnd,
+ mSubtypeSwitcher.getCurrentSubtypeLocale())) {
mPositionalInfoForUserDictPendingAddition = null;
}
// If tryReplaceWithActualWord returns false, we don't know what word was
@@ -1223,11 +1224,17 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mPositionalInfoForUserDictPendingAddition = null;
return;
}
+ final String wordToEdit;
+ if (StringUtils.isAutoCapsMode(mLastComposedWord.mCapitalizedMode)) {
+ wordToEdit = word.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale());
+ } else {
+ wordToEdit = word;
+ }
mPositionalInfoForUserDictPendingAddition =
new PositionalInfoForUserDictPendingAddition(
- word, mLastSelectionEnd, getCurrentInputEditorInfo(),
+ wordToEdit, mLastSelectionEnd, getCurrentInputEditorInfo(),
mLastComposedWord.mCapitalizedMode);
- mUserDictionary.addWordToUserDictionary(word, 128);
+ mUserDictionary.addWordToUserDictionary(wordToEdit);
}
public void onWordAddedToUserDictionary(final String newSpelling) {
@@ -1240,7 +1247,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mPositionalInfoForUserDictPendingAddition.setActualWordBeingAdded(newSpelling);
if (mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord(
- mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd)) {
+ mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd,
+ mSubtypeSwitcher.getCurrentSubtypeLocale())) {
mPositionalInfoForUserDictPendingAddition = null;
}
}
@@ -1476,7 +1484,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer);
}
}
- if (mWordComposer.size() <= 1) {
+ final int wordComposerSize = mWordComposer.size();
+ // Since isComposingWord() is true, the size is at least 1.
+ final int lastChar = mWordComposer.getCodeAt(wordComposerSize - 1);
+ if (wordComposerSize <= 1) {
// We auto-correct the previous (typed, not gestured) string iff it's one character
// long. The reason for this is, even in the middle of gesture typing, you'll still
// tap one-letter words and you want them auto-corrected (typically, "i" in English
@@ -1490,8 +1501,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mExpectingUpdateSelection = true;
// The following is necessary for the case where the user typed something but didn't
- // manual pick it and didn't input any separator.
- mSpaceState = SPACE_STATE_PHANTOM;
+ // manual pick it and didn't input any separator: we want to put a space between what
+ // has been entered and the coming gesture input result, so we go into phantom space
+ // state, which will be promoted to a space when the gesture result is committed. But if
+ // the current input ends in a word connector on the other hand, then we want to have
+ // the next input stick to the current input so we don't switch to phantom space state.
+ if (!mSettings.getCurrent().isWordConnector(lastChar)) {
+ mSpaceState = SPACE_STATE_PHANTOM;
+ }
} else {
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
if (mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) {
diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
index a33cefcd6..8493ef669 100644
--- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
+++ b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
@@ -18,6 +18,8 @@ package com.android.inputmethod.latin;
import android.view.inputmethod.EditorInfo;
+import java.util.Locale;
+
/**
* Holder class for data about a word already committed but that may still be edited.
*
@@ -70,10 +72,11 @@ public final class PositionalInfoForUserDictPendingAddition {
* @param connection The RichInputConnection through which to contact the editor.
* @param editorInfo Information pertaining to the editor we are currently in.
* @param currentCursorPosition The current cursor position, for checking purposes.
+ * @param locale The locale for changing case, if necessary
* @return true if the edit has been successfully made, false if we need to try again later
*/
public boolean tryReplaceWithActualWord(final RichInputConnection connection,
- final EditorInfo editorInfo, final int currentCursorPosition) {
+ final EditorInfo editorInfo, final int currentCursorPosition, final Locale locale) {
// If we still don't know the actual word being added, we need to try again later.
if (null == mActualWordBeingAdded) return false;
// The entered text and the registered text were the same anyway : we can
@@ -92,9 +95,12 @@ public final class PositionalInfoForUserDictPendingAddition {
// so that it won't be tried again
if (currentCursorPosition != mCursorPos) return true;
// We have made all the checks : do the replacement and report success
+ // If this was auto-capitalized, we need to restore the case before committing
+ final String wordWithCaseFixed = StringUtils.applyAutoCapsMode(mActualWordBeingAdded,
+ mCapitalizedMode, locale);
connection.setComposingRegion(currentCursorPosition - mOriginalWord.length(),
currentCursorPosition);
- connection.commitText(mActualWordBeingAdded, mActualWordBeingAdded.length());
+ connection.commitText(wordWithCaseFixed, wordWithCaseFixed.length());
return true;
}
}
diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java
index ddaa5ff5b..d00edbe92 100644
--- a/java/src/com/android/inputmethod/latin/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/StringUtils.java
@@ -103,6 +103,37 @@ public final class StringUtils {
}
}
+ /**
+ * Apply an auto-caps mode to a string.
+ *
+ * This intentionally does NOT apply manual caps mode. It only changes the capitalization if
+ * the mode is one of the auto-caps modes.
+ * @param s The string to capitalize.
+ * @param capitalizeMode The mode in which to capitalize.
+ * @param locale The locale for capitalizing.
+ * @return The capitalized string.
+ */
+ public static String applyAutoCapsMode(final String s, final int capitalizeMode,
+ final Locale locale) {
+ if (WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == capitalizeMode) {
+ return s.toUpperCase(locale);
+ } else if (WordComposer.CAPS_MODE_AUTO_SHIFTED == capitalizeMode) {
+ return toTitleCase(s, locale);
+ } else {
+ return s;
+ }
+ }
+
+ /**
+ * Return whether a constant represents an auto-caps mode (either auto-shift or auto-shift-lock)
+ * @param mode The mode to test for
+ * @return true if this represents an auto-caps mode, false otherwise
+ */
+ public static boolean isAutoCapsMode(final int mode) {
+ return WordComposer.CAPS_MODE_AUTO_SHIFTED == mode
+ || WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == mode;
+ }
+
public static String toTitleCase(final String s, final Locale locale) {
if (s.length() <= 1) {
// TODO: is this really correct? Shouldn't this be s.toUpperCase()?
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index a16784985..0d5bde623 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -216,17 +216,13 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
*
* @param word the word to add. If the word is capitalized, then the dictionary will
* recognize it as a capitalized word when searched.
- * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered
- * the highest.
- * @TODO use a higher or float range for frequency
*/
- public synchronized void addWordToUserDictionary(final String word, final int frequency) {
+ public synchronized void addWordToUserDictionary(final String word) {
// TODO: do something for the UI. With the following, any sufficiently long word will
// look like it will go to the user dictionary but it won't.
// Safeguard against adding long words. Can cause stack overflow.
if (word.length() >= MAX_WORD_LENGTH) return;
- // TODO: Add an argument to the intent to specify the frequency.
Intent intent = new Intent(ACTION_USER_DICTIONARY_INSERT);
intent.putExtra(Words.WORD, word);
intent.putExtra(Words.LOCALE, mLocale);
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index b9ec4979d..01629fefa 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -360,8 +360,10 @@ public final class WordComposer {
mDigitsCount = 0;
mIsBatchMode = false;
mTypedWord.setLength(0);
+ mCodePointSize = 0;
mTrailingSingleQuotesCount = 0;
mIsFirstCharCapitalized = false;
+ mCapitalizedMode = CAPS_MODE_OFF;
refreshSize();
mAutoCorrection = null;
mIsResumed = false;
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index cfba28909..70bbf9dc0 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -60,6 +60,7 @@ import java.util.Map;
private String mWord;
private boolean mMayContainDigit;
private boolean mIsPartOfMegaword;
+ private boolean mContainsCorrection;
public LogUnit() {
mLogStatementList = new ArrayList<LogStatement>();
@@ -274,6 +275,14 @@ import java.util.Map;
return mMayContainDigit;
}
+ public void setContainsCorrection() {
+ mContainsCorrection = true;
+ }
+
+ public boolean containsCorrection() {
+ return mContainsCorrection;
+ }
+
public boolean isEmpty() {
return mLogStatementList.isEmpty();
}
@@ -301,6 +310,7 @@ import java.util.Map;
true /* isPartOfMegaword */);
newLogUnit.mWord = null;
newLogUnit.mMayContainDigit = mMayContainDigit;
+ newLogUnit.mContainsCorrection = mContainsCorrection;
// Purge the logStatements and associated data from this LogUnit.
laterLogStatements.clear();
@@ -320,6 +330,7 @@ import java.util.Map;
mTimeList.addAll(logUnit.mTimeList);
mWord = null;
mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit;
+ mContainsCorrection = mContainsCorrection || logUnit.mContainsCorrection;
mIsPartOfMegaword = false;
}
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index a2bcf4441..a46216c5e 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -720,6 +720,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mCurrentLogUnit.setMayContainDigit();
}
+ private void setCurrentLogUnitContainsCorrection() {
+ mCurrentLogUnit.setContainsCorrection();
+ }
+
/* package for test */ void commitCurrentLogUnit() {
if (DEBUG) {
Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ?
@@ -850,7 +854,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mCurrentLogUnit.setWord(word);
final boolean isDictionaryWord = dictionary != null
&& dictionary.isValidWord(word);
- mStatistics.recordWordEntered(isDictionaryWord);
+ mStatistics.recordWordEntered(isDictionaryWord, mCurrentLogUnit.containsCorrection());
}
final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime);
enqueueCommitText(word, isBatchMode);
@@ -1181,6 +1185,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
scrubDigitsFromString(replacedWord), index,
suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE,
Constants.SUGGESTION_STRIP_COORDINATE);
+ researchLogger.setCurrentLogUnitContainsCorrection();
researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode);
researchLogger.mStatistics.recordManualSuggestion(SystemClock.uptimeMillis());
}
@@ -1340,6 +1345,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit,
LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord,
separatorString);
+ if (logUnit != null) {
+ logUnit.setContainsCorrection();
+ }
researchLogger.mStatistics.recordRevertCommit(SystemClock.uptimeMillis());
researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE, isBatchMode);
}
@@ -1500,6 +1508,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
final String scrubbedWord = scrubDigitsFromString(committedWord);
researchLogger.enqueueEvent(LOGSTATEMENT_COMMIT_PARTIAL_TEXT);
+ researchLogger.mStatistics.recordAutoCorrection(SystemClock.uptimeMillis());
researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData,
isBatchMode);
}
@@ -1740,7 +1749,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
"averageTimeDuringRepeatedDelete", "averageTimeAfterDelete",
"dictionaryWordCount", "splitWordsCount", "gestureInputCount",
"gestureCharsCount", "gesturesDeletedCount", "manualSuggestionsCount",
- "revertCommitsCount");
+ "revertCommitsCount", "correctedWordsCount", "autoCorrectionsCount");
private static void logStatistics() {
final ResearchLogger researchLogger = getInstance();
final Statistics statistics = researchLogger.mStatistics;
@@ -1754,6 +1763,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
statistics.mDictionaryWordCount, statistics.mSplitWordsCount,
statistics.mGesturesInputCount, statistics.mGesturesCharsCount,
statistics.mGesturesDeletedCount, statistics.mManualSuggestionsCount,
- statistics.mRevertCommitsCount);
+ statistics.mRevertCommitsCount, statistics.mCorrectedWordsCount,
+ statistics.mAutoCorrectionsCount);
}
}
diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java
index a9202651e..f0cb1578c 100644
--- a/java/src/com/android/inputmethod/research/Statistics.java
+++ b/java/src/com/android/inputmethod/research/Statistics.java
@@ -25,6 +25,7 @@ public class Statistics {
private static final String TAG = Statistics.class.getSimpleName();
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
+ // TODO: Cleanup comments to only including those giving meaningful information.
// Number of characters entered during a typing session
int mCharCount;
// Number of letter characters entered during a typing session
@@ -41,6 +42,8 @@ public class Statistics {
int mDictionaryWordCount;
// Number of words split and spaces automatically entered.
int mSplitWordsCount;
+ // Number of words entered during a session.
+ int mCorrectedWordsCount;
// Number of gestures that were input.
int mGesturesInputCount;
// Number of gestures that were deleted.
@@ -49,6 +52,8 @@ public class Statistics {
int mGesturesCharsCount;
// Number of manual suggestions chosen.
int mManualSuggestionsCount;
+ // Number of times that autocorrection was invoked.
+ int mAutoCorrectionsCount;
// Number of times a commit was reverted in this session.
int mRevertCommitsCount;
// Whether the text field was empty upon editing
@@ -113,10 +118,12 @@ public class Statistics {
mWordCount = 0;
mDictionaryWordCount = 0;
mSplitWordsCount = 0;
+ mCorrectedWordsCount = 0;
mGesturesInputCount = 0;
mGesturesDeletedCount = 0;
mManualSuggestionsCount = 0;
mRevertCommitsCount = 0;
+ mAutoCorrectionsCount = 0;
mIsEmptyUponStarting = true;
mIsEmptinessStateKnown = false;
mKeyCounter.reset();
@@ -152,11 +159,15 @@ public class Statistics {
}
}
- public void recordWordEntered(final boolean isDictionaryWord) {
+ public void recordWordEntered(final boolean isDictionaryWord,
+ final boolean containsCorrection) {
mWordCount++;
if (isDictionaryWord) {
mDictionaryWordCount++;
}
+ if (containsCorrection) {
+ mCorrectedWordsCount++;
+ }
}
public void recordSplitWords() {
@@ -184,6 +195,11 @@ public class Statistics {
recordUserAction(time, false /* isDeletion */);
}
+ public void recordAutoCorrection(final long time) {
+ mAutoCorrectionsCount++;
+ recordUserAction(time, false /* isDeletion */);
+ }
+
public void recordRevertCommit(final long time) {
mRevertCommitsCount++;
recordUserAction(time, true /* isDeletion */);
diff --git a/native/jni/src/additional_proximity_chars.h b/native/jni/src/additional_proximity_chars.h
index 21eb0bf8d..a88fd6cea 100644
--- a/native/jni/src/additional_proximity_chars.h
+++ b/native/jni/src/additional_proximity_chars.h
@@ -45,7 +45,7 @@ class AdditionalProximityChars {
}
public:
- static int getAdditionalCharsSize(const char *localeStr, const int c) {
+ static int getAdditionalCharsSize(const char *const localeStr, const int c) {
if (!isEnLocale(localeStr)) {
return 0;
}
@@ -65,7 +65,7 @@ class AdditionalProximityChars {
}
}
- static const int *getAdditionalChars(const char *localeStr, const int c) {
+ static const int *getAdditionalChars(const char *const localeStr, const int c) {
if (!isEnLocale(localeStr)) {
return 0;
}
diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp
index 9b99554d6..08646afa2 100644
--- a/native/jni/src/proximity_info.cpp
+++ b/native/jni/src/proximity_info.cpp
@@ -94,11 +94,6 @@ ProximityInfo::~ProximityInfo() {
delete[] mProximityCharsArray;
}
-inline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) const {
- return ((y / CELL_HEIGHT) * GRID_WIDTH + (x / CELL_WIDTH))
- * MAX_PROXIMITY_CHARS_SIZE;
-}
-
bool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
if (x < 0 || y < 0) {
if (DEBUG_DICT) {
@@ -109,7 +104,8 @@ bool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
return false;
}
- const int startIndex = getStartIndexFromCoordinates(x, y);
+ const int startIndex = ProximityInfoUtils::getStartIndexFromCoordinates(
+ MAX_PROXIMITY_CHARS_SIZE, x, y, CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH);
if (DEBUG_PROXIMITY_INFO) {
AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y);
}
@@ -147,100 +143,6 @@ float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
return getSquaredDistanceFloat(centerX, centerY, touchX, touchY) / SQUARE_FLOAT(keyWidth);
}
-int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) const {
- if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case
- const int left = mKeyXCoordinates[keyId];
- const int top = mKeyYCoordinates[keyId];
- const int right = left + mKeyWidths[keyId];
- const int bottom = top + mKeyHeights[keyId];
- const int edgeX = x < left ? left : (x > right ? right : x);
- const int edgeY = y < top ? top : (y > bottom ? bottom : y);
- const int dx = x - edgeX;
- const int dy = y - edgeY;
- return dx * dx + dy * dy;
-}
-
-void ProximityInfo::calculateNearbyKeyCodes(
- const int x, const int y, const int primaryKey, int *inputCodes) const {
- int *proximityCharsArray = mProximityCharsArray;
- int insertPos = 0;
- inputCodes[insertPos++] = primaryKey;
- const int startIndex = getStartIndexFromCoordinates(x, y);
- if (startIndex >= 0) {
- for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
- const int c = proximityCharsArray[startIndex + i];
- if (c < KEYCODE_SPACE || c == primaryKey) {
- continue;
- }
- const int keyIndex = getKeyIndexOf(c);
- const bool onKey = isOnKey(keyIndex, x, y);
- const int distance = squaredDistanceToEdge(keyIndex, x, y);
- if (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE) {
- inputCodes[insertPos++] = c;
- if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
- if (DEBUG_DICT) {
- ASSERT(false);
- }
- return;
- }
- }
- }
- const int additionalProximitySize =
- AdditionalProximityChars::getAdditionalCharsSize(mLocaleStr, primaryKey);
- if (additionalProximitySize > 0) {
- inputCodes[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
- if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
- if (DEBUG_DICT) {
- ASSERT(false);
- }
- return;
- }
-
- const int *additionalProximityChars =
- AdditionalProximityChars::getAdditionalChars(mLocaleStr, primaryKey);
- for (int j = 0; j < additionalProximitySize; ++j) {
- const int ac = additionalProximityChars[j];
- int k = 0;
- for (; k < insertPos; ++k) {
- if (ac == inputCodes[k]) {
- break;
- }
- }
- if (k < insertPos) {
- continue;
- }
- inputCodes[insertPos++] = ac;
- if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
- if (DEBUG_DICT) {
- ASSERT(false);
- }
- return;
- }
- }
- }
- }
- // Add a delimiter for the proximity characters
- for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
- inputCodes[i] = NOT_A_CODE_POINT;
- }
-}
-
-int ProximityInfo::getKeyIndexOf(const int c) const {
- if (KEY_COUNT == 0) {
- // We do not have the coordinate data
- return NOT_AN_INDEX;
- }
- if (c == NOT_A_CODE_POINT) {
- return NOT_AN_INDEX;
- }
- const int lowerCode = toLowerCase(c);
- hash_map_compat<int, int>::const_iterator mapPos = mCodeToKeyMap.find(lowerCode);
- if (mapPos != mCodeToKeyMap.end()) {
- return mapPos->second;
- }
- return NOT_AN_INDEX;
-}
-
int ProximityInfo::getCodePointOf(const int keyIndex) const {
if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
return NOT_A_CODE_POINT;
@@ -269,11 +171,13 @@ void ProximityInfo::initializeG() {
}
int ProximityInfo::getKeyCenterXOfCodePointG(int charCode) const {
- return getKeyCenterXOfKeyIdG(getKeyIndexOf(charCode));
+ return getKeyCenterXOfKeyIdG(
+ ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap));
}
int ProximityInfo::getKeyCenterYOfCodePointG(int charCode) const {
- return getKeyCenterYOfKeyIdG(getKeyIndexOf(charCode));
+ return getKeyCenterYOfKeyIdG(
+ ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap));
}
int ProximityInfo::getKeyCenterXOfKeyIdG(int keyId) const {
diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h
index d00228359..6be42a057 100644
--- a/native/jni/src/proximity_info.h
+++ b/native/jni/src/proximity_info.h
@@ -20,6 +20,7 @@
#include "defines.h"
#include "hash_map_compat.h"
#include "jni.h"
+#include "proximity_info_utils.h"
namespace latinime {
@@ -40,7 +41,6 @@ class ProximityInfo {
float getNormalizedSquaredDistanceFromCenterFloatG(
const int keyId, const int x, const int y) const;
bool sameAsTyped(const unsigned short *word, int length) const;
- int getKeyIndexOf(const int c) const;
int getCodePointOf(const int keyIndex) const;
bool hasSweetSpotData(const int keyIndex) const {
// When there are no calibration data for a key,
@@ -109,23 +109,26 @@ class ProximityInfo {
int getKeyCenterYOfKeyIdG(int keyId) const;
int getKeyKeyDistanceG(int keyId0, int keyId1) const;
+ void initializeProximities(const int *const inputCodes, const int *const inputXCoordinates,
+ const int *const inputYCoordinates, const int inputSize, int *allInputCodes) const {
+ ProximityInfoUtils::initializeProximities(inputCodes, inputXCoordinates, inputYCoordinates,
+ inputSize, mKeyXCoordinates, mKeyYCoordinates, mKeyWidths, mKeyHeights,
+ mProximityCharsArray, MAX_PROXIMITY_CHARS_SIZE, CELL_HEIGHT, CELL_WIDTH,
+ GRID_WIDTH, MOST_COMMON_KEY_WIDTH, KEY_COUNT, mLocaleStr, &mCodeToKeyMap,
+ allInputCodes);
+ }
+
+ int getKeyIndexOf(const int c) const {
+ return ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, c, &mCodeToKeyMap);
+ }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfo);
static const float NOT_A_DISTANCE_FLOAT;
- int getStartIndexFromCoordinates(const int x, const int y) const;
void initializeG();
float calculateNormalizedSquaredDistance(const int keyIndex, const int inputIndex) const;
bool hasInputCoordinates() const;
- int squaredDistanceToEdge(const int keyId, const int x, const int y) const;
- bool isOnKey(const int keyId, const int x, const int y) const {
- if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case
- const int left = mKeyXCoordinates[keyId];
- const int top = mKeyYCoordinates[keyId];
- const int right = left + mKeyWidths[keyId] + 1;
- const int bottom = top + mKeyHeights[keyId];
- return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom;
- }
const int MAX_PROXIMITY_CHARS_SIZE;
const int GRID_WIDTH;
diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp
index aa029297e..1e1413a5d 100644
--- a/native/jni/src/proximity_info_state.cpp
+++ b/native/jni/src/proximity_info_state.cpp
@@ -53,33 +53,11 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
mGridHeight = proximityInfo->getGridWidth();
mGridWidth = proximityInfo->getGridHeight();
- memset(mInputCodes, 0, sizeof(mInputCodes));
+ memset(mInputProximities, 0, sizeof(mInputProximities));
if (!isGeometric && pointerId == 0) {
- // Initialize
- // - mInputCodes
- // - mNormalizedSquaredDistances
- // TODO: Merge
- for (int i = 0; i < inputSize; ++i) {
- const int primaryKey = inputCodes[i];
- const int x = xCoordinates[i];
- const int y = yCoordinates[i];
- int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL];
- mProximityInfo->calculateNearbyKeyCodes(x, y, primaryKey, proximities);
- }
-
- if (DEBUG_PROXIMITY_CHARS) {
- for (int i = 0; i < inputSize; ++i) {
- AKLOGI("---");
- for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) {
- int icc = mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j];
- int icfjc = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j];
- icc += 0;
- icfjc += 0;
- AKLOGI("--- (%d)%c,%c", i, icc, icfjc); AKLOGI("--- A<%d>,B<%d>", icc, icfjc);
- }
- }
- }
+ mProximityInfo->initializeProximities(inputCodes, xCoordinates, yCoordinates,
+ inputSize, mInputProximities);
}
///////////////////////
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index d747bae2a..bc2cf505c 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -61,7 +61,7 @@ class ProximityInfoState {
mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache_G(),
mSpeedRates(), mDirections(), mCharProbabilities(), mNearKeysVector(),
mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) {
- memset(mInputCodes, 0, sizeof(mInputCodes));
+ memset(mInputProximities, 0, sizeof(mInputProximities));
memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances));
memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord));
}
@@ -117,12 +117,12 @@ class ProximityInfoState {
if (length != mSampledInputSize) {
return false;
}
- const int *inputCodes = mInputCodes;
+ const int *inputProximities = mInputProximities;
while (length--) {
- if (*inputCodes != *word) {
+ if (*inputProximities != *word) {
return false;
}
- inputCodes += MAX_PROXIMITY_CHARS_SIZE_INTERNAL;
+ inputProximities += MAX_PROXIMITY_CHARS_SIZE_INTERNAL;
word++;
}
return true;
@@ -229,7 +229,7 @@ class ProximityInfoState {
}
inline const int *getProximityCodePointsAt(const int index) const {
- return mInputCodes + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL);
+ return mInputProximities + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL);
}
float updateNearKeysDistances(const int x, const int y,
@@ -289,7 +289,7 @@ class ProximityInfoState {
// inputs including the current input point.
std::vector<NearKeycodesSet> mSearchKeysVector;
bool mTouchPositionCorrectionEnabled;
- int mInputCodes[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH];
+ int mInputProximities[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH];
int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH];
int mSampledInputSize;
int mPrimaryInputWord[MAX_WORD_LENGTH];
diff --git a/native/jni/src/proximity_info_utils.h b/native/jni/src/proximity_info_utils.h
new file mode 100644
index 000000000..b9348d885
--- /dev/null
+++ b/native/jni/src/proximity_info_utils.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef LATINIME_PROXIMITY_INFO_UTILS_H
+#define LATINIME_PROXIMITY_INFO_UTILS_H
+
+#include "additional_proximity_chars.h"
+#include "char_utils.h"
+#include "defines.h"
+#include "hash_map_compat.h"
+
+namespace latinime {
+class ProximityInfoUtils {
+ public:
+ static int getKeyIndexOf(const int keyCount, const int c,
+ const hash_map_compat<int, int> *const codeToKeyMap) {
+ if (keyCount == 0) {
+ // We do not have the coordinate data
+ return NOT_AN_INDEX;
+ }
+ if (c == NOT_A_CODE_POINT) {
+ return NOT_AN_INDEX;
+ }
+ const int lowerCode = toLowerCase(c);
+ hash_map_compat<int, int>::const_iterator mapPos = codeToKeyMap->find(lowerCode);
+ if (mapPos != codeToKeyMap->end()) {
+ return mapPos->second;
+ }
+ return NOT_AN_INDEX;
+ }
+
+ static void initializeProximities(const int *const inputCodes,
+ const int *const inputXCoordinates, const int *const inputYCoordinates,
+ const int inputSize, const int *const keyXCoordinates,
+ const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
+ const int *const proximityCharsArray, const int maxProximityCharsSize,
+ const int cellHeight, const int cellWidth, const int gridWidth,
+ const int mostCommonKeyWidth, const int keyCount, const char *const localeStr,
+ const hash_map_compat<int, int> *const codeToKeyMap, int *inputProximities) {
+ // Initialize
+ // - mInputCodes
+ // - mNormalizedSquaredDistances
+ // TODO: Merge
+ for (int i = 0; i < inputSize; ++i) {
+ const int primaryKey = inputCodes[i];
+ const int x = inputXCoordinates[i];
+ const int y = inputYCoordinates[i];
+ int *proximities = &inputProximities[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL];
+ calculateProximities(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
+ proximityCharsArray, maxProximityCharsSize, cellHeight, cellWidth, gridWidth,
+ mostCommonKeyWidth, keyCount, x, y, primaryKey, localeStr, codeToKeyMap,
+ proximities);
+ }
+
+ if (DEBUG_PROXIMITY_CHARS) {
+ for (int i = 0; i < inputSize; ++i) {
+ AKLOGI("---");
+ for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) {
+ int proximityChar =
+ inputProximities[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j];
+ proximityChar += 0;
+ AKLOGI("--- (%d)%c", i, proximityChar);
+ }
+ }
+ }
+ }
+
+ AK_FORCE_INLINE static int getStartIndexFromCoordinates(const int maxProximityCharsSize,
+ const int x, const int y, const int cellHeight, const int cellWidth,
+ const int gridWidth) {
+ return ((y / cellHeight) * gridWidth + (x / cellWidth)) * maxProximityCharsSize;
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoUtils);
+
+ static bool isOnKey(const int *const keyXCoordinates, const int *const keyYCoordinates,
+ const int *const keyWidths, const int *keyHeights, const int keyId, const int x,
+ const int y) {
+ if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case
+ const int left = keyXCoordinates[keyId];
+ const int top = keyYCoordinates[keyId];
+ const int right = left + keyWidths[keyId] + 1;
+ const int bottom = top + keyHeights[keyId];
+ return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom;
+ }
+
+ static void calculateProximities(
+ const int *const keyXCoordinates, const int *const keyYCoordinates,
+ const int *const keyWidths, const int *keyHeights,
+ const int *const proximityCharsArray,
+ const int maxProximityCharsSize, const int cellHeight, const int cellWidth,
+ const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
+ const int x, const int y, const int primaryKey, const char *const localeStr,
+ const hash_map_compat<int, int> *const codeToKeyMap, int *proximities) {
+ const int mostCommonKeyWidthSquare = mostCommonKeyWidth * mostCommonKeyWidth;
+ int insertPos = 0;
+ proximities[insertPos++] = primaryKey;
+ const int startIndex = getStartIndexFromCoordinates(
+ maxProximityCharsSize, x, y, cellHeight, cellWidth, gridWidth);
+ if (startIndex >= 0) {
+ for (int i = 0; i < maxProximityCharsSize; ++i) {
+ const int c = proximityCharsArray[startIndex + i];
+ if (c < KEYCODE_SPACE || c == primaryKey) {
+ continue;
+ }
+ const int keyIndex = getKeyIndexOf(keyCount, c, codeToKeyMap);
+ const bool onKey = isOnKey(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
+ keyIndex, x, y);
+ const int distance = squaredLengthToEdge(keyXCoordinates, keyYCoordinates,
+ keyWidths, keyHeights, keyIndex, x, y);
+ if (onKey || distance < mostCommonKeyWidthSquare) {
+ proximities[insertPos++] = c;
+ if (insertPos >= maxProximityCharsSize) {
+ if (DEBUG_DICT) {
+ ASSERT(false);
+ }
+ return;
+ }
+ }
+ }
+ const int additionalProximitySize =
+ AdditionalProximityChars::getAdditionalCharsSize(localeStr, primaryKey);
+ if (additionalProximitySize > 0) {
+ proximities[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
+ if (insertPos >= maxProximityCharsSize) {
+ if (DEBUG_DICT) {
+ ASSERT(false);
+ }
+ return;
+ }
+
+ const int *additionalProximityChars =
+ AdditionalProximityChars::getAdditionalChars(localeStr, primaryKey);
+ for (int j = 0; j < additionalProximitySize; ++j) {
+ const int ac = additionalProximityChars[j];
+ int k = 0;
+ for (; k < insertPos; ++k) {
+ if (ac == proximities[k]) {
+ break;
+ }
+ }
+ if (k < insertPos) {
+ continue;
+ }
+ proximities[insertPos++] = ac;
+ if (insertPos >= maxProximityCharsSize) {
+ if (DEBUG_DICT) {
+ ASSERT(false);
+ }
+ return;
+ }
+ }
+ }
+ }
+ // Add a delimiter for the proximity characters
+ for (int i = insertPos; i < maxProximityCharsSize; ++i) {
+ proximities[i] = NOT_A_CODE_POINT;
+ }
+ }
+
+ static int squaredLengthToEdge(const int *const keyXCoordinates,
+ const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
+ const int keyId, const int x, const int y) {
+ // NOT_A_ID is -1, but return whenever < 0 just in case
+ if (keyId < 0) return MAX_POINT_TO_KEY_LENGTH;
+ const int left = keyXCoordinates[keyId];
+ const int top = keyYCoordinates[keyId];
+ const int right = left + keyWidths[keyId];
+ const int bottom = top + keyHeights[keyId];
+ const int edgeX = x < left ? left : (x > right ? right : x);
+ const int edgeY = y < top ? top : (y > bottom ? bottom : y);
+ const int dx = x - edgeX;
+ const int dy = y - edgeY;
+ return dx * dx + dy * dy;
+ }
+};
+} // namespace latinime
+#endif // LATINIME_PROXIMITY_INFO_UTILS_H