Introduce clustering punctuation

Bug: 10081730
Change-Id: If198fa3df68ecb267da0a278da41fd509d6165f1
main
Jean Chalard 2014-05-01 12:33:59 +09:00
parent 879629af3c
commit 29c00ff538
6 changed files with 49 additions and 10 deletions

View File

@ -22,6 +22,8 @@
<string name="symbols_preceded_by_space">([{&amp;;:!?</string> <string name="symbols_preceded_by_space">([{&amp;;:!?</string>
<!-- Symbols that are normally followed by a space (used to add an auto-space after these) --> <!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
<string name="symbols_followed_by_space">.,;:!?)]}&amp;</string> <string name="symbols_followed_by_space">.,;:!?)]}&amp;</string>
<!-- Symbols that behave like a single punctuation when typed next to each other -->
<string name="symbols_clustering_together">!?</string>
<!-- Symbols that separate words --> <!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) --> <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
<string name="symbols_word_separators">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string> <string name="symbols_word_separators">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>

View File

@ -26,6 +26,8 @@
<string name="symbols_preceded_by_space">([{&amp;</string> <string name="symbols_preceded_by_space">([{&amp;</string>
<!-- Symbols that are normally followed by a space (used to add an auto-space after these) --> <!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
<string name="symbols_followed_by_space">.,;:!?)]}&amp;</string> <string name="symbols_followed_by_space">.,;:!?)]}&amp;</string>
<!-- Symbols that behave like a single punctuation when typed next to each other -->
<string name="symbols_clustering_together"></string>
<!-- Symbols that separate words --> <!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) --> <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
<string name="symbols_word_separators">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string> <string name="symbols_word_separators">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>

View File

@ -784,11 +784,11 @@ public final class InputLogic {
// TODO: remove this argument // TODO: remove this argument
final LatinIME.UIHandler handler) { final LatinIME.UIHandler handler) {
final int codePoint = inputTransaction.mEvent.mCodePoint; final int codePoint = inputTransaction.mEvent.mCodePoint;
final SettingsValues settingsValues = inputTransaction.mSettingsValues;
boolean didAutoCorrect = false; boolean didAutoCorrect = false;
// We avoid sending spaces in languages without spaces if we were composing. // We avoid sending spaces in languages without spaces if we were composing.
final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint
&& !inputTransaction.mSettingsValues.mSpacingAndPunctuations && !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
.mCurrentLanguageHasSpaces
&& mWordComposer.isComposingWord(); && mWordComposer.isComposingWord();
if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
// If we are in the middle of a recorrection, we need to commit the recorrection // If we are in the middle of a recorrection, we need to commit the recorrection
@ -798,13 +798,13 @@ public final class InputLogic {
} }
// isComposingWord() may have changed since we stored wasComposing // isComposingWord() may have changed since we stored wasComposing
if (mWordComposer.isComposingWord()) { if (mWordComposer.isComposingWord()) {
if (inputTransaction.mSettingsValues.mCorrectionEnabled) { if (settingsValues.mCorrectionEnabled) {
final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
: StringUtils.newSingleCodePointString(codePoint); : StringUtils.newSingleCodePointString(codePoint);
commitCurrentAutoCorrection(inputTransaction.mSettingsValues, separator, handler); commitCurrentAutoCorrection(settingsValues, separator, handler);
didAutoCorrect = true; didAutoCorrect = true;
} else { } else {
commitTyped(inputTransaction.mSettingsValues, commitTyped(settingsValues,
StringUtils.newSingleCodePointString(codePoint)); StringUtils.newSingleCodePointString(codePoint));
} }
} }
@ -821,20 +821,23 @@ public final class InputLogic {
// Double quotes behave like they are usually preceded by space iff we are // Double quotes behave like they are usually preceded by space iff we are
// not inside a double quote or after a digit. // not inside a double quote or after a digit.
needsPrecedingSpace = !isInsideDoubleQuoteOrAfterDigit; needsPrecedingSpace = !isInsideDoubleQuoteOrAfterDigit;
} else if (settingsValues.mSpacingAndPunctuations.isClusteringSymbol(codePoint)
&& settingsValues.mSpacingAndPunctuations.isClusteringSymbol(
mConnection.getCodePointBeforeCursor())) {
needsPrecedingSpace = false;
} else { } else {
needsPrecedingSpace = inputTransaction.mSettingsValues.isUsuallyPrecededBySpace( needsPrecedingSpace = settingsValues.isUsuallyPrecededBySpace(codePoint);
codePoint);
} }
if (needsPrecedingSpace) { if (needsPrecedingSpace) {
promotePhantomSpace(inputTransaction.mSettingsValues); promotePhantomSpace(settingsValues);
} }
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_handleSeparator(codePoint, mWordComposer.isComposingWord()); ResearchLogger.latinIME_handleSeparator(codePoint, mWordComposer.isComposingWord());
} }
if (!shouldAvoidSendingCode) { if (!shouldAvoidSendingCode) {
sendKeyCodePoint(inputTransaction.mSettingsValues, codePoint); sendKeyCodePoint(settingsValues, codePoint);
} }
if (Constants.CODE_SPACE == codePoint) { if (Constants.CODE_SPACE == codePoint) {
@ -852,7 +855,7 @@ public final class InputLogic {
swapSwapperAndSpace(inputTransaction); swapSwapperAndSpace(inputTransaction);
mSpaceState = SpaceState.SWAP_PUNCTUATION; mSpaceState = SpaceState.SWAP_PUNCTUATION;
} else if ((SpaceState.PHANTOM == inputTransaction.mSpaceState } else if ((SpaceState.PHANTOM == inputTransaction.mSpaceState
&& inputTransaction.mSettingsValues.isUsuallyFollowedBySpace(codePoint)) && settingsValues.isUsuallyFollowedBySpace(codePoint))
|| (Constants.CODE_DOUBLE_QUOTE == codePoint || (Constants.CODE_DOUBLE_QUOTE == codePoint
&& isInsideDoubleQuoteOrAfterDigit)) { && isInsideDoubleQuoteOrAfterDigit)) {
// If we are in phantom space state, and the user presses a separator, we want to // If we are in phantom space state, and the user presses a separator, we want to

View File

@ -30,6 +30,7 @@ import java.util.Locale;
public final class SpacingAndPunctuations { public final class SpacingAndPunctuations {
private final int[] mSortedSymbolsPrecededBySpace; private final int[] mSortedSymbolsPrecededBySpace;
private final int[] mSortedSymbolsFollowedBySpace; private final int[] mSortedSymbolsFollowedBySpace;
private final int[] mSortedSymbolsClusteringTogether;
private final int[] mSortedWordConnectors; private final int[] mSortedWordConnectors;
public final int[] mSortedWordSeparators; public final int[] mSortedWordSeparators;
public final PunctuationSuggestions mSuggestPuncList; public final PunctuationSuggestions mSuggestPuncList;
@ -46,6 +47,8 @@ public final class SpacingAndPunctuations {
// To be able to binary search the code point. See {@link #isUsuallyFollowedBySpace(int)}. // To be able to binary search the code point. See {@link #isUsuallyFollowedBySpace(int)}.
mSortedSymbolsFollowedBySpace = StringUtils.toSortedCodePointArray( mSortedSymbolsFollowedBySpace = StringUtils.toSortedCodePointArray(
res.getString(R.string.symbols_followed_by_space)); res.getString(R.string.symbols_followed_by_space));
mSortedSymbolsClusteringTogether = StringUtils.toSortedCodePointArray(
res.getString(R.string.symbols_clustering_together));
// To be able to binary search the code point. See {@link #isWordConnector(int)}. // To be able to binary search the code point. See {@link #isWordConnector(int)}.
mSortedWordConnectors = StringUtils.toSortedCodePointArray( mSortedWordConnectors = StringUtils.toSortedCodePointArray(
res.getString(R.string.symbols_word_connectors)); res.getString(R.string.symbols_word_connectors));
@ -85,6 +88,10 @@ public final class SpacingAndPunctuations {
return Arrays.binarySearch(mSortedSymbolsFollowedBySpace, code) >= 0; return Arrays.binarySearch(mSortedSymbolsFollowedBySpace, code) >= 0;
} }
public boolean isClusteringSymbol(final int code) {
return Arrays.binarySearch(mSortedSymbolsClusteringTogether, code) >= 0;
}
public boolean isSentenceSeparator(final int code) { public boolean isSentenceSeparator(final int code) {
return code == mSentenceSeparator; return code == mSentenceSeparator;
} }

View File

@ -334,6 +334,18 @@ public class InputLogicTests extends InputTestsBase {
assertEquals("manual pick then separator", EXPECTED_RESULT, mEditText.getText().toString()); assertEquals("manual pick then separator", EXPECTED_RESULT, mEditText.getText().toString());
} }
// This test matches the one in InputLogicTestsNonEnglish. In some non-English languages,
// ! and ? are clustering punctuation signs.
public void testClusteringPunctuation() {
final String WORD1_TO_TYPE = "test";
final String WORD2_TO_TYPE = "!!?!:!";
final String EXPECTED_RESULT = "test!!?!:!";
type(WORD1_TO_TYPE);
pickSuggestionManually(0, WORD1_TO_TYPE);
type(WORD2_TO_TYPE);
assertEquals("clustering punctuation", EXPECTED_RESULT, mEditText.getText().toString());
}
public void testManualPickThenStripperThenPick() { public void testManualPickThenStripperThenPick() {
final String WORD_TO_TYPE = "this"; final String WORD_TO_TYPE = "this";
final String STRIPPER = "\n"; final String STRIPPER = "\n";

View File

@ -45,6 +45,19 @@ public class InputLogicTestsNonEnglish extends InputTestsBase {
mEditText.getText().toString()); mEditText.getText().toString());
} }
public void testClusteringPunctuationForFrench() {
final String WORD1_TO_TYPE = "test";
final String WORD2_TO_TYPE = "!!?!:!";
// In English, the expected result would be "test!!?!:!"
final String EXPECTED_RESULT = "test !!?! : !";
changeLanguage("fr");
type(WORD1_TO_TYPE);
pickSuggestionManually(0, WORD1_TO_TYPE);
type(WORD2_TO_TYPE);
assertEquals("clustering punctuation for French", EXPECTED_RESULT,
mEditText.getText().toString());
}
public void testWordThenSpaceThenPunctuationFromStripTwiceForFrench() { public void testWordThenSpaceThenPunctuationFromStripTwiceForFrench() {
final String WORD_TO_TYPE = "test "; final String WORD_TO_TYPE = "test ";
final String PUNCTUATION_FROM_STRIP = "!"; final String PUNCTUATION_FROM_STRIP = "!";