diff options
Diffstat (limited to 'java')
5 files changed, 84 insertions, 12 deletions
diff --git a/java/src/com/android/inputmethod/event/Combiner.java b/java/src/com/android/inputmethod/event/Combiner.java index c3869a299..8b808c6b3 100644 --- a/java/src/com/android/inputmethod/event/Combiner.java +++ b/java/src/com/android/inputmethod/event/Combiner.java @@ -34,4 +34,15 @@ public interface Combiner { * @return the resulting event. */ Event processEvent(ArrayList<Event> previousEvents, Event event); + + /** + * Get the feedback that should be shown to the user for the current state of this combiner. + * @return A CharSequence representing the feedback to show users. It may include styles. + */ + CharSequence getCombiningStateFeedback(); + + /** + * Reset the state of this combiner, for example when the cursor was moved. + */ + void reset(); } diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java index 0e01c819a..5ca9842c1 100644 --- a/java/src/com/android/inputmethod/event/CombinerChain.java +++ b/java/src/com/android/inputmethod/event/CombinerChain.java @@ -16,6 +16,8 @@ package com.android.inputmethod.event; +import android.text.SpannableStringBuilder; + import com.android.inputmethod.latin.utils.CollectionUtils; import java.util.ArrayList; @@ -33,8 +35,10 @@ import java.util.ArrayList; * a colored background. */ public class CombinerChain { - // TODO: Create an object type to represent input material + visual feedback + decoding state - + // The already combined text, as described above + private StringBuilder mCombinedText; + // The feedback on the composing state, as described above + private SpannableStringBuilder mStateFeedback; private final ArrayList<Combiner> mCombiners; /** @@ -50,9 +54,23 @@ public class CombinerChain { mCombiners = CollectionUtils.newArrayList(); // The dead key combiner is always active, and always first mCombiners.add(new DeadKeyCombiner()); + mCombinedText = new StringBuilder(); + mStateFeedback = new SpannableStringBuilder(); } - // Pass a new event through the whole chain. + public void reset() { + mCombinedText.setLength(0); + mStateFeedback.clear(); + for (final Combiner c : mCombiners) { + c.reset(); + } + } + + /** + * Pass a new event through the whole chain. + * @param previousEvents the list of previous events in this composition + * @param newEvent the new event to process + */ public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { final ArrayList<Event> modifiablePreviousEvents = new ArrayList<Event>(previousEvents); Event event = newEvent; @@ -62,8 +80,24 @@ public class CombinerChain { event = combiner.processEvent(modifiablePreviousEvents, event); if (null == event) { // Combiners return null if they eat the event. - return; + break; } } + if (null != event) { + mCombinedText.append(event.getTextToCommit()); + } + mStateFeedback.clear(); + for (int i = mCombiners.size() - 1; i >= 0; --i) { + mStateFeedback.append(mCombiners.get(i).getCombiningStateFeedback()); + } + } + + /** + * Get the char sequence that should be displayed as the composing word. It may include + * styling spans. + */ + public CharSequence getComposingWordWithCombiningFeedback() { + final SpannableStringBuilder s = new SpannableStringBuilder(mCombinedText); + return s.append(mStateFeedback); } } diff --git a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java index f77ce6347..89e623a1d 100644 --- a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java +++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java @@ -61,4 +61,14 @@ public class DeadKeyCombiner implements Combiner { } } } + + @Override + public void reset() { + mDeadSequence.setLength(0); + } + + @Override + public CharSequence getCombiningStateFeedback() { + return mDeadSequence; + } } diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index db4023436..2bfe0732d 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -18,6 +18,7 @@ package com.android.inputmethod.event; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.utils.StringUtils; /** * Class representing a generic input event as handled by Latin IME. @@ -223,4 +224,19 @@ public class Event { public boolean isHandled() { return EVENT_NOT_HANDLED != mType; } + + public CharSequence getTextToCommit() { + switch (mType) { + case EVENT_MODE_KEY: + case EVENT_NOT_HANDLED: + return ""; + case EVENT_INPUT_KEYPRESS: + case EVENT_TOGGLE: + return StringUtils.newSingleCodePointString(mCodePoint); + case EVENT_GESTURE: + case EVENT_SOFTWARE_GENERATED_STRING: + return mText; + } + throw new RuntimeException("Unknown event type: " + mType); + } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 29382fea4..a60ca3d41 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -127,6 +127,7 @@ public final class WordComposer { * Clear out the keys registered so far. */ public void reset() { + mCombinerChain.reset(); mTypedWord.setLength(0); mEvents.clear(); mAutoCorrection = null; @@ -166,13 +167,6 @@ public final class WordComposer { return mPrimaryKeyCodes[index]; } - public int getCodeBeforeCursor() { - if (mCursorPositionWithinWord < 1 || mCursorPositionWithinWord > mPrimaryKeyCodes.length) { - return Constants.NOT_A_CODE; - } - return mPrimaryKeyCodes[mCursorPositionWithinWord - 1]; - } - public InputPointers getInputPointers() { return mInputPointers; } @@ -193,7 +187,10 @@ public final class WordComposer { final int keyY = event.mY; final int newIndex = size(); mCombinerChain.processEvent(mEvents, event); - mTypedWord.appendCodePoint(primaryCode); + // TODO: remove mTypedWord and compute it dynamically when necessary. We also need to + // make the views of the composing word a SpannableString. + mTypedWord.replace(0, mTypedWord.length(), + mCombinerChain.getComposingWordWithCombiningFeedback().toString()); mEvents.add(event); refreshSize(); mCursorPositionWithinWord = mCodePointSize; @@ -243,6 +240,8 @@ public final class WordComposer { * @return true if the cursor is still inside the composing word, false otherwise. */ public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) { + // TODO: should uncommit the composing feedback + mCombinerChain.reset(); int actualMoveAmountWithinWord = 0; int cursorPos = mCursorPositionWithinWord; final int[] codePoints; @@ -482,6 +481,7 @@ public final class WordComposer { mIsBatchMode = false; mPreviousWordForSuggestion = committedWord.toString(); mTypedWord.setLength(0); + mCombinerChain.reset(); mEvents.clear(); mCodePointSize = 0; mTrailingSingleQuotesCount = 0; @@ -509,6 +509,7 @@ public final class WordComposer { Collections.copy(mEvents, lastComposedWord.mEvents); mInputPointers.set(lastComposedWord.mInputPointers); mTypedWord.setLength(0); + mCombinerChain.reset(); mTypedWord.append(lastComposedWord.mTypedWord); refreshSize(); mCapitalizedMode = lastComposedWord.mCapitalizedMode; |