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