WordComposer.java revision 3708787fe91227083d2a1874fa41493d3bc9fe10
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 3923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * 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; 20887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector; 213708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 22887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.ArrayList; 24c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalardimport java.util.Arrays; 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class WordComposer { 308fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 31887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; 328fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public static final int NOT_A_COORDINATE = -1; 33887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 3427dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard // Storage for all the info about the current input. 3527dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard private static class CharacterStore { 3627dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard /** 3727dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard * The list of unicode values for each keystroke (including surrounding keys) 3827dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard */ 3927dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard ArrayList<int[]> mCodes; 4027dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard int[] mXCoordinates; 4127dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard int[] mYCoordinates; 4227dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard StringBuilder mTypedWord; 4327dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard CharacterStore() { 4427dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard final int N = BinaryDictionary.MAX_WORD_LENGTH; 4527dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCodes = new ArrayList<int[]>(N); 4627dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mTypedWord = new StringBuilder(N); 4727dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mXCoordinates = new int[N]; 4827dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mYCoordinates = new int[N]; 4927dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard } 5027dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard CharacterStore(final CharacterStore that) { 5127dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCodes = new ArrayList<int[]>(that.mCodes); 5227dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mTypedWord = new StringBuilder(that.mTypedWord); 5327dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mXCoordinates = Arrays.copyOf(that.mXCoordinates, that.mXCoordinates.length); 5427dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mYCoordinates = Arrays.copyOf(that.mYCoordinates, that.mYCoordinates.length); 5527dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard } 5627dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard void reset() { 5727dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard // For better performance than creating a new character store. 5827dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCodes.clear(); 5927dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mTypedWord.setLength(0); 6027dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard } 6127dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard } 628fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 63c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard // The currently typing word. May not be null. 6427dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard private CharacterStore mCurrentWord; 65c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard // The information being kept for resuming suggestion. May be null if wiped. 66c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard private CharacterStore mWordKeptForSuggestionResuming; 67117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard // An auto-correction for this word out of the dictionary. 68117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard private CharSequence mAutoCorrection; 694a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 704a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 711c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 721c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani private boolean mAutoCapitalized; 73c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard // Cache this value for performance 74117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard private int mTrailingSingleQuotesCount; 75c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 770b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether the user chose to capitalize the first char of the word. 78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 790b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa private boolean mIsFirstCharCapitalized; 80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 81979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 8227dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord = new CharacterStore(); 83c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mWordKeptForSuggestionResuming = null; 84117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 85117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = null; 86923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 87923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 88f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok public WordComposer(WordComposer source) { 899fbfd5877305ed19a20663630b498b6b3fdae942satok init(source); 909fbfd5877305ed19a20663630b498b6b3fdae942satok } 919fbfd5877305ed19a20663630b498b6b3fdae942satok 929fbfd5877305ed19a20663630b498b6b3fdae942satok public void init(WordComposer source) { 9327dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord = new CharacterStore(source.mCurrentWord); 94c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mWordKeptForSuggestionResuming = source.mWordKeptForSuggestionResuming; 95ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mCapsCount = source.mCapsCount; 96ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; 97ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mAutoCapitalized = source.mAutoCapitalized; 98117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; 99117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = null; 100979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 101979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 10627dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord.reset(); 107c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mWordKeptForSuggestionResuming = null; 1084a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 109ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 110117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 111117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = null; 112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 118ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka public final int size() { 11927dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard return mCurrentWord.mTypedWord.length(); 120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 122196d82cdd740580ed79d801483dbc282be85d076Jean Chalard public final boolean isComposingWord() { 123196d82cdd740580ed79d801483dbc282be85d076Jean Chalard return size() > 0; 124196d82cdd740580ed79d801483dbc282be85d076Jean Chalard } 125196d82cdd740580ed79d801483dbc282be85d076Jean Chalard 126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the codes at a particular position in the word. 128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param index the position in the word 129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the unicode for the pressed and surrounding keys 130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public int[] getCodesAt(int index) { 13227dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard return mCurrentWord.mCodes.get(index); 133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1358fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public int[] getXCoordinates() { 13627dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard return mCurrentWord.mXCoordinates; 1378fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1388fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 1398fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public int[] getYCoordinates() { 14027dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard return mCurrentWord.mYCoordinates; 1418fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1428fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 143ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { 144ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (index == 0) return Character.isUpperCase(codePoint); 145436a645ea837d36f7e0f81948d343fa6e166f33aTadashi G. Takaoka return previous && !Character.isUpperCase(codePoint); 146ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka } 147ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka 148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of 150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. 151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param codes the array of unicode values 152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 1538fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public void add(int primaryCode, int[] codes, int x, int y) { 154ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int newIndex = size(); 15527dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord.mTypedWord.append((char) primaryCode); 156231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani correctPrimaryJuxtapos(primaryCode, codes); 15727dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord.mCodes.add(codes); 158ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { 15927dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord.mXCoordinates[newIndex] = x; 16027dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord.mYCoordinates[newIndex] = y; 1618fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 162ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = isFirstCharCapitalized( 163ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka newIndex, primaryCode, mIsFirstCharCapitalized); 164ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(primaryCode)) mCapsCount++; 165117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) { 166117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 167117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } else { 168117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 169117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 170117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = null; 171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 1746b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Internal method to retrieve reasonable proximity info for a character. 1756b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 1763708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka private void addKeyInfo(final int codePoint, final Keyboard keyboard, 1776b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final KeyDetector keyDetector) { 1786b1f500da451de56932a8b2a99c63857994ece85Jean Chalard for (final Key key : keyboard.mKeys) { 1796b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (key.mCode == codePoint) { 1806b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int x = key.mX + key.mWidth / 2; 1816b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int y = key.mY + key.mHeight / 2; 1826b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int[] codes = keyDetector.newCodeArray(); 183e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka keyDetector.getKeyAndNearbyCodes(x, y, codes); 1846b1f500da451de56932a8b2a99c63857994ece85Jean Chalard add(codePoint, codes, x, y); 1856b1f500da451de56932a8b2a99c63857994ece85Jean Chalard return; 1866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1876b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1886b1f500da451de56932a8b2a99c63857994ece85Jean Chalard add(codePoint, new int[] { codePoint }, 1896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); 1906b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1916b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 1926b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 1936b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Set the currently composing word to the one passed as an argument. 1946b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. 1956b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 1963708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka public void setComposingWord(final CharSequence word, final Keyboard keyboard, 1976b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final KeyDetector keyDetector) { 1986b1f500da451de56932a8b2a99c63857994ece85Jean Chalard reset(); 1996b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int length = word.length(); 2006b1f500da451de56932a8b2a99c63857994ece85Jean Chalard for (int i = 0; i < length; ++i) { 2016b1f500da451de56932a8b2a99c63857994ece85Jean Chalard int codePoint = word.charAt(i); 2026b1f500da451de56932a8b2a99c63857994ece85Jean Chalard addKeyInfo(codePoint, keyboard, keyDetector); 2036b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 204117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = null; 2056b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 2066b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 2076b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 2086b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Shortcut for the above method, this will create a new KeyDetector for the passed keyboard. 2096b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 2103708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka public void setComposingWord(final CharSequence word, final Keyboard keyboard) { 2116b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final KeyDetector keyDetector = new KeyDetector(0); 2126b1f500da451de56932a8b2a99c63857994ece85Jean Chalard keyDetector.setKeyboard(keyboard, 0, 0); 2136b1f500da451de56932a8b2a99c63857994ece85Jean Chalard keyDetector.setProximityCorrectionEnabled(true); 2146b1f500da451de56932a8b2a99c63857994ece85Jean Chalard keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); 2156b1f500da451de56932a8b2a99c63857994ece85Jean Chalard setComposingWord(word, keyboard, keyDetector); 2166b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 2176b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 2186b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 219231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * Swaps the first and second values in the codes array if the primary code is not the first 220231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * value in the array but the second. This happens when the preferred key is not the key that 221231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * the user released the finger on. 222231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param primaryCode the preferred character 223231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param codes array of codes based on distance from touch point 224231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani */ 2258fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) { 226231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes.length < 2) return; 227231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { 228231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[1] = codes[0]; 229231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[0] = primaryCode; 230231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 231231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 232231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani 233231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani /** 234923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Delete the last keystroke as a result of hitting backspace. 235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 236923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void deleteLast() { 237ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int size = size(); 238ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size > 0) { 239ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int lastPos = size - 1; 24027dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard char lastChar = mCurrentWord.mTypedWord.charAt(lastPos); 24127dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord.mCodes.remove(lastPos); 24227dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard mCurrentWord.mTypedWord.deleteCharAt(lastPos); 243ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(lastChar)) mCapsCount--; 244d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka } 245ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size() == 0) { 246ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 247117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 248117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard if (mTrailingSingleQuotesCount > 0) { 249117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard --mTrailingSingleQuotesCount; 250c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } else { 25127dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard for (int i = mCurrentWord.mTypedWord.length() - 1; i >= 0; --i) { 25227dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard if (Keyboard.CODE_SINGLE_QUOTE != mCurrentWord.mTypedWord.codePointAt(i)) break; 253117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 254117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 2558fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 256117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = null; 257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 261117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * @return the word that was typed so far. Never returns null. 262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 2635c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard public String getTypedWord() { 26427dff63833bf1c8a36eed826746de3c6725d8423Jean Chalard return mCurrentWord.mTypedWord.toString(); 265923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 266923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 267923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Whether or not the user typed a capital letter as the first letter in the word 269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 2710b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isFirstCharCapitalized() { 2720b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return mIsFirstCharCapitalized; 273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2740b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 275117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard public int trailingSingleQuotesCount() { 276117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard return mTrailingSingleQuotesCount; 277c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } 278c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 2790b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 2800b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 2810b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 2820b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 2830b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 2840b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return (mCapsCount > 0) && (mCapsCount == size()); 2850b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 2860b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 287923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 2884a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 2894a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 2904a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 2914a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 2924a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 2931c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 2941c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 2951c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Saves the reason why the word is capitalized - whether it was automatic or 2961c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * due to the user hitting shift in the middle of a sentence. 2971c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @param auto whether it was an automatic capitalization due to start of sentence 2981c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 2991c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public void setAutoCapitalized(boolean auto) { 3001c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani mAutoCapitalized = auto; 3011c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 3021c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 3031c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 3041c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 3051c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 3061c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 3071c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public boolean isAutoCapitalized() { 3081c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani return mAutoCapitalized; 3091c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 310117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 311117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 312117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * Sets the auto-correction for this word. 313117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 314117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard public void setAutoCorrection(final CharSequence correction) { 315117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = correction; 316117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 317117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 318117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 319117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * Remove any auto-correction that may have been set. 320117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 321117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard public void deleteAutoCorrection() { 322117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mAutoCorrection = null; 323117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 324117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 325117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 326f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard * @return the auto-correction for this word, or null if none. 327117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 328117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard public CharSequence getAutoCorrectionOrNull() { 329117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard return mAutoCorrection; 330117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 331c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 332c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard // TODO: pass the information about what was committed and how. Was it an auto-correction? 333c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard // Was it a completion? Was is what the user typed? 334c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard public void onCommitWord() { 335c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mWordKeptForSuggestionResuming = mCurrentWord; 336c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard // TODO: improve performance by swapping buffers instead of creating a new object. 337c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mCurrentWord = new CharacterStore(); 338c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 339c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 340c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard public boolean hasWordKeptForSuggestionResuming() { 341c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard return null != mWordKeptForSuggestionResuming; 342c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 343c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 344c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard public void resumeSuggestionOnKeptWord() { 345c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mCurrentWord = mWordKeptForSuggestionResuming; 346c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mWordKeptForSuggestionResuming = null; 347c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 349