Keyboard.java revision 9237a72634be821c22911633ef0848130e162d58
1/*
2 * Copyright (C) 2010 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.keyboard;
18
19import android.graphics.drawable.Drawable;
20import android.text.TextUtils;
21
22import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
23import com.android.inputmethod.keyboard.internal.KeyboardParams;
24import com.android.inputmethod.keyboard.internal.KeyboardShiftState;
25
26import java.util.Collections;
27import java.util.List;
28import java.util.Map;
29import java.util.Set;
30
31/**
32 * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
33 * consists of rows of keys.
34 * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
35 * <pre>
36 * &lt;Keyboard
37 *         latin:keyWidth="%10p"
38 *         latin:keyHeight="50px"
39 *         latin:horizontalGap="2px"
40 *         latin:verticalGap="2px" &gt;
41 *     &lt;Row latin:keyWidth="32px" &gt;
42 *         &lt;Key latin:keyLabel="A" /&gt;
43 *         ...
44 *     &lt;/Row&gt;
45 *     ...
46 * &lt;/Keyboard&gt;
47 * </pre>
48 */
49public class Keyboard {
50    public static final int EDGE_LEFT = 0x01;
51    public static final int EDGE_RIGHT = 0x02;
52    public static final int EDGE_TOP = 0x04;
53    public static final int EDGE_BOTTOM = 0x08;
54
55    /** Some common keys code.  These should be aligned with values/keycodes.xml */
56    public static final int CODE_ENTER = '\n';
57    public static final int CODE_TAB = '\t';
58    public static final int CODE_SPACE = ' ';
59    public static final int CODE_PERIOD = '.';
60    public static final int CODE_DASH = '-';
61    public static final int CODE_SINGLE_QUOTE = '\'';
62    public static final int CODE_DOUBLE_QUOTE = '"';
63    // TODO: Check how this should work for right-to-left languages. It seems to stand
64    // that for rtl languages, a closing parenthesis is a left parenthesis. Is this
65    // managed by the font? Or is it a different char?
66    public static final int CODE_CLOSING_PARENTHESIS = ')';
67    public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
68    public static final int CODE_CLOSING_CURLY_BRACKET = '}';
69    public static final int CODE_CLOSING_ANGLE_BRACKET = '>';
70    public static final int CODE_DIGIT0 = '0';
71    public static final int CODE_PLUS = '+';
72
73
74    /** Special keys code.  These should be aligned with values/keycodes.xml */
75    public static final int CODE_DUMMY = 0;
76    public static final int CODE_SHIFT = -1;
77    public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
78    public static final int CODE_CAPSLOCK = -3;
79    public static final int CODE_CANCEL = -4;
80    public static final int CODE_DELETE = -5;
81    public static final int CODE_SETTINGS = -6;
82    public static final int CODE_SHORTCUT = -7;
83    // Code value representing the code is not specified.
84    public static final int CODE_UNSPECIFIED = -99;
85
86    public final KeyboardId mId;
87
88    /** Total height of the keyboard, including the padding and keys */
89    public final int mOccupiedHeight;
90    /** Total width of the keyboard, including the padding and keys */
91    public final int mOccupiedWidth;
92
93    public final int mHeight;
94    public final int mWidth;
95
96    /** Default row height */
97    public final int mDefaultRowHeight;
98
99    /** Default gap between rows */
100    public final int mVerticalGap;
101
102    public final int mMostCommonKeyWidth;
103
104    /** Popup keyboard template */
105    public final int mPopupTemplateId;
106
107    /** Maximum column for mini keyboard */
108    public final int mMaxMiniKeyboardColumn;
109
110    /** True if Right-To-Left keyboard */
111    public final boolean mIsRtlKeyboard;
112
113    /** List of keys and icons in this keyboard */
114    public final List<Key> mKeys;
115    public final List<Key> mShiftKeys;
116    public final Set<Key> mShiftLockKeys;
117    public final Map<Key, Drawable> mShiftedIcons;
118    public final Map<Key, Drawable> mUnshiftedIcons;
119    public final KeyboardIconsSet mIconsSet;
120
121    private final KeyboardShiftState mShiftState = new KeyboardShiftState();
122
123    private final ProximityInfo mProximityInfo;
124
125    public Keyboard(KeyboardParams params) {
126        mId = params.mId;
127        mOccupiedHeight = params.mOccupiedHeight;
128        mOccupiedWidth = params.mOccupiedWidth;
129        mHeight = params.mHeight;
130        mWidth = params.mWidth;
131        mMostCommonKeyWidth = params.mMostCommonKeyWidth;
132        mIsRtlKeyboard = params.mIsRtlKeyboard;
133        mPopupTemplateId = params.mPopupTemplateId;
134        mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn;
135
136        mDefaultRowHeight = params.mDefaultRowHeight;
137        mVerticalGap = params.mVerticalGap;
138
139        mKeys = Collections.unmodifiableList(params.mKeys);
140        mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
141        mShiftLockKeys = Collections.unmodifiableSet(params.mShiftLockKeys);
142        mShiftedIcons = Collections.unmodifiableMap(params.mShiftedIcons);
143        mUnshiftedIcons = Collections.unmodifiableMap(params.mUnshiftedIcons);
144        mIconsSet = params.mIconsSet;
145
146        mProximityInfo = new ProximityInfo(
147                params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
148                mMostCommonKeyWidth, mKeys);
149    }
150
151    public ProximityInfo getProximityInfo() {
152        return mProximityInfo;
153    }
154
155    public boolean hasShiftLockKey() {
156        return !mShiftLockKeys.isEmpty();
157    }
158
159    public boolean setShiftLocked(boolean newShiftLockState) {
160        for (final Key key : mShiftLockKeys) {
161            // To represent "shift locked" state. The highlight is handled by background image that
162            // might be a StateListDrawable.
163            key.setHighlightOn(newShiftLockState);
164            // To represent "shifted" state. The key might have a shifted icon.
165            if (newShiftLockState && mShiftedIcons.containsKey(key)) {
166                key.setIcon(mShiftedIcons.get(key));
167            } else {
168                key.setIcon(mUnshiftedIcons.get(key));
169            }
170        }
171        mShiftState.setShiftLocked(newShiftLockState);
172        return true;
173    }
174
175    public boolean isShiftLocked() {
176        return mShiftState.isShiftLocked();
177    }
178
179    public boolean setShifted(boolean newShiftState) {
180        for (final Key key : mShiftKeys) {
181            if (!newShiftState && !mShiftState.isShiftLocked()) {
182                key.setIcon(mUnshiftedIcons.get(key));
183            } else if (newShiftState && !mShiftState.isShiftedOrShiftLocked()) {
184                key.setIcon(mShiftedIcons.get(key));
185            }
186        }
187        return mShiftState.setShifted(newShiftState);
188    }
189
190    public boolean isShiftedOrShiftLocked() {
191        return mShiftState.isShiftedOrShiftLocked();
192    }
193
194    public void setAutomaticTemporaryUpperCase() {
195        setShifted(true);
196        mShiftState.setAutomaticTemporaryUpperCase();
197    }
198
199    public boolean isAutomaticTemporaryUpperCase() {
200        return isAlphaKeyboard() && mShiftState.isAutomaticTemporaryUpperCase();
201    }
202
203    public boolean isManualTemporaryUpperCase() {
204        return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase();
205    }
206
207    public boolean isManualTemporaryUpperCaseFromAuto() {
208        return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto();
209    }
210
211    public KeyboardShiftState getKeyboardShiftState() {
212        return mShiftState;
213    }
214
215    public boolean isAlphaKeyboard() {
216        return mId.isAlphabetKeyboard();
217    }
218
219    public boolean isPhoneKeyboard() {
220        return mId.isPhoneKeyboard();
221    }
222
223    public boolean isNumberKeyboard() {
224        return mId.isNumberKeyboard();
225    }
226
227    public CharSequence adjustLabelCase(CharSequence label) {
228        if (isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) && label.length() < 3
229                && Character.isLowerCase(label.charAt(0))) {
230            return label.toString().toUpperCase(mId.mLocale);
231        }
232        return label;
233    }
234
235    /**
236     * Returns the indices of the keys that are closest to the given point.
237     * @param x the x-coordinate of the point
238     * @param y the y-coordinate of the point
239     * @return the array of integer indices for the nearest keys to the given point. If the given
240     * point is out of range, then an array of size zero is returned.
241     */
242    public int[] getNearestKeys(int x, int y) {
243        return mProximityInfo.getNearestKeys(x, y);
244    }
245}
246