WordComposer.java revision 8fbf29e2d54027a17993cd0d4ad486e3454b56f6
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 19887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector; 20887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.ArrayList; 22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class WordComposer { 278fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 28887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; 298fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public static final int NOT_A_COORDINATE = -1; 30887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * The list of unicode values for each keystroke (including surrounding keys) 33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 349fbfd5877305ed19a20663630b498b6b3fdae942satok private ArrayList<int[]> mCodes; 358fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 369fbfd5877305ed19a20663630b498b6b3fdae942satok private int[] mXCoordinates; 379fbfd5877305ed19a20663630b498b6b3fdae942satok private int[] mYCoordinates; 388fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 399fbfd5877305ed19a20663630b498b6b3fdae942satok private StringBuilder mTypedWord; 404a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 414a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 421c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 431c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani private boolean mAutoCapitalized; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 460b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether the user chose to capitalize the first char of the word. 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 480b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa private boolean mIsFirstCharCapitalized; 49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 50979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 518fbd55229243cb66c03d5ea1f79dfb39f596590dsatok final int N = BinaryDictionary.MAX_WORD_LENGTH; 528fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mCodes = new ArrayList<int[]>(N); 538fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mTypedWord = new StringBuilder(N); 548fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mXCoordinates = new int[N]; 558fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mYCoordinates = new int[N]; 56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 58f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok public WordComposer(WordComposer source) { 599fbfd5877305ed19a20663630b498b6b3fdae942satok init(source); 609fbfd5877305ed19a20663630b498b6b3fdae942satok } 619fbfd5877305ed19a20663630b498b6b3fdae942satok 629fbfd5877305ed19a20663630b498b6b3fdae942satok public void init(WordComposer source) { 638fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mCodes = new ArrayList<int[]>(source.mCodes); 648fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mTypedWord = new StringBuilder(source.mTypedWord); 658fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mXCoordinates = source.mXCoordinates; 668fbd55229243cb66c03d5ea1f79dfb39f596590dsatok mYCoordinates = source.mYCoordinates; 67ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mCapsCount = source.mCapsCount; 68ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; 69ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mAutoCapitalized = source.mAutoCapitalized; 70979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 71979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 72923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 73923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mCodes.clear(); 77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mTypedWord.setLength(0); 784a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 79ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 84923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 85923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 86ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka public final int size() { 87ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka return mTypedWord.length(); 88923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 90923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 91923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the codes at a particular position in the word. 92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param index the position in the word 93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the unicode for the pressed and surrounding keys 94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public int[] getCodesAt(int index) { 96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return mCodes.get(index); 97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 998fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public int[] getXCoordinates() { 1008fbd55229243cb66c03d5ea1f79dfb39f596590dsatok return mXCoordinates; 1018fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1028fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 1038fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public int[] getYCoordinates() { 1048fbd55229243cb66c03d5ea1f79dfb39f596590dsatok return mYCoordinates; 1058fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1068fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 107ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { 108ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (index == 0) return Character.isUpperCase(codePoint); 109436a645ea837d36f7e0f81948d343fa6e166f33aTadashi G. Takaoka return previous && !Character.isUpperCase(codePoint); 110ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka } 111ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka 112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of 114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. 115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param codes the array of unicode values 116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 1178fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public void add(int primaryCode, int[] codes, int x, int y) { 118ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int newIndex = size(); 119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mTypedWord.append((char) primaryCode); 120231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani correctPrimaryJuxtapos(primaryCode, codes); 121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mCodes.add(codes); 122ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { 123ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mXCoordinates[newIndex] = x; 124ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mYCoordinates[newIndex] = y; 1258fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 126ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = isFirstCharCapitalized( 127ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka newIndex, primaryCode, mIsFirstCharCapitalized); 128ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(primaryCode)) mCapsCount++; 129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 132231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * Swaps the first and second values in the codes array if the primary code is not the first 133231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * value in the array but the second. This happens when the preferred key is not the key that 134231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * the user released the finger on. 135231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param primaryCode the preferred character 136231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param codes array of codes based on distance from touch point 137231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani */ 1388fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) { 139231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes.length < 2) return; 140231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { 141231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[1] = codes[0]; 142231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[0] = primaryCode; 143231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 144231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 145231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani 146231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani /** 147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Delete the last keystroke as a result of hitting backspace. 148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void deleteLast() { 150ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int size = size(); 151ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size > 0) { 152ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int lastPos = size - 1; 153ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka char lastChar = mTypedWord.charAt(lastPos); 154ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mCodes.remove(lastPos); 155d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka mTypedWord.deleteCharAt(lastPos); 156ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(lastChar)) mCapsCount--; 157d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka } 158ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size() == 0) { 159ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 1608fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the word that was typed so far 166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 1675c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard public String getTypedWord() { 168ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size() == 0) { 169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return null; 170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1715c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard return mTypedWord.toString(); 172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Whether or not the user typed a capital letter as the first letter in the word 176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 1780b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isFirstCharCapitalized() { 1790b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return mIsFirstCharCapitalized; 180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1810b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 1820b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 1830b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 1840b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 1850b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 1860b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 1870b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return (mCapsCount > 0) && (mCapsCount == size()); 1880b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 1890b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 1914a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 1924a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 1934a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 1944a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 1954a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 1961c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1971c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 1981c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Saves the reason why the word is capitalized - whether it was automatic or 1991c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * due to the user hitting shift in the middle of a sentence. 2001c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @param auto whether it was an automatic capitalization due to start of sentence 2011c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 2021c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public void setAutoCapitalized(boolean auto) { 2031c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani mAutoCapitalized = auto; 2041c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 2051c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 2061c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 2071c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 2081c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 2091c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 2101c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public boolean isAutoCapitalized() { 2111c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani return mAutoCapitalized; 2121c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 214