WordComposer.java revision 0b4ae1f578e768eec4ada90aeb81d11acb10eb2e
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 19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.ArrayList; 20923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well 23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class WordComposer { 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * The list of unicode values for each keystroke (including surrounding keys) 27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 28d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka private final ArrayList<int[]> mCodes; 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * The word chosen from the candidate list, until it is committed. 32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private String mPreferredWord; 34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 35d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka private final StringBuilder mTypedWord; 364a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 374a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 381c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 391c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani private boolean mAutoCapitalized; 40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 420b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether the user chose to capitalize the first char of the word. 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 440b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa private boolean mIsFirstCharCapitalized; 45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 46979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mCodes = new ArrayList<int[]>(12); 48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mTypedWord = new StringBuilder(20); 49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 51979f8690967ff5409fe18f5085858ccdb8e0ccf1satok WordComposer(WordComposer copy) { 52525141a402ac9a3fb3495cb069ad25b9ba1fc970satok mCodes = new ArrayList<int[]>(copy.mCodes); 53979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mPreferredWord = copy.mPreferredWord; 54979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mTypedWord = new StringBuilder(copy.mTypedWord); 55979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mCapsCount = copy.mCapsCount; 56979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mAutoCapitalized = copy.mAutoCapitalized; 570b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa mIsFirstCharCapitalized = copy.mIsFirstCharCapitalized; 58979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 59979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mCodes.clear(); 650b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa mIsFirstCharCapitalized = false; 66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreferredWord = null; 67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mTypedWord.setLength(0); 684a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 70923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 71923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 72923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 73923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public int size() { 76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return mCodes.size(); 77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the codes at a particular position in the word. 81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param index the position in the word 82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the unicode for the pressed and surrounding keys 83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 84923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public int[] getCodesAt(int index) { 85923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return mCodes.get(index); 86923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 87923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 88923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of 90923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. 91923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param codes the array of unicode values 92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void add(int primaryCode, int[] codes) { 94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mTypedWord.append((char) primaryCode); 95231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani correctPrimaryJuxtapos(primaryCode, codes); 96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mCodes.add(codes); 974a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani if (Character.isUpperCase((char) primaryCode)) mCapsCount++; 98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 99923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 101231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * Swaps the first and second values in the codes array if the primary code is not the first 102231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * value in the array but the second. This happens when the preferred key is not the key that 103231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * the user released the finger on. 104231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param primaryCode the preferred character 105231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param codes array of codes based on distance from touch point 106231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani */ 107231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani private void correctPrimaryJuxtapos(int primaryCode, int[] codes) { 108231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes.length < 2) return; 109231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { 110231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[1] = codes[0]; 111231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[0] = primaryCode; 112231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 113231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 114231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani 115231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani /** 116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Delete the last keystroke as a result of hitting backspace. 117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void deleteLast() { 119d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka final int codesSize = mCodes.size(); 120d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka if (codesSize > 0) { 121d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka mCodes.remove(codesSize - 1); 122d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka final int lastPos = mTypedWord.length() - 1; 123d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka char last = mTypedWord.charAt(lastPos); 124d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka mTypedWord.deleteCharAt(lastPos); 125d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka if (Character.isUpperCase(last)) mCapsCount--; 126d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka } 127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the word that was typed so far 132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CharSequence getTypedWord() { 134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int wordSize = mCodes.size(); 135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (wordSize == 0) { 136923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return null; 137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return mTypedWord; 139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1410b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public void setFirstCharCapitalized(boolean capitalized) { 1420b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa mIsFirstCharCapitalized = capitalized; 143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Whether or not the user typed a capital letter as the first letter in the word 147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 1490b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isFirstCharCapitalized() { 1500b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return mIsFirstCharCapitalized; 151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1520b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 1530b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 1540b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 1550b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 1560b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 1570b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 1580b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return (mCapsCount > 0) && (mCapsCount == size()); 1590b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 1600b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Stores the user's selected word, before it is actually committed to the text field. 163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param preferred 164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void setPreferredWord(String preferred) { 166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreferredWord = preferred; 167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Return the word chosen by the user, or the typed word if no other word was chosen. 171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the preferred word 172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CharSequence getPreferredWord() { 174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return mPreferredWord != null ? mPreferredWord : getTypedWord(); 175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1764a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 1774a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani /** 1784a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 1794a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 1804a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 1814a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 1824a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 1831c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1841c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 1851c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Saves the reason why the word is capitalized - whether it was automatic or 1861c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * due to the user hitting shift in the middle of a sentence. 1871c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @param auto whether it was an automatic capitalization due to start of sentence 1881c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 1891c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public void setAutoCapitalized(boolean auto) { 1901c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani mAutoCapitalized = auto; 1911c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 1921c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1931c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 1941c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 1951c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 1961c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 1971c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public boolean isAutoCapitalized() { 1981c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani return mAutoCapitalized; 1991c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 201