WordComposer.java revision 5fa2202e36a84bd5808fa10ca25c9179acb1b173
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 30fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License. 68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at 70fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 90fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and 148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 196b1f500da451de56932a8b2a99c63857994ece85Jean Chalardimport com.android.inputmethod.keyboard.Key; 203708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 215fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalardimport com.android.inputmethod.latin.utils.StringUtils; 22887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 23c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalardimport java.util.Arrays; 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well 27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 28a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class WordComposer { 2996b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH; 300e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 318fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 32adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_OFF = 0; 33adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // 1 is shift bit, 2 is caps bit, 4 is auto bit but this is just a convention as these bits 34adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // aren't used anywhere in the code 35adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_MANUAL_SHIFTED = 0x1; 36adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_MANUAL_SHIFT_LOCKED = 0x3; 37adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_AUTO_SHIFTED = 0x5; 38adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_AUTO_SHIFT_LOCKED = 0x7; 39adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard 405fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // An array of code points representing the characters typed so far. 415fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // The array is limited to MAX_WORD_LENGTH code points, but mTypedWord extends past that 425fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // and mCodePointSize can go past that. If mCodePointSize is greater than MAX_WORD_LENGTH, 435fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // this just does not contain the associated code points past MAX_WORD_LENGTH. 4401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok private int[] mPrimaryKeyCodes; 4596b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH); 465fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // This is the typed word, as a StringBuilder. This has the same contents as mPrimaryKeyCodes 475fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // but under a StringBuilder representation for ease of use, depending on what is more useful 485fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // at any given time. However this is not limited in size, while mPrimaryKeyCodes is limited 495fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // to MAX_WORD_LENGTH code points. 506b4ce58fc6216b9befd0567b56522ee32f2471a2Tadashi G. Takaoka private final StringBuilder mTypedWord; 51bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String mAutoCorrection; 524b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard private boolean mIsResumed; 53d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka private boolean mIsBatchMode; 54d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // A memory of the last rejected batch mode suggestion, if any. This goes like this: the user 55d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // gestures a word, is displeased with the results and hits backspace, then gestures again. 56d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // At the very least we should avoid re-suggesting the same thing, and to do that we memorize 57d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // the rejected suggestion in this variable. 58d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // TODO: this should be done in a comprehensive way by the User History feature instead of 59d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // as an ad-hockery here. 60d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard private String mRejectedBatchModeSuggestion; 614a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 62be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard // Cache these values for performance 634a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 64e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard private int mDigitsCount; 65adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard private int mCapitalizedMode; 66117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard private int mTrailingSingleQuotesCount; 675fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // This is the number of code points entered so far. This is not limited to MAX_WORD_LENGTH. 685fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // In general, this contains the size of mPrimaryKeyCodes, except when this is greater than 695fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // MAX_WORD_LENGTH in which case mPrimaryKeyCodes only contain the first MAX_WORD_LENGTH 705fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // code points. 7101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok private int mCodePointSize; 726a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard private int mCursorPositionWithinWord; 73c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 750b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether the user chose to capitalize the first char of the word. 76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 770b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa private boolean mIsFirstCharCapitalized; 78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 79979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 8096b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa mPrimaryKeyCodes = new int[MAX_WORD_LENGTH]; 8196b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa mTypedWord = new StringBuilder(MAX_WORD_LENGTH); 82be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 83117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 844b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 85d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = false; 866a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 87d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 8801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 90923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 91bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public WordComposer(final WordComposer source) { 9201ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length); 93be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord = new StringBuilder(source.mTypedWord); 9471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka mInputPointers.copy(source.mInputPointers); 95ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mCapsCount = source.mCapsCount; 96e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard mDigitsCount = source.mDigitsCount; 97ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; 98adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mCapitalizedMode = source.mCapitalizedMode; 99117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; 1004b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = source.mIsResumed; 101d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = source.mIsBatchMode; 1026a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = source.mCursorPositionWithinWord; 103d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = source.mRejectedBatchModeSuggestion; 10401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 105979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 106979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 111be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 112be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 1134a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 114e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard mDigitsCount = 0; 115ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 116117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 1174b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 118d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = false; 1196a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 120d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 12101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 12201ab7c8b59a7f12862fbd95fb252e56719f1757fsatok } 12301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok 124e55c23e4b0b8d9d66349a3b275d0fa1540d7450aKen Wakasa private final void refreshSize() { 12501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mCodePointSize = mTypedWord.codePointCount(0, mTypedWord.length()); 126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 132ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka public final int size() { 13301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return mCodePointSize; 134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 136196d82cdd740580ed79d801483dbc282be85d076Jean Chalard public final boolean isComposingWord() { 13701ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return size() > 0; 138196d82cdd740580ed79d801483dbc282be85d076Jean Chalard } 139196d82cdd740580ed79d801483dbc282be85d076Jean Chalard 1409611b281e18ac71d825ff5bc771a111423772cb3satok // TODO: make sure that the index should not exceed MAX_WORD_LENGTH 14101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok public int getCodeAt(int index) { 14296b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa if (index >= MAX_WORD_LENGTH) { 1439611b281e18ac71d825ff5bc771a111423772cb3satok return -1; 1449611b281e18ac71d825ff5bc771a111423772cb3satok } 14501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return mPrimaryKeyCodes[index]; 146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1480e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard public int getCodeBeforeCursor() { 1490e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (mCursorPositionWithinWord < 1 || mCursorPositionWithinWord > mPrimaryKeyCodes.length) { 1500e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard return Constants.NOT_A_CODE; 1510e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 1520e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard return mPrimaryKeyCodes[mCursorPositionWithinWord - 1]; 1530e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 1540e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard 15571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka public InputPointers getInputPointers() { 15671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka return mInputPointers; 1578fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1588fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 159bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private static boolean isFirstCharCapitalized(final int index, final int codePoint, 160bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final boolean previous) { 161ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (index == 0) return Character.isUpperCase(codePoint); 162436a645ea837d36f7e0f81948d343fa6e166f33aTadashi G. Takaoka return previous && !Character.isUpperCase(codePoint); 163ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka } 164ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka 165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 166c61cd79229b1871d0f603a23389695d7f7751e66Tadashi G. Takaoka * Add a new keystroke, with the pressed key's code point with the touch point coordinates. 167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 168bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void add(final int primaryCode, final int keyX, final int keyY) { 16901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final int newIndex = size(); 1709159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard mTypedWord.appendCodePoint(primaryCode); 17101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 1726a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = mCodePointSize; 17396b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa if (newIndex < MAX_WORD_LENGTH) { 174240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mPrimaryKeyCodes[newIndex] = primaryCode >= Constants.CODE_SPACE 17567094f5bdece00994f70c6f1fa9a6ff7b8f3c3c1satok ? Character.toLowerCase(primaryCode) : primaryCode; 176eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // In the batch input mode, the {@code mInputPointers} holds batch input points and 177eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // shouldn't be overridden by the "typed key" coordinates 178eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // (See {@link #setBatchInputWord}). 179eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (!mIsBatchMode) { 180eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // TODO: Set correct pointer id and time 181eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0); 182eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1838fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 184ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = isFirstCharCapitalized( 185ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka newIndex, primaryCode, mIsFirstCharCapitalized); 186ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(primaryCode)) mCapsCount++; 187e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard if (Character.isDigit(primaryCode)) mDigitsCount++; 188240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_SINGLE_QUOTE == primaryCode) { 189117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 190117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } else { 191117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 192117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 193be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 195923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1966a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard public void setCursorPositionWithinWord(final int posWithinWord) { 1976a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = posWithinWord; 1986a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 1996a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 2000e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard public boolean isCursorFrontOrMiddleOfComposingWord() { 2010e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (DBG && mCursorPositionWithinWord > mCodePointSize) { 2020e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard throw new RuntimeException("Wrong cursor position : " + mCursorPositionWithinWord 2030e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard + "in a word of size " + mCodePointSize); 2040e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 2050e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard return mCursorPositionWithinWord != mCodePointSize; 2066a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 2076a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 208f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard /** 209f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * When the cursor is moved by the user, we need to update its position. 210f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * If it falls inside the currently composing word, we don't reset the composition, and 211f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * only update the cursor position. 212f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * 213f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * @param expectedMoveAmount How many java chars to move the cursor. Negative values move 214f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * the cursor backward, positive values move the cursor forward. 215f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * @return true if the cursor is still inside the composing word, false otherwise. 216f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard */ 217f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) { 218f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard int actualMoveAmountWithinWord = 0; 219f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard int cursorPos = mCursorPositionWithinWord; 2205fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard final int[] codePoints; 2215fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard if (mCodePointSize >= MAX_WORD_LENGTH) { 2225fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // If we have more than MAX_WORD_LENGTH characters, we don't have everything inside 2235fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // mPrimaryKeyCodes. This should be rare enough that we can afford to just compute 2245fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // the array on the fly when this happens. 2255fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard codePoints = StringUtils.toCodePointArray(mTypedWord.toString()); 2265fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard } else { 2275fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard codePoints = mPrimaryKeyCodes; 2285fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard } 229f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard if (expectedMoveAmount >= 0) { 230f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // Moving the cursor forward for the expected amount or until the end of the word has 231f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // been reached, whichever comes first. 232f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard while (actualMoveAmountWithinWord < expectedMoveAmount && cursorPos < mCodePointSize) { 2335fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard actualMoveAmountWithinWord += Character.charCount(codePoints[cursorPos]); 234f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard ++cursorPos; 235f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 236f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } else { 237f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // Moving the cursor backward for the expected amount or until the start of the word 238f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // has been reached, whichever comes first. 239f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard while (actualMoveAmountWithinWord > expectedMoveAmount && cursorPos > 0) { 240f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard --cursorPos; 2415fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard actualMoveAmountWithinWord -= Character.charCount(codePoints[cursorPos]); 242f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 243f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 244f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // If the actual and expected amounts differ, we crossed the start or the end of the word 245f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // so the result would not be inside the composing word. 246f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard if (actualMoveAmountWithinWord != expectedMoveAmount) return false; 247f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard mCursorPositionWithinWord = cursorPos; 248f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard return true; 249f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 250f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard 251bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setBatchInputPointers(final InputPointers batchPointers) { 252eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mInputPointers.set(batchPointers); 253d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = true; 254d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka } 255d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka 256bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setBatchInputWord(final String word) { 257eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang reset(); 258eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mIsBatchMode = true; 259eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int length = word.length(); 260eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { 261eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int codePoint = Character.codePointAt(word, i); 262eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // We don't want to override the batch input points that are held in mInputPointers 263eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // (See {@link #add(int,int,int)}). 264ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka add(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 265eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 266eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 267eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 269244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka * Add a dummy key by retrieving reasonable coordinates 2706b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 2715701a6647f43eaa1eb4cb84c9c063d8440fe24ceTadashi G. Takaoka public void addKeyInfo(final int codePoint, final Keyboard keyboard) { 272d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka final int x, y; 273d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka final Key key; 274d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka if (keyboard != null && (key = keyboard.getKey(codePoint)) != null) { 275d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka x = key.mX + key.mWidth / 2; 276d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka y = key.mY + key.mHeight / 2; 277d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka } else { 278d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka x = Constants.NOT_A_COORDINATE; 279d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka y = Constants.NOT_A_COORDINATE; 2806b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 281d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka add(codePoint, x, y); 2826b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 2836b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 2846b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 2856b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Set the currently composing word to the one passed as an argument. 2866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. 2876b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 288a492790982c6d7df62f66344db30b31995800e1bJean Chalard public void setComposingWord(final CharSequence word, final Keyboard keyboard) { 2896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard reset(); 2906b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int length = word.length(); 2919159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { 292d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka final int codePoint = Character.codePointAt(word, i); 293a492790982c6d7df62f66344db30b31995800e1bJean Chalard addKeyInfo(codePoint, keyboard); 2946b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 2954b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = true; 2966b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 2976b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 2986b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Delete the last keystroke as a result of hitting backspace. 300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void deleteLast() { 30201ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final int size = size(); 303ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size > 0) { 3049159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs 3059159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard final int stringBuilderLength = mTypedWord.length(); 3069159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard if (stringBuilderLength < size) { 3079159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard throw new RuntimeException( 3089159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard "In WordComposer: mCodes and mTypedWords have non-matching lengths"); 3099159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard } 3109159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard final int lastChar = mTypedWord.codePointBefore(stringBuilderLength); 3119159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard if (Character.isSupplementaryCodePoint(lastChar)) { 3129159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength); 3139159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard } else { 3149159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard mTypedWord.deleteCharAt(stringBuilderLength - 1); 3159159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard } 316ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(lastChar)) mCapsCount--; 317e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard if (Character.isDigit(lastChar)) mDigitsCount--; 31801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 319d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka } 3209159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard // We may have deleted the last one. 32101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok if (0 == size()) { 322ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 323117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 324117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard if (mTrailingSingleQuotesCount > 0) { 325117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard --mTrailingSingleQuotesCount; 326c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } else { 327825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard int i = mTypedWord.length(); 328825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard while (i > 0) { 329825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard i = mTypedWord.offsetByCodePoints(i, -1); 330240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; 331117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 332117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 3338fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 3346a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = mCodePointSize; 335be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 337923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 338923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 340117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * @return the word that was typed so far. Never returns null. 341923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 3425c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard public String getTypedWord() { 343be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mTypedWord.toString(); 344923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 346923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 347923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Whether or not the user typed a capital letter as the first letter in the word 348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 349923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 3500b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isFirstCharCapitalized() { 3510b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return mIsFirstCharCapitalized; 352923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 3530b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 354117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard public int trailingSingleQuotesCount() { 355117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard return mTrailingSingleQuotesCount; 356c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } 357c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 3580b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 3590b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 3600b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 3610b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 3620b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 363ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard if (size() <= 1) { 364ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED 365ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED; 366ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard } else { 367ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard return mCapsCount == size(); 368ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard } 3691eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard } 3701eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard 3711eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard public boolean wasShiftedNoLock() { 3721eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFTED 3731eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFTED; 3740b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 3750b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 376923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 3774a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 3784a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 3794a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 3804a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 3814a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 3821c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 3830fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard /** 384e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard * Returns true if we have digits in the composing word. 385e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard */ 386e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard public boolean hasDigits() { 387e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard return mDigitsCount > 0; 388e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard } 389e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard 390e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard /** 391adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * Saves the caps mode at the start of composing. 392adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * 393adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * WordComposer needs to know about this for several reasons. The first is, we need to know 394adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * after the fact what the reason was, to register the correct form into the user history 395adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * dictionary: if the word was automatically capitalized, we should insert it in all-lower 396adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * case but if it's a manual pressing of shift, then it should be inserted as is. 397adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * Also, batch input needs to know about the current caps mode to display correctly 398adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * capitalized suggestions. 399adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * @param mode the mode at the time of start 4001c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 401adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public void setCapitalizedModeAtStartComposingTime(final int mode) { 402adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mCapitalizedMode = mode; 4031c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 4041c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 4051c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 4061c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 4071c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 4081c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 409adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public boolean wasAutoCapitalized() { 410adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED 411adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard || mCapitalizedMode == CAPS_MODE_AUTO_SHIFTED; 4121c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 413117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 414117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 415117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * Sets the auto-correction for this word. 416117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 417bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setAutoCorrection(final String correction) { 418be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = correction; 419117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 420117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 421117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 422f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard * @return the auto-correction for this word, or null if none. 423117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 424bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public String getAutoCorrectionOrNull() { 425be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mAutoCorrection; 426117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 427c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 4284b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard /** 4294b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard * @return whether we started composing this word by resuming suggestion on an existing string 4304b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard */ 4314b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard public boolean isResumed() { 4324b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard return mIsResumed; 4334b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard } 4344b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard 435267563d1bb4d8091293fbd8774f0f95ef59f03c4Jean Chalard // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. 43666bb563535dbe3672f99f75bd71763a551444867Jean Chalard public LastComposedWord commitWord(final int type, final String committedWord, 437bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String separatorString, final String prevWord) { 4389271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK 4399271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate 4409271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // the last composed word to ensure this does not happen. 44101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final int[] primaryKeyCodes = mPrimaryKeyCodes; 44296b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa mPrimaryKeyCodes = new int[MAX_WORD_LENGTH]; 44301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, 444a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mInputPointers, mTypedWord.toString(), committedWord, separatorString, 445b6b7f5e39e9ea1bf9a05203c536327a6be7e7214Jean Chalard prevWord, mCapitalizedMode); 44671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka mInputPointers.reset(); 4479271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD 4489271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { 449449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard lastComposedWord.deactivate(); 450449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard } 451e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mCapsCount = 0; 452e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard mDigitsCount = 0; 453e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mIsBatchMode = false; 454be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 4558914555776a4d3dfd6afc4926a69169ca1c82a0eJean Chalard mCodePointSize = 0; 4562a37fb9d30848aee42757546e8478cb7a9e45bc6Jean Chalard mTrailingSingleQuotesCount = 0; 457e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mIsFirstCharCapitalized = false; 4588914555776a4d3dfd6afc4926a69169ca1c82a0eJean Chalard mCapitalizedMode = CAPS_MODE_OFF; 45901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 460be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 4616a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 4624b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 463d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 4641f8fc62ccb5018716457dc309ab11ad3e1506ad1Jean Chalard return lastComposedWord; 465c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 466c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 4672712f23acbb197af3b125da4cc47108e71b7446dJean Chalard public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { 46801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; 46971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka mInputPointers.set(lastComposedWord.mInputPointers); 470be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 471be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.append(lastComposedWord.mTypedWord); 47201ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 473b6b7f5e39e9ea1bf9a05203c536327a6be7e7214Jean Chalard mCapitalizedMode = lastComposedWord.mCapitalizedMode; 474cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. 4756a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = mCodePointSize; 476d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 4774b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = true; 4789e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard } 479d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka 480d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka public boolean isBatchMode() { 481d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka return mIsBatchMode; 482d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka } 483d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard 484d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard public void setRejectedBatchModeSuggestion(final String rejectedSuggestion) { 485d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = rejectedSuggestion; 486d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard } 487d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard 488d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard public String getRejectedBatchModeSuggestion() { 489d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard return mRejectedBatchModeSuggestion; 490d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard } 491923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 492