am e05b3f4b: Support additional proximity characters
* commit 'e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476c': Support additional proximity charactersmain
commit
d1ee49a939
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
**
|
||||||
|
** Copyright 2012, 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.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
|
||||||
|
<string-array name="additional_proximitychars">
|
||||||
|
<!-- Empty entry terminates the proximity chars array. -->
|
||||||
|
|
||||||
|
<!-- Additional proximity chars for a -->
|
||||||
|
<item>a</item>
|
||||||
|
<item>e</item>
|
||||||
|
<item>i</item>
|
||||||
|
<item>o</item>
|
||||||
|
<item>u</item>
|
||||||
|
<item></item>
|
||||||
|
<!-- Additional proximity chars for e -->
|
||||||
|
<item>e</item>
|
||||||
|
<item>a</item>
|
||||||
|
<item>i</item>
|
||||||
|
<item>o</item>
|
||||||
|
<item>u</item>
|
||||||
|
<item></item>
|
||||||
|
<!-- Additional proximity chars for i -->
|
||||||
|
<item>i</item>
|
||||||
|
<item>a</item>
|
||||||
|
<item>e</item>
|
||||||
|
<item>o</item>
|
||||||
|
<item>u</item>
|
||||||
|
<item></item>
|
||||||
|
<!-- Additional proximity chars for o -->
|
||||||
|
<item>o</item>
|
||||||
|
<item>a</item>
|
||||||
|
<item>e</item>
|
||||||
|
<item>i</item>
|
||||||
|
<item>u</item>
|
||||||
|
<item></item>
|
||||||
|
<!-- Additional proximity chars for u -->
|
||||||
|
<item>u</item>
|
||||||
|
<item>a</item>
|
||||||
|
<item>e</item>
|
||||||
|
<item>i</item>
|
||||||
|
<item>o</item>
|
||||||
|
<item></item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
**
|
||||||
|
** Copyright 2012, 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.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string-array name="additional_proximitychars">
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
|
@ -19,12 +19,14 @@ package com.android.inputmethod.keyboard;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class KeyDetector {
|
public class KeyDetector {
|
||||||
private static final String TAG = KeyDetector.class.getSimpleName();
|
private static final String TAG = KeyDetector.class.getSimpleName();
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
public static final int NOT_A_CODE = -1;
|
public static final int NOT_A_CODE = -1;
|
||||||
|
private static final int ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE = 2;
|
||||||
|
|
||||||
private final int mKeyHysteresisDistanceSquared;
|
private final int mKeyHysteresisDistanceSquared;
|
||||||
|
|
||||||
|
@ -154,8 +156,9 @@ public class KeyDetector {
|
||||||
return distances.length;
|
return distances.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getNearbyKeyCodes(final int[] allCodes) {
|
private void getNearbyKeyCodes(final int primaryCode, final int[] allCodes) {
|
||||||
final Key[] neighborKeys = mNeighborKeys;
|
final Key[] neighborKeys = mNeighborKeys;
|
||||||
|
final int maxCodesSize = allCodes.length;
|
||||||
|
|
||||||
// allCodes[0] should always have the key code even if it is a non-letter key.
|
// allCodes[0] should always have the key code even if it is a non-letter key.
|
||||||
if (neighborKeys[0] == null) {
|
if (neighborKeys[0] == null) {
|
||||||
|
@ -164,7 +167,7 @@ public class KeyDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
int numCodes = 0;
|
int numCodes = 0;
|
||||||
for (int j = 0; j < neighborKeys.length && numCodes < allCodes.length; j++) {
|
for (int j = 0; j < neighborKeys.length && numCodes < maxCodesSize; j++) {
|
||||||
final Key key = neighborKeys[j];
|
final Key key = neighborKeys[j];
|
||||||
if (key == null)
|
if (key == null)
|
||||||
break;
|
break;
|
||||||
|
@ -174,6 +177,38 @@ public class KeyDetector {
|
||||||
continue;
|
continue;
|
||||||
allCodes[numCodes++] = code;
|
allCodes[numCodes++] = code;
|
||||||
}
|
}
|
||||||
|
if (maxCodesSize <= numCodes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (primaryCode != NOT_A_CODE) {
|
||||||
|
final List<Integer> additionalChars =
|
||||||
|
mKeyboard.getAdditionalProximityChars().get(primaryCode);
|
||||||
|
if (additionalChars == null || additionalChars.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int currentCodesSize = numCodes;
|
||||||
|
allCodes[numCodes++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
|
||||||
|
if (maxCodesSize <= numCodes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: This is O(N^2). Assuming additionalChars.size() is up to 4 or 5.
|
||||||
|
for (int i = 0; i < additionalChars.size(); ++i) {
|
||||||
|
final int additionalChar = additionalChars.get(i);
|
||||||
|
boolean contains = false;
|
||||||
|
for (int j = 0; j < currentCodesSize; ++j) {
|
||||||
|
if (additionalChar == allCodes[j]) {
|
||||||
|
contains = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!contains) {
|
||||||
|
allCodes[numCodes++] = additionalChar;
|
||||||
|
if (maxCodesSize <= numCodes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,7 +240,7 @@ public class KeyDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allCodes != null && allCodes.length > 0) {
|
if (allCodes != null && allCodes.length > 0) {
|
||||||
getNearbyKeyCodes(allCodes);
|
getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "x=" + x + " y=" + y
|
Log.d(TAG, "x=" + x + " y=" + y
|
||||||
+ " primary=" + printableCode(primaryKey)
|
+ " primary=" + printableCode(primaryKey)
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.content.res.XmlResourceParser;
|
import android.content.res.XmlResourceParser;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -38,10 +39,12 @@ import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -130,6 +133,8 @@ public class Keyboard {
|
||||||
|
|
||||||
private final ProximityInfo mProximityInfo;
|
private final ProximityInfo mProximityInfo;
|
||||||
|
|
||||||
|
public final Map<Integer, List<Integer>> mAdditionalProximityChars;
|
||||||
|
|
||||||
public Keyboard(Params params) {
|
public Keyboard(Params params) {
|
||||||
mId = params.mId;
|
mId = params.mId;
|
||||||
mThemeId = params.mThemeId;
|
mThemeId = params.mThemeId;
|
||||||
|
@ -146,10 +151,12 @@ public class Keyboard {
|
||||||
mKeys = Collections.unmodifiableSet(params.mKeys);
|
mKeys = Collections.unmodifiableSet(params.mKeys);
|
||||||
mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys);
|
mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys);
|
||||||
mIconsSet = params.mIconsSet;
|
mIconsSet = params.mIconsSet;
|
||||||
|
mAdditionalProximityChars = params.mAdditionalProximityChars;
|
||||||
|
|
||||||
mProximityInfo = new ProximityInfo(
|
mProximityInfo = new ProximityInfo(
|
||||||
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
|
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
|
||||||
mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection);
|
mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection,
|
||||||
|
params.mAdditionalProximityChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProximityInfo getProximityInfo() {
|
public ProximityInfo getProximityInfo() {
|
||||||
|
@ -227,6 +234,9 @@ public class Keyboard {
|
||||||
public final Set<Key> mKeys = new HashSet<Key>();
|
public final Set<Key> mKeys = new HashSet<Key>();
|
||||||
public final Set<Key> mShiftKeys = new HashSet<Key>();
|
public final Set<Key> mShiftKeys = new HashSet<Key>();
|
||||||
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
|
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
|
||||||
|
// TODO: Should be in Key instead of Keyboard.Params?
|
||||||
|
public final Map<Integer, List<Integer>> mAdditionalProximityChars =
|
||||||
|
new HashMap<Integer, List<Integer>>();
|
||||||
|
|
||||||
public KeyboardSet.KeysCache mKeysCache;
|
public KeyboardSet.KeysCache mKeysCache;
|
||||||
|
|
||||||
|
@ -358,6 +368,10 @@ public class Keyboard {
|
||||||
return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
|
return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<Integer, List<Integer>> getAdditionalProximityChars() {
|
||||||
|
return mAdditionalProximityChars;
|
||||||
|
}
|
||||||
|
|
||||||
public static String printableCode(int code) {
|
public static String printableCode(int code) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case CODE_SHIFT: return "shift";
|
case CODE_SHIFT: return "shift";
|
||||||
|
@ -614,6 +628,7 @@ public class Keyboard {
|
||||||
mParams = params;
|
mParams = params;
|
||||||
|
|
||||||
setTouchPositionCorrectionData(context, params);
|
setTouchPositionCorrectionData(context, params);
|
||||||
|
setAdditionalProximityChars(context, params);
|
||||||
|
|
||||||
params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
|
params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
|
||||||
params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
|
params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
|
||||||
|
@ -636,6 +651,25 @@ public class Keyboard {
|
||||||
params.mTouchPositionCorrection.load(data);
|
params.mTouchPositionCorrection.load(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void setAdditionalProximityChars(Context context, Params params) {
|
||||||
|
final String[] additionalChars =
|
||||||
|
context.getResources().getStringArray(R.array.additional_proximitychars);
|
||||||
|
int currentPrimaryIndex = 0;
|
||||||
|
for (int i = 0; i < additionalChars.length; ++i) {
|
||||||
|
final String additionalChar = additionalChars[i];
|
||||||
|
if (TextUtils.isEmpty(additionalChar)) {
|
||||||
|
currentPrimaryIndex = 0;
|
||||||
|
} else if (currentPrimaryIndex == 0) {
|
||||||
|
currentPrimaryIndex = additionalChar.charAt(0);
|
||||||
|
params.mAdditionalProximityChars.put(
|
||||||
|
currentPrimaryIndex, new ArrayList<Integer>());
|
||||||
|
} else if (currentPrimaryIndex != 0) {
|
||||||
|
final int c = additionalChar.charAt(0);
|
||||||
|
params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setAutoGenerate(KeyboardSet.KeysCache keysCache) {
|
public void setAutoGenerate(KeyboardSet.KeysCache keysCache) {
|
||||||
mParams.mKeysCache = keysCache;
|
mParams.mKeysCache = keysCache;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@ import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ProximityInfo {
|
public class ProximityInfo {
|
||||||
|
@ -44,7 +47,8 @@ public class ProximityInfo {
|
||||||
private final Key[][] mGridNeighbors;
|
private final Key[][] mGridNeighbors;
|
||||||
|
|
||||||
ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth,
|
ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth,
|
||||||
int keyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection) {
|
int keyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection,
|
||||||
|
Map<Integer, List<Integer>> additionalProximityChars) {
|
||||||
mGridWidth = gridWidth;
|
mGridWidth = gridWidth;
|
||||||
mGridHeight = gridHeight;
|
mGridHeight = gridHeight;
|
||||||
mGridSize = mGridWidth * mGridHeight;
|
mGridSize = mGridWidth * mGridHeight;
|
||||||
|
@ -58,20 +62,20 @@ public class ProximityInfo {
|
||||||
// No proximity required. Keyboard might be mini keyboard.
|
// No proximity required. Keyboard might be mini keyboard.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
computeNearestNeighbors(keyWidth, keys, touchPositionCorrection);
|
computeNearestNeighbors(keyWidth, keys, touchPositionCorrection, additionalProximityChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProximityInfo createDummyProximityInfo() {
|
public static ProximityInfo createDummyProximityInfo() {
|
||||||
return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptySet(), null);
|
return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key> emptySet(),
|
||||||
|
null, Collections.<Integer, List<Integer>> emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) {
|
public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) {
|
||||||
final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo();
|
final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo();
|
||||||
spellCheckerProximityInfo.mNativeProximityInfo =
|
spellCheckerProximityInfo.mNativeProximityInfo =
|
||||||
spellCheckerProximityInfo.setProximityInfoNative(
|
spellCheckerProximityInfo.setProximityInfoNative(
|
||||||
SpellCheckerProximityInfo.ROW_SIZE,
|
SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 11, 3, proximity, 0,
|
||||||
480, 300, 11, 3, proximity,
|
null, null, null, null, null, null, null, null);
|
||||||
0, null, null, null, null, null, null, null, null);
|
|
||||||
return spellCheckerProximityInfo;
|
return spellCheckerProximityInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,11 +83,13 @@ public class ProximityInfo {
|
||||||
static {
|
static {
|
||||||
Utils.loadNativeLibrary();
|
Utils.loadNativeLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth,
|
private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth,
|
||||||
int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray,
|
int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray,
|
||||||
int keyCount, int[] keyXCoordinates, int[] keyYCoordinates,
|
int keyCount, int[] keyXCoordinates, int[] keyYCoordinates,
|
||||||
int[] keyWidths, int[] keyHeights, int[] keyCharCodes,
|
int[] keyWidths, int[] keyHeights, int[] keyCharCodes,
|
||||||
float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii);
|
float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii);
|
||||||
|
|
||||||
private native void releaseProximityInfoNative(long nativeProximityInfo);
|
private native void releaseProximityInfoNative(long nativeProximityInfo);
|
||||||
|
|
||||||
private final void setProximityInfo(Key[][] gridNeighborKeys, int keyboardWidth,
|
private final void setProximityInfo(Key[][] gridNeighborKeys, int keyboardWidth,
|
||||||
|
@ -138,7 +144,7 @@ public class ProximityInfo {
|
||||||
final float radius = touchPositionCorrection.mRadii[row];
|
final float radius = touchPositionCorrection.mRadii[row];
|
||||||
sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
|
sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
|
||||||
sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
|
sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
|
||||||
sweetSpotRadii[i] = radius * (float)Math.sqrt(
|
sweetSpotRadii[i] = radius * (float) Math.sqrt(
|
||||||
hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
|
hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +174,12 @@ public class ProximityInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void computeNearestNeighbors(int defaultWidth, Set<Key> keys,
|
private void computeNearestNeighbors(int defaultWidth, Set<Key> keys,
|
||||||
TouchPositionCorrection touchPositionCorrection) {
|
TouchPositionCorrection touchPositionCorrection,
|
||||||
|
Map<Integer, List<Integer>> additionalProximityChars) {
|
||||||
|
final Map<Integer, Key> keyCodeMap = new HashMap<Integer, Key>();
|
||||||
|
for (final Key key : keys) {
|
||||||
|
keyCodeMap.put(key.mCode, key);
|
||||||
|
}
|
||||||
final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE);
|
final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE);
|
||||||
final int threshold = thresholdBase * thresholdBase;
|
final int threshold = thresholdBase * thresholdBase;
|
||||||
// Round-up so we don't have any pixels outside the grid
|
// Round-up so we don't have any pixels outside the grid
|
||||||
|
@ -186,6 +197,27 @@ public class ProximityInfo {
|
||||||
neighborKeys[count++] = key;
|
neighborKeys[count++] = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int currentCodesSize = count;
|
||||||
|
for (int i = 0; i < currentCodesSize; ++i) {
|
||||||
|
final int c = neighborKeys[i].mCode;
|
||||||
|
final List<Integer> additionalChars = additionalProximityChars.get(c);
|
||||||
|
if (additionalChars == null || additionalChars.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < additionalChars.size(); ++j) {
|
||||||
|
final int additionalChar = additionalChars.get(j);
|
||||||
|
boolean contains = false;
|
||||||
|
for (int k = 0; k < count; ++k) {
|
||||||
|
if(additionalChar == neighborKeys[k].mCode) {
|
||||||
|
contains = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!contains) {
|
||||||
|
neighborKeys[count++] = keyCodeMap.get(additionalChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] =
|
mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] =
|
||||||
Arrays.copyOfRange(neighborKeys, 0, count);
|
Arrays.copyOfRange(neighborKeys, 0, count);
|
||||||
}
|
}
|
||||||
|
@ -199,7 +231,7 @@ public class ProximityInfo {
|
||||||
return EMPTY_KEY_ARRAY;
|
return EMPTY_KEY_ARRAY;
|
||||||
}
|
}
|
||||||
if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) {
|
if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) {
|
||||||
int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth);
|
int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth);
|
||||||
if (index < mGridSize) {
|
if (index < mGridSize) {
|
||||||
return mGridNeighbors[index];
|
return mGridNeighbors[index];
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin;
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.android.inputmethod.keyboard.Key;
|
import com.android.inputmethod.keyboard.Key;
|
||||||
import com.android.inputmethod.keyboard.KeyDetector;
|
import com.android.inputmethod.keyboard.KeyDetector;
|
||||||
import com.android.inputmethod.keyboard.Keyboard;
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
|
@ -33,7 +31,7 @@ public class WordComposer {
|
||||||
public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
|
public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
|
||||||
public static final int NOT_A_COORDINATE = -1;
|
public static final int NOT_A_COORDINATE = -1;
|
||||||
|
|
||||||
final int N = BinaryDictionary.MAX_WORD_LENGTH;
|
final static int N = BinaryDictionary.MAX_WORD_LENGTH;
|
||||||
|
|
||||||
private ArrayList<int[]> mCodes;
|
private ArrayList<int[]> mCodes;
|
||||||
private int[] mXCoordinates;
|
private int[] mXCoordinates;
|
||||||
|
|
|
@ -383,7 +383,10 @@ Correction::CorrectionType Correction::processCharAndCalcState(
|
||||||
incrementInputIndex();
|
incrementInputIndex();
|
||||||
} else {
|
} else {
|
||||||
--mTransposedCount;
|
--mTransposedCount;
|
||||||
if (DEBUG_CORRECTION) {
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0
|
||||||
|
|| MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
DUMP_WORD(mWord, mOutputIndex);
|
DUMP_WORD(mWord, mOutputIndex);
|
||||||
AKLOGI("UNRELATED(0): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
AKLOGI("UNRELATED(0): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
mTransposedCount, mExcessiveCount, c);
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
@ -404,13 +407,17 @@ Correction::CorrectionType Correction::processCharAndCalcState(
|
||||||
: mProximityInfo->getMatchedProximityId(
|
: mProximityInfo->getMatchedProximityId(
|
||||||
mInputIndex, c, checkProximityChars, &proximityIndex);
|
mInputIndex, c, checkProximityChars, &proximityIndex);
|
||||||
|
|
||||||
if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId) {
|
if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId
|
||||||
|
|| ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) {
|
||||||
if (canTryCorrection && mOutputIndex > 0
|
if (canTryCorrection && mOutputIndex > 0
|
||||||
&& mCorrectionStates[mOutputIndex].mProximityMatching
|
&& mCorrectionStates[mOutputIndex].mProximityMatching
|
||||||
&& mCorrectionStates[mOutputIndex].mExceeding
|
&& mCorrectionStates[mOutputIndex].mExceeding
|
||||||
&& isEquivalentChar(mProximityInfo->getMatchedProximityId(
|
&& isEquivalentChar(mProximityInfo->getMatchedProximityId(
|
||||||
mInputIndex, mWord[mOutputIndex - 1], false))) {
|
mInputIndex, mWord[mOutputIndex - 1], false))) {
|
||||||
if (DEBUG_CORRECTION) {
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0
|
||||||
|
|| MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
AKLOGI("CONVERSION p->e %c", mWord[mOutputIndex - 1]);
|
AKLOGI("CONVERSION p->e %c", mWord[mOutputIndex - 1]);
|
||||||
}
|
}
|
||||||
// Conversion p->e
|
// Conversion p->e
|
||||||
|
@ -429,7 +436,8 @@ Correction::CorrectionType Correction::processCharAndCalcState(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId) {
|
if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId
|
||||||
|
|| ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) {
|
||||||
// TODO: Optimize
|
// TODO: Optimize
|
||||||
// As the current char turned out to be an unrelated char,
|
// As the current char turned out to be an unrelated char,
|
||||||
// we will try other correction-types. Please note that mCorrectionStates[mOutputIndex]
|
// we will try other correction-types. Please note that mCorrectionStates[mOutputIndex]
|
||||||
|
@ -481,12 +489,47 @@ Correction::CorrectionType Correction::processCharAndCalcState(
|
||||||
++mExcessiveCount;
|
++mExcessiveCount;
|
||||||
incrementInputIndex();
|
incrementInputIndex();
|
||||||
}
|
}
|
||||||
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0
|
||||||
|
|| MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
|
DUMP_WORD(mWord, mOutputIndex);
|
||||||
|
if (mTransposing) {
|
||||||
|
AKLOGI("TRANSPOSE: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
} else {
|
||||||
|
AKLOGI("EXCEED: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (mSkipping) {
|
} else if (mSkipping) {
|
||||||
// 3. Skip correction
|
// 3. Skip correction
|
||||||
++mSkippedCount;
|
++mSkippedCount;
|
||||||
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0
|
||||||
|
|| MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
|
AKLOGI("SKIP: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
}
|
||||||
return processSkipChar(c, isTerminal, false);
|
return processSkipChar(c, isTerminal, false);
|
||||||
|
} else if (ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) {
|
||||||
|
// As a last resort, use additional proximity characters
|
||||||
|
mProximityMatching = true;
|
||||||
|
++mProximityCount;
|
||||||
|
mDistances[mOutputIndex] = ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO;
|
||||||
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0
|
||||||
|
|| MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
|
AKLOGI("ADDITIONALPROX: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG_CORRECTION) {
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0
|
||||||
|
|| MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
DUMP_WORD(mWord, mOutputIndex);
|
DUMP_WORD(mWord, mOutputIndex);
|
||||||
AKLOGI("UNRELATED(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
AKLOGI("UNRELATED(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
mTransposedCount, mExcessiveCount, c);
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
@ -506,6 +549,13 @@ Correction::CorrectionType Correction::processCharAndCalcState(
|
||||||
++mProximityCount;
|
++mProximityCount;
|
||||||
mDistances[mOutputIndex] =
|
mDistances[mOutputIndex] =
|
||||||
mProximityInfo->getNormalizedSquaredDistance(mInputIndex, proximityIndex);
|
mProximityInfo->getNormalizedSquaredDistance(mInputIndex, proximityIndex);
|
||||||
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0
|
||||||
|
|| MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
|
AKLOGI("PROX: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addCharToCurrentWord(c);
|
addCharToCurrentWord(c);
|
||||||
|
@ -539,7 +589,9 @@ Correction::CorrectionType Correction::processCharAndCalcState(
|
||||||
|| isSameAsUserTypedLength) && isTerminal) {
|
|| isSameAsUserTypedLength) && isTerminal) {
|
||||||
mTerminalInputIndex = mInputIndex - 1;
|
mTerminalInputIndex = mInputIndex - 1;
|
||||||
mTerminalOutputIndex = mOutputIndex - 1;
|
mTerminalOutputIndex = mOutputIndex - 1;
|
||||||
if (DEBUG_CORRECTION) {
|
if (DEBUG_CORRECTION
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength)
|
||||||
|
&& (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) {
|
||||||
DUMP_WORD(mWord, mOutputIndex);
|
DUMP_WORD(mWord, mOutputIndex);
|
||||||
AKLOGI("ONTERMINAL(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
AKLOGI("ONTERMINAL(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount,
|
||||||
mTransposedCount, mExcessiveCount, c);
|
mTransposedCount, mExcessiveCount, c);
|
||||||
|
@ -678,7 +730,7 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const
|
||||||
if (excessiveCount > 0) {
|
if (excessiveCount > 0) {
|
||||||
multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE, &finalFreq);
|
multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE, &finalFreq);
|
||||||
if (!lastCharExceeded && !proximityInfo->existsAdjacentProximityChars(excessivePos)) {
|
if (!lastCharExceeded && !proximityInfo->existsAdjacentProximityChars(excessivePos)) {
|
||||||
if (DEBUG_CORRECTION_FREQ) {
|
if (DEBUG_DICT_FULL) {
|
||||||
AKLOGI("Double excessive demotion");
|
AKLOGI("Double excessive demotion");
|
||||||
}
|
}
|
||||||
// If an excessive character is not adjacent to the left char or the right char,
|
// If an excessive character is not adjacent to the left char or the right char,
|
||||||
|
@ -687,51 +739,46 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool performTouchPositionCorrection =
|
||||||
|
CALIBRATE_SCORE_BY_TOUCH_COORDINATES && proximityInfo->touchPositionCorrectionEnabled()
|
||||||
|
&& skippedCount == 0 && excessiveCount == 0 && transposedCount == 0;
|
||||||
// Score calibration by touch coordinates is being done only for pure-fat finger typing error
|
// Score calibration by touch coordinates is being done only for pure-fat finger typing error
|
||||||
// cases.
|
// cases.
|
||||||
// TODO: Remove this constraint.
|
// TODO: Remove this constraint.
|
||||||
if (CALIBRATE_SCORE_BY_TOUCH_COORDINATES && proximityInfo->touchPositionCorrectionEnabled()
|
for (int i = 0; i < outputLength; ++i) {
|
||||||
&& skippedCount == 0 && excessiveCount == 0 && transposedCount == 0) {
|
const int squaredDistance = correction->mDistances[i];
|
||||||
for (int i = 0; i < outputLength; ++i) {
|
if (i < adjustedProximityMatchedCount) {
|
||||||
const int squaredDistance = correction->mDistances[i];
|
|
||||||
if (i < adjustedProximityMatchedCount) {
|
|
||||||
multiplyIntCapped(typedLetterMultiplier, &finalFreq);
|
|
||||||
}
|
|
||||||
if (squaredDistance >= 0) {
|
|
||||||
// Promote or demote the score according to the distance from the sweet spot
|
|
||||||
static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f;
|
|
||||||
static const float B = 1.0f;
|
|
||||||
static const float C = 0.5f;
|
|
||||||
static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS;
|
|
||||||
static const float R2 = HALF_SCORE_SQUARED_RADIUS;
|
|
||||||
const float x = (float)squaredDistance
|
|
||||||
/ ProximityInfo::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
|
|
||||||
const float factor = (x < R1)
|
|
||||||
? (A * (R1 - x) + B * x) / R1
|
|
||||||
: (B * (R2 - x) + C * (x - R1)) / (R2 - R1);
|
|
||||||
// factor is piecewise linear function like:
|
|
||||||
// A -_ .
|
|
||||||
// ^-_ .
|
|
||||||
// B \ .
|
|
||||||
// \ .
|
|
||||||
// C \ .
|
|
||||||
// 0 R1 R2
|
|
||||||
if (factor <= 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
multiplyRate((int)(factor * 100), &finalFreq);
|
|
||||||
} else if (squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) {
|
|
||||||
multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Promotion for a word with proximity characters
|
|
||||||
for (int i = 0; i < adjustedProximityMatchedCount; ++i) {
|
|
||||||
// A word with proximity corrections
|
|
||||||
if (DEBUG_DICT_FULL) {
|
|
||||||
AKLOGI("Found a proximity correction.");
|
|
||||||
}
|
|
||||||
multiplyIntCapped(typedLetterMultiplier, &finalFreq);
|
multiplyIntCapped(typedLetterMultiplier, &finalFreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performTouchPositionCorrection && squaredDistance >= 0) {
|
||||||
|
// Promote or demote the score according to the distance from the sweet spot
|
||||||
|
static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f;
|
||||||
|
static const float B = 1.0f;
|
||||||
|
static const float C = 0.5f;
|
||||||
|
static const float MIN = 0.3f;
|
||||||
|
static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS;
|
||||||
|
static const float R2 = HALF_SCORE_SQUARED_RADIUS;
|
||||||
|
const float x = (float)squaredDistance
|
||||||
|
/ ProximityInfo::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
|
||||||
|
const float factor = max((x < R1)
|
||||||
|
? (A * (R1 - x) + B * x) / R1
|
||||||
|
: (B * (R2 - x) + C * (x - R1)) / (R2 - R1), MIN);
|
||||||
|
// factor is piecewise linear function like:
|
||||||
|
// A -_ .
|
||||||
|
// ^-_ .
|
||||||
|
// B \ .
|
||||||
|
// \_ .
|
||||||
|
// C ------------.
|
||||||
|
// .
|
||||||
|
// 0 R1 R2 .
|
||||||
|
multiplyRate((int)(factor * 100), &finalFreq);
|
||||||
|
} else if (performTouchPositionCorrection
|
||||||
|
&& squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) {
|
||||||
|
multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
|
||||||
|
} else if (squaredDistance == ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO) {
|
||||||
|
multiplyRate(WORDS_WITH_ADDITIONAL_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
|
||||||
|
} else if (i < adjustedProximityMatchedCount) {
|
||||||
multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
|
multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,7 +841,8 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const
|
||||||
AKLOGI("calc: %d, %d", outputLength, sameLength);
|
AKLOGI("calc: %d, %d", outputLength, sameLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG_CORRECTION_FREQ) {
|
if (DEBUG_CORRECTION_FREQ
|
||||||
|
&& (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == inputLength)) {
|
||||||
DUMP_WORD(correction->mWord, outputLength);
|
DUMP_WORD(correction->mWord, outputLength);
|
||||||
AKLOGI("FinalFreq: [P%d, S%d, T%d, E%d] %d, %d, %d, %d, %d, %d", proximityMatchedCount,
|
AKLOGI("FinalFreq: [P%d, S%d, T%d, E%d] %d, %d, %d, %d, %d, %d", proximityMatchedCount,
|
||||||
skippedCount, transposedCount, excessiveCount, outputLength, lastCharExceeded,
|
skippedCount, transposedCount, excessiveCount, outputLength, lastCharExceeded,
|
||||||
|
|
|
@ -85,7 +85,7 @@ class Correction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Correction(const int typedLetterMultiplier, const int fullWordMultiplier);
|
Correction(const int typedLetterMultiplier, const int fullWordMultiplier);
|
||||||
void initCorrection(
|
void initCorrection(
|
||||||
const ProximityInfo *pi, const int inputLength, const int maxWordLength);
|
const ProximityInfo *pi, const int inputLength, const int maxWordLength);
|
||||||
void initCorrectionState(const int rootPos, const int childCount, const bool traverseAll);
|
void initCorrectionState(const int rootPos, const int childCount, const bool traverseAll);
|
||||||
|
|
|
@ -172,6 +172,7 @@ static void prof_out(void) {
|
||||||
#define NOT_A_COORDINATE -1
|
#define NOT_A_COORDINATE -1
|
||||||
#define EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO -2
|
#define EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO -2
|
||||||
#define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO -3
|
#define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO -3
|
||||||
|
#define ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO -4
|
||||||
#define NOT_A_INDEX -1
|
#define NOT_A_INDEX -1
|
||||||
#define NOT_A_FREQUENCY -1
|
#define NOT_A_FREQUENCY -1
|
||||||
|
|
||||||
|
@ -194,6 +195,7 @@ static void prof_out(void) {
|
||||||
#define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 70
|
#define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 70
|
||||||
#define FULL_MATCHED_WORDS_PROMOTION_RATE 120
|
#define FULL_MATCHED_WORDS_PROMOTION_RATE 120
|
||||||
#define WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE 90
|
#define WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE 90
|
||||||
|
#define WORDS_WITH_ADDITIONAL_PROXIMITY_CHARACTER_DEMOTION_RATE 30
|
||||||
#define WORDS_WITH_MATCH_SKIP_PROMOTION_RATE 105
|
#define WORDS_WITH_MATCH_SKIP_PROMOTION_RATE 105
|
||||||
#define WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_RATE 160
|
#define WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_RATE 160
|
||||||
#define CORRECTION_COUNT_RATE_DEMOTION_RATE_BASE 45
|
#define CORRECTION_COUNT_RATE_DEMOTION_RATE_BASE 45
|
||||||
|
@ -210,6 +212,9 @@ static void prof_out(void) {
|
||||||
// This is only used for the size of array. Not to be used in c functions.
|
// This is only used for the size of array. Not to be used in c functions.
|
||||||
#define MAX_WORD_LENGTH_INTERNAL 48
|
#define MAX_WORD_LENGTH_INTERNAL 48
|
||||||
|
|
||||||
|
// This must be equal to ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE in KeyDetector.java
|
||||||
|
#define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2
|
||||||
|
|
||||||
// Word limit for sub queues used in WordsPriorityQueuePool. Sub queues are temporary queues used
|
// Word limit for sub queues used in WordsPriorityQueuePool. Sub queues are temporary queues used
|
||||||
// for better performance.
|
// for better performance.
|
||||||
// Holds up to 1 candidate for each word
|
// Holds up to 1 candidate for each word
|
||||||
|
@ -241,4 +246,8 @@ static void prof_out(void) {
|
||||||
// The ratio of neutral area radius to sweet spot radius.
|
// The ratio of neutral area radius to sweet spot radius.
|
||||||
#define NEUTRAL_AREA_RADIUS_RATIO 1.3f
|
#define NEUTRAL_AREA_RADIUS_RATIO 1.3f
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
#define INPUTLENGTH_FOR_DEBUG -1
|
||||||
|
#define MIN_OUTPUT_INDEX_FOR_DEBUG -1
|
||||||
|
|
||||||
#endif // LATINIME_DEFINES_H
|
#endif // LATINIME_DEFINES_H
|
||||||
|
|
|
@ -261,7 +261,8 @@ ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int inde
|
||||||
|
|
||||||
// Not an exact nor an accent-alike match: search the list of close keys
|
// Not an exact nor an accent-alike match: search the list of close keys
|
||||||
int j = 1;
|
int j = 1;
|
||||||
while (j < MAX_PROXIMITY_CHARS_SIZE && currentChars[j] > 0) {
|
while (j < MAX_PROXIMITY_CHARS_SIZE
|
||||||
|
&& currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
|
||||||
const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c);
|
const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c);
|
||||||
if (matched) {
|
if (matched) {
|
||||||
if (proximityIndex) {
|
if (proximityIndex) {
|
||||||
|
@ -271,6 +272,21 @@ ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int inde
|
||||||
}
|
}
|
||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
|
if (j < MAX_PROXIMITY_CHARS_SIZE
|
||||||
|
&& currentChars[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
|
||||||
|
++j;
|
||||||
|
while (j < MAX_PROXIMITY_CHARS_SIZE
|
||||||
|
&& currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
|
||||||
|
const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c);
|
||||||
|
if (matched) {
|
||||||
|
if (proximityIndex) {
|
||||||
|
*proximityIndex = j;
|
||||||
|
}
|
||||||
|
return ADDITIONAL_PROXIMITY_CHAR;
|
||||||
|
}
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Was not included, signal this as an unrelated character.
|
// Was not included, signal this as an unrelated character.
|
||||||
return UNRELATED_CHAR;
|
return UNRELATED_CHAR;
|
||||||
|
|
|
@ -38,7 +38,9 @@ class ProximityInfo {
|
||||||
// It is a char located nearby on the keyboard
|
// It is a char located nearby on the keyboard
|
||||||
NEAR_PROXIMITY_CHAR,
|
NEAR_PROXIMITY_CHAR,
|
||||||
// It is an unrelated char
|
// It is an unrelated char
|
||||||
UNRELATED_CHAR
|
UNRELATED_CHAR,
|
||||||
|
// Additional proximity char which can differ by language.
|
||||||
|
ADDITIONAL_PROXIMITY_CHAR
|
||||||
} ProximityType;
|
} ProximityType;
|
||||||
|
|
||||||
ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth,
|
ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth,
|
||||||
|
|
Loading…
Reference in New Issue