diff --git a/java/src/com/android/inputmethod/event/Combiner.java b/java/src/com/android/inputmethod/event/Combiner.java index c3869a299..bdc761234 100644 --- a/java/src/com/android/inputmethod/event/Combiner.java +++ b/java/src/com/android/inputmethod/event/Combiner.java @@ -34,4 +34,10 @@ public interface Combiner { * @return the resulting event. */ Event processEvent(ArrayList 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(); } diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java index 0e01c819a..cf2a4d1a1 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 mCombiners; /** @@ -50,9 +54,15 @@ 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. + /** + * 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 previousEvents, final Event newEvent) { final ArrayList modifiablePreviousEvents = new ArrayList(previousEvents); Event event = newEvent; @@ -62,8 +72,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..f891017a3 100644 --- a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java +++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java @@ -61,4 +61,9 @@ public class DeadKeyCombiner implements Combiner { } } } + + @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..d55a773b4 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -193,7 +193,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; diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java index 66ad60c74..e70ede4d3 100644 --- a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java +++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java @@ -21,6 +21,12 @@ import com.android.inputmethod.latin.utils.CollectionUtils; import java.util.ArrayList; public class CombinerChain { + private StringBuilder mComposingWord = new StringBuilder(); public CombinerChain(final Combiner... combinerList) {} - public void processEvent(final ArrayList previousEvents, final Event newEvent) {} + public void processEvent(final ArrayList previousEvents, final Event newEvent) { + mComposingWord.append(newEvent.getTextToCommit()); + } + public CharSequence getComposingWordWithCombiningFeedback() { + return mComposingWord; + } }