1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.inputmethod.latin; 18 19 import java.util.ArrayList; 20 21 /** 22 * A place to store the currently composing word with information such as adjacent key codes as well 23 */ 24 public class WordComposer { 25 /** 26 * The list of unicode values for each keystroke (including surrounding keys) 27 */ 28 private final ArrayList<int[]> mCodes; 29 30 /** 31 * The word chosen from the candidate list, until it is committed. 32 */ 33 private String mPreferredWord; 34 35 private final StringBuilder mTypedWord; 36 37 private int mCapsCount; 38 39 private boolean mAutoCapitalized; 40 41 /** 42 * Whether the user chose to capitalize the first char of the word. 43 */ 44 private boolean mIsFirstCharCapitalized; 45 46 public WordComposer() { 47 mCodes = new ArrayList<int[]>(12); 48 mTypedWord = new StringBuilder(20); 49 } 50 51 WordComposer(WordComposer copy) { 52 mCodes = new ArrayList<int[]>(copy.mCodes); 53 mPreferredWord = copy.mPreferredWord; 54 mTypedWord = new StringBuilder(copy.mTypedWord); 55 mCapsCount = copy.mCapsCount; 56 mAutoCapitalized = copy.mAutoCapitalized; 57 mIsFirstCharCapitalized = copy.mIsFirstCharCapitalized; 58 } 59 60 /** 61 * Clear out the keys registered so far. 62 */ 63 public void reset() { 64 mCodes.clear(); 65 mIsFirstCharCapitalized = false; 66 mPreferredWord = null; 67 mTypedWord.setLength(0); 68 mCapsCount = 0; 69 } 70 71 /** 72 * Number of keystrokes in the composing word. 73 * @return the number of keystrokes 74 */ 75 public int size() { 76 return mCodes.size(); 77 } 78 79 /** 80 * Returns the codes at a particular position in the word. 81 * @param index the position in the word 82 * @return the unicode for the pressed and surrounding keys 83 */ 84 public int[] getCodesAt(int index) { 85 return mCodes.get(index); 86 } 87 88 /** 89 * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of 90 * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. 91 * @param codes the array of unicode values 92 */ 93 public void add(int primaryCode, int[] codes) { 94 mTypedWord.append((char) primaryCode); 95 correctPrimaryJuxtapos(primaryCode, codes); 96 mCodes.add(codes); 97 if (Character.isUpperCase((char) primaryCode)) mCapsCount++; 98 } 99 100 /** 101 * Swaps the first and second values in the codes array if the primary code is not the first 102 * value in the array but the second. This happens when the preferred key is not the key that 103 * the user released the finger on. 104 * @param primaryCode the preferred character 105 * @param codes array of codes based on distance from touch point 106 */ 107 private void correctPrimaryJuxtapos(int primaryCode, int[] codes) { 108 if (codes.length < 2) return; 109 if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { 110 codes[1] = codes[0]; 111 codes[0] = primaryCode; 112 } 113 } 114 115 /** 116 * Delete the last keystroke as a result of hitting backspace. 117 */ 118 public void deleteLast() { 119 final int codesSize = mCodes.size(); 120 if (codesSize > 0) { 121 mCodes.remove(codesSize - 1); 122 final int lastPos = mTypedWord.length() - 1; 123 char last = mTypedWord.charAt(lastPos); 124 mTypedWord.deleteCharAt(lastPos); 125 if (Character.isUpperCase(last)) mCapsCount--; 126 } 127 } 128 129 /** 130 * Returns the word as it was typed, without any correction applied. 131 * @return the word that was typed so far 132 */ 133 public CharSequence getTypedWord() { 134 int wordSize = mCodes.size(); 135 if (wordSize == 0) { 136 return null; 137 } 138 return mTypedWord; 139 } 140 141 public void setFirstCharCapitalized(boolean capitalized) { 142 mIsFirstCharCapitalized = capitalized; 143 } 144 145 /** 146 * Whether or not the user typed a capital letter as the first letter in the word 147 * @return capitalization preference 148 */ 149 public boolean isFirstCharCapitalized() { 150 return mIsFirstCharCapitalized; 151 } 152 153 /** 154 * Whether or not all of the user typed chars are upper case 155 * @return true if all user typed chars are upper case, false otherwise 156 */ 157 public boolean isAllUpperCase() { 158 return (mCapsCount > 0) && (mCapsCount == size()); 159 } 160 161 /** 162 * Stores the user's selected word, before it is actually committed to the text field. 163 * @param preferred 164 */ 165 public void setPreferredWord(String preferred) { 166 mPreferredWord = preferred; 167 } 168 169 /** 170 * Return the word chosen by the user, or the typed word if no other word was chosen. 171 * @return the preferred word 172 */ 173 public CharSequence getPreferredWord() { 174 return mPreferredWord != null ? mPreferredWord : getTypedWord(); 175 } 176 177 /** 178 * Returns true if more than one character is upper case, otherwise returns false. 179 */ 180 public boolean isMostlyCaps() { 181 return mCapsCount > 1; 182 } 183 184 /** 185 * Saves the reason why the word is capitalized - whether it was automatic or 186 * due to the user hitting shift in the middle of a sentence. 187 * @param auto whether it was an automatic capitalization due to start of sentence 188 */ 189 public void setAutoCapitalized(boolean auto) { 190 mAutoCapitalized = auto; 191 } 192 193 /** 194 * Returns whether the word was automatically capitalized. 195 * @return whether the word was automatically capitalized 196 */ 197 public boolean isAutoCapitalized() { 198 return mAutoCapitalized; 199 } 200 } 201