diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
4 files changed, 159 insertions, 52 deletions
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index cdd782244..3b6904847 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -25,6 +25,8 @@ import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Collections; +import javax.annotation.Nonnull; + /** * A place to store the currently composing word with information such as adjacent key codes as well */ @@ -175,20 +177,31 @@ public final class WordComposer { } /** - * Process an input event. + * Process an event and return an event, and return a processed event to apply. + * @param event the unprocessed event. + * @return the processed event. Never null, but may be marked as consumed. + */ + @Nonnull + public Event processEvent(final Event event) { + final Event processedEvent = mCombinerChain.processEvent(mEvents, event); + mEvents.add(event); + return processedEvent; + } + + /** + * Apply a processed input event. * * All input events should be supported, including software/hardware events, characters as well * as deletions, multiple inputs and gestures. * - * @param event the event to process. + * @param event the event to apply. Must not be null. */ - public void processEvent(final Event event) { + public void applyProcessedEvent(final Event event) { + mCombinerChain.applyProcessedEvent(event); final int primaryCode = event.mCodePoint; final int keyX = event.mX; final int keyY = event.mY; final int newIndex = size(); - mCombinerChain.processEvent(mEvents, event); - mEvents.add(event); refreshTypedWordCache(); mCursorPositionWithinWord = mCodePointSize; // We may have deleted the last one. @@ -281,7 +294,9 @@ public final class WordComposer { final int codePoint = Character.codePointAt(word, i); // We don't want to override the batch input points that are held in mInputPointers // (See {@link #add(int,int,int)}). - processEvent(Event.createEventForCodePointFromUnknownSource(codePoint)); + final Event processedEvent = + processEvent(Event.createEventForCodePointFromUnknownSource(codePoint)); + applyProcessedEvent(processedEvent); } } @@ -295,9 +310,11 @@ public final class WordComposer { reset(); final int length = codePoints.length; for (int i = 0; i < length; ++i) { - processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i], + final Event processedEvent = + processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i], CoordinateUtils.xFromArray(coordinates, i), CoordinateUtils.yFromArray(coordinates, i))); + applyProcessedEvent(processedEvent); } mIsResumed = true; } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 74d879919..bb2d304a6 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -762,7 +762,8 @@ public final class InputLogic { resetComposingState(false /* alsoResetLastComposedWord */); } if (isComposingWord) { - mWordComposer.processEvent(inputTransaction.mEvent); + final Event processedEvent = mWordComposer.processEvent(inputTransaction.mEvent); + mWordComposer.applyProcessedEvent(processedEvent); // If it's the first letter, make note of auto-caps state if (mWordComposer.isSingleLetter()) { mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState); @@ -933,7 +934,8 @@ public final class InputLogic { mDictionaryFacilitator.removeWordFromPersonalizedDicts(rejectedSuggestion); } } else { - mWordComposer.processEvent(inputTransaction.mEvent); + final Event processedEvent = mWordComposer.processEvent(inputTransaction.mEvent); + mWordComposer.applyProcessedEvent(processedEvent); } if (mWordComposer.isComposingWord()) { mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index d151e4037..6c4d80ecb 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -38,6 +38,7 @@ import android.widget.ImageButton; import android.widget.RelativeLayout; import android.widget.TextView; +import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.keyboard.MoreKeysPanel; @@ -368,13 +369,15 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick return true; } - // Working variables for {@link #onLongClick(View)} and - // {@link onInterceptTouchEvent(MotionEvent)}. + // Working variables for {@link onInterceptTouchEvent(MotionEvent)} and + // {@link onTouchEvent(MotionEvent)}. private int mLastX; private int mLastY; private int mOriginX; private int mOriginY; private final int mMoreSuggestionsModalTolerance; + private boolean mNeedsToTransformTouchEventToHoverEvent; + private boolean mIsDispatchingHoverEventToMoreSuggestions; private final GestureDetector mMoreSuggestionsSlidingDetector; private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener = new GestureDetector.SimpleOnGestureListener() { @@ -402,9 +405,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick final int y = (int)me.getY(index); if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance || mOriginY - y >= mMoreSuggestionsModalTolerance) { - // Decided to be in the sliding input mode only when the touch point has been moved + // Decided to be in the sliding suggestion mode only when the touch point has been moved // upward. Further {@link MotionEvent}s will be delivered to // {@link #onTouchEvent(MotionEvent)}. + mNeedsToTransformTouchEventToHoverEvent = AccessibilityUtils.getInstance() + .isTouchExplorationEnabled(); + mIsDispatchingHoverEventToMoreSuggestions = false; return true; } @@ -426,10 +432,41 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick // In the sliding input mode. {@link MotionEvent} should be forwarded to // {@link MoreSuggestionsView}. final int index = me.getActionIndex(); - final int x = (int)me.getX(index); - final int y = (int)me.getY(index); - me.setLocation(mMoreSuggestionsView.translateX(x), mMoreSuggestionsView.translateY(y)); - mMoreSuggestionsView.onTouchEvent(me); + final int x = mMoreSuggestionsView.translateX((int)me.getX(index)); + final int y = mMoreSuggestionsView.translateY((int)me.getY(index)); + me.setLocation(x, y); + if (!mNeedsToTransformTouchEventToHoverEvent) { + mMoreSuggestionsView.onTouchEvent(me); + return true; + } + // In sliding suggestion mode with accessibility mode on, a touch event should be + // transformed to a hover event. + final int width = mMoreSuggestionsView.getWidth(); + final int height = mMoreSuggestionsView.getHeight(); + final boolean onMoreSuggestions = (x >= 0 && x < width && y >= 0 && y < height); + if (!onMoreSuggestions && !mIsDispatchingHoverEventToMoreSuggestions) { + // Just drop this touch event because dispatching hover event isn't started yet and + // the touch event isn't on {@link MoreSuggestionsView}. + return true; + } + final int hoverAction; + if (onMoreSuggestions && !mIsDispatchingHoverEventToMoreSuggestions) { + // Transform this touch event to a hover enter event and start dispatching a hover + // event to {@link MoreSuggestionsView}. + mIsDispatchingHoverEventToMoreSuggestions = true; + hoverAction = MotionEvent.ACTION_HOVER_ENTER; + } else if (me.getActionMasked() == MotionEvent.ACTION_UP) { + // Transform this touch event to a hover exit event and stop dispatching a hover event + // after this. + mIsDispatchingHoverEventToMoreSuggestions = false; + mNeedsToTransformTouchEventToHoverEvent = false; + hoverAction = MotionEvent.ACTION_HOVER_EXIT; + } else { + // Transform this touch event to a hover move event. + hoverAction = MotionEvent.ACTION_HOVER_MOVE; + } + me.setAction(hoverAction); + mMoreSuggestionsView.onHoverEvent(me); return true; } diff --git a/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java b/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java index a76a6dfd7..0e244666d 100644 --- a/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java @@ -26,13 +26,24 @@ public class ScriptUtils { // Used for hardware keyboards public static final int SCRIPT_UNKNOWN = -1; // TODO: should we use ISO 15924 identifiers instead? - public static final int SCRIPT_LATIN = 0; - public static final int SCRIPT_CYRILLIC = 1; - public static final int SCRIPT_GREEK = 2; - public static final int SCRIPT_ARABIC = 3; - public static final int SCRIPT_HEBREW = 4; - public static final int SCRIPT_ARMENIAN = 5; - public static final int SCRIPT_GEORGIAN = 6; + public static final int SCRIPT_ARABIC = 0; + public static final int SCRIPT_ARMENIAN = 1; + public static final int SCRIPT_BENGALI = 2; + public static final int SCRIPT_CYRILLIC = 3; + public static final int SCRIPT_DEVANAGARI = 4; + public static final int SCRIPT_GEORGIAN = 5; + public static final int SCRIPT_GREEK = 6; + public static final int SCRIPT_HEBREW = 7; + public static final int SCRIPT_KANNADA = 8; + public static final int SCRIPT_KHMER = 9; + public static final int SCRIPT_LAO = 10; + public static final int SCRIPT_LATIN = 11; + public static final int SCRIPT_MALAYALAM = 12; + public static final int SCRIPT_MYANMAR = 13; + public static final int SCRIPT_SINHALA = 14; + public static final int SCRIPT_TAMIL = 15; + public static final int SCRIPT_TELUGU = 16; + public static final int SCRIPT_THAI = 17; public static final TreeMap<String, Integer> mSpellCheckerLanguageToScript; static { // List of the supported languages and their associated script. We won't check @@ -72,56 +83,96 @@ public class ScriptUtils { */ public static boolean isLetterPartOfScript(final int codePoint, final int scriptId) { switch (scriptId) { - case SCRIPT_LATIN: - // Our supported latin script dictionaries (EFIGS) at the moment only include - // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode - // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF, - // so the below is a very efficient way to test for it. As for the 0-0x3F, it's - // excluded from isLetter anyway. - return codePoint <= 0x2AF && Character.isLetter(codePoint); - case SCRIPT_CYRILLIC: - // All Cyrillic characters are in the 400~52F block. There are some in the upper - // Unicode range, but they are archaic characters that are not used in modern - // Russian and are not used by our dictionary. - return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint); - case SCRIPT_GREEK: - // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the - // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters. - // Our dictionary also contains a few words with 0xF2; it would be best to check - // if that's correct, but a web search does return results for these words so - // they are probably okay. - return (codePoint >= 0x370 && codePoint <= 0x3FF) - || (codePoint >= 0x1F00 && codePoint <= 0x1FFF) - || codePoint == 0xF2; case SCRIPT_ARABIC: // Arabic letters can be in any of the following blocks: // Arabic U+0600..U+06FF - // Arabic Supplement U+0750..U+077F + // Arabic Supplement, Thaana U+0750..U+077F, U+0780..U+07BF // Arabic Extended-A U+08A0..U+08FF // Arabic Presentation Forms-A U+FB50..U+FDFF // Arabic Presentation Forms-B U+FE70..U+FEFF return (codePoint >= 0x600 && codePoint <= 0x6FF) - || (codePoint >= 0x750 && codePoint <= 0x77F) + || (codePoint >= 0x750 && codePoint <= 0x7BF) || (codePoint >= 0x8A0 && codePoint <= 0x8FF) || (codePoint >= 0xFB50 && codePoint <= 0xFDFF) || (codePoint >= 0xFE70 && codePoint <= 0xFEFF); - case SCRIPT_HEBREW: - // Hebrew letters are in the Hebrew unicode block, which spans from U+0590 to U+05FF, - // or in the Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the - // Hebrew part of that block, which is U+FB1D..U+FB4F. - return (codePoint >= 0x590 && codePoint <= 0x5FF - || codePoint >= 0xFB1D && codePoint <= 0xFB4F); case SCRIPT_ARMENIAN: // Armenian letters are in the Armenian unicode block, U+0530..U+058F and // Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the Armenian part // of that block, which is U+FB13..U+FB17. return (codePoint >= 0x530 && codePoint <= 0x58F || codePoint >= 0xFB13 && codePoint <= 0xFB17); + case SCRIPT_BENGALI: + // Bengali unicode block is U+0980..U+09FF + return (codePoint >= 0x980 && codePoint <= 0x9FF); + case SCRIPT_CYRILLIC: + // All Cyrillic characters are in the 400~52F block. There are some in the upper + // Unicode range, but they are archaic characters that are not used in modern + // Russian and are not used by our dictionary. + return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint); + case SCRIPT_DEVANAGARI: + // Devanagari unicode block is +0900..U+097F + return (codePoint >= 0x900 && codePoint <= 0x97F); case SCRIPT_GEORGIAN: // Georgian letters are in the Georgian unicode block, U+10A0..U+10FF, // or Georgian supplement block, U+2D00..U+2D2F return (codePoint >= 0x10A0 && codePoint <= 0x10FF || codePoint >= 0x2D00 && codePoint <= 0x2D2F); + case SCRIPT_GREEK: + // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the + // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters. + // Our dictionary also contains a few words with 0xF2; it would be best to check + // if that's correct, but a web search does return results for these words so + // they are probably okay. + return (codePoint >= 0x370 && codePoint <= 0x3FF) + || (codePoint >= 0x1F00 && codePoint <= 0x1FFF) + || codePoint == 0xF2; + case SCRIPT_HEBREW: + // Hebrew letters are in the Hebrew unicode block, which spans from U+0590 to U+05FF, + // or in the Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the + // Hebrew part of that block, which is U+FB1D..U+FB4F. + return (codePoint >= 0x590 && codePoint <= 0x5FF + || codePoint >= 0xFB1D && codePoint <= 0xFB4F); + case SCRIPT_KANNADA: + // Kannada unicode block is U+0C80..U+0CFF + return (codePoint >= 0xC80 && codePoint <= 0xCFF); + case SCRIPT_KHMER: + // Khmer letters are in unicode block U+1780..U+17FF, and the Khmer symbols block + // is U+19E0..U+19FF + return (codePoint >= 0x1780 && codePoint <= 0x17FF + || codePoint >= 0x19E0 && codePoint <= 0x19FF); + case SCRIPT_LAO: + // The Lao block is U+0E80..U+0EFF + return (codePoint >= 0xE80 && codePoint <= 0xEFF); + case SCRIPT_LATIN: + // Our supported latin script dictionaries (EFIGS) at the moment only include + // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode + // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF, + // so the below is a very efficient way to test for it. As for the 0-0x3F, it's + // excluded from isLetter anyway. + return codePoint <= 0x2AF && Character.isLetter(codePoint); + case SCRIPT_MALAYALAM: + // Malayalam unicode block is U+0D00..U+0D7F + return (codePoint >= 0xD00 && codePoint <= 0xD7F); + case SCRIPT_MYANMAR: + // Myanmar has three unicode blocks : + // Myanmar U+1000..U+109F + // Myanmar extended-A U+AA60..U+AA7F + // Myanmar extended-B U+A9E0..U+A9FF + return (codePoint >= 0x1000 && codePoint <= 0x109F + || codePoint >= 0xAA60 && codePoint <= 0xAA7F + || codePoint >= 0xA9E0 && codePoint <= 0xA9FF); + case SCRIPT_SINHALA: + // Sinhala unicode block is U+0D80..U+0DFF + return (codePoint >= 0xD80 && codePoint <= 0xDFF); + case SCRIPT_TAMIL: + // Tamil unicode block is U+0B80..U+0BFF + return (codePoint >= 0xB80 && codePoint <= 0xBFF); + case SCRIPT_TELUGU: + // Telugu unicode block is U+0C00..U+0C7F + return (codePoint >= 0xC00 && codePoint <= 0xC7F); + case SCRIPT_THAI: + // Thai unicode block is U+0E00..U+0E7F + return (codePoint >= 0xE00 && codePoint <= 0xE7F); case SCRIPT_UNKNOWN: return true; default: |