• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.inputmethod.keyboard;
18 
19 import android.util.Log;
20 import android.util.SparseArray;
21 
22 import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
23 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
24 import com.android.inputmethod.keyboard.internal.KeyboardParams;
25 import com.android.inputmethod.latin.CollectionUtils;
26 
27 
28 
29 /**
30  * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
31  * consists of rows of keys.
32  * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
33  * <pre>
34  * &lt;Keyboard
35  *         latin:keyWidth="%10p"
36  *         latin:keyHeight="50px"
37  *         latin:horizontalGap="2px"
38  *         latin:verticalGap="2px" &gt;
39  *     &lt;Row latin:keyWidth="32px" &gt;
40  *         &lt;Key latin:keyLabel="A" /&gt;
41  *         ...
42  *     &lt;/Row&gt;
43  *     ...
44  * &lt;/Keyboard&gt;
45  * </pre>
46  */
47 public class Keyboard {
48     private static final String TAG = Keyboard.class.getSimpleName();
49 
50     /** Some common keys code. Must be positive.
51      * These should be aligned with values/keycodes.xml
52      */
53     public static final int CODE_ENTER = '\n';
54     public static final int CODE_TAB = '\t';
55     public static final int CODE_SPACE = ' ';
56     public static final int CODE_PERIOD = '.';
57     public static final int CODE_DASH = '-';
58     public static final int CODE_SINGLE_QUOTE = '\'';
59     public static final int CODE_DOUBLE_QUOTE = '"';
60     public static final int CODE_QUESTION_MARK = '?';
61     public static final int CODE_EXCLAMATION_MARK = '!';
62     // TODO: Check how this should work for right-to-left languages. It seems to stand
63     // that for rtl languages, a closing parenthesis is a left parenthesis. Is this
64     // managed by the font? Or is it a different char?
65     public static final int CODE_CLOSING_PARENTHESIS = ')';
66     public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
67     public static final int CODE_CLOSING_CURLY_BRACKET = '}';
68     public static final int CODE_CLOSING_ANGLE_BRACKET = '>';
69 
70     /** Special keys code. Must be negative.
71      * These should be aligned with KeyboardCodesSet.ID_TO_NAME[],
72      * KeyboardCodesSet.DEFAULT[] and KeyboardCodesSet.RTL[]
73      */
74     public static final int CODE_SHIFT = -1;
75     public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
76     public static final int CODE_OUTPUT_TEXT = -3;
77     public static final int CODE_DELETE = -4;
78     public static final int CODE_SETTINGS = -5;
79     public static final int CODE_SHORTCUT = -6;
80     public static final int CODE_ACTION_ENTER = -7;
81     public static final int CODE_ACTION_NEXT = -8;
82     public static final int CODE_ACTION_PREVIOUS = -9;
83     public static final int CODE_LANGUAGE_SWITCH = -10;
84     public static final int CODE_RESEARCH = -11;
85     // Code value representing the code is not specified.
86     public static final int CODE_UNSPECIFIED = -12;
87 
88     public final KeyboardId mId;
89     public final int mThemeId;
90 
91     /** Total height of the keyboard, including the padding and keys */
92     public final int mOccupiedHeight;
93     /** Total width of the keyboard, including the padding and keys */
94     public final int mOccupiedWidth;
95 
96     /** The padding above the keyboard */
97     public final int mTopPadding;
98     /** Default gap between rows */
99     public final int mVerticalGap;
100 
101     /** Per keyboard key visual parameters */
102     public final KeyVisualAttributes mKeyVisualAttributes;
103 
104     public final int mMostCommonKeyHeight;
105     public final int mMostCommonKeyWidth;
106 
107     /** More keys keyboard template */
108     public final int mMoreKeysTemplate;
109 
110     /** Maximum column for more keys keyboard */
111     public final int mMaxMoreKeysKeyboardColumn;
112 
113     /** Array of keys and icons in this keyboard */
114     public final Key[] mKeys;
115     public final Key[] mShiftKeys;
116     public final Key[] mAltCodeKeysWhileTyping;
117     public final KeyboardIconsSet mIconsSet;
118 
119     private final SparseArray<Key> mKeyCache = CollectionUtils.newSparseArray();
120 
121     private final ProximityInfo mProximityInfo;
122     private final boolean mProximityCharsCorrectionEnabled;
123 
Keyboard(final KeyboardParams params)124     public Keyboard(final KeyboardParams params) {
125         mId = params.mId;
126         mThemeId = params.mThemeId;
127         mOccupiedHeight = params.mOccupiedHeight;
128         mOccupiedWidth = params.mOccupiedWidth;
129         mMostCommonKeyHeight = params.mMostCommonKeyHeight;
130         mMostCommonKeyWidth = params.mMostCommonKeyWidth;
131         mMoreKeysTemplate = params.mMoreKeysTemplate;
132         mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn;
133         mKeyVisualAttributes = params.mKeyVisualAttributes;
134         mTopPadding = params.mTopPadding;
135         mVerticalGap = params.mVerticalGap;
136 
137         mKeys = params.mKeys.toArray(new Key[params.mKeys.size()]);
138         mShiftKeys = params.mShiftKeys.toArray(new Key[params.mShiftKeys.size()]);
139         mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray(
140                 new Key[params.mAltCodeKeysWhileTyping.size()]);
141         mIconsSet = params.mIconsSet;
142 
143         mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(),
144                 params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
145                 mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection);
146         mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
147     }
148 
hasProximityCharsCorrection(final int code)149     public boolean hasProximityCharsCorrection(final int code) {
150         if (!mProximityCharsCorrectionEnabled) {
151             return false;
152         }
153         // Note: The native code has the main keyboard layout only at this moment.
154         // TODO: Figure out how to handle proximity characters information of all layouts.
155         final boolean canAssumeNativeHasProximityCharsInfoOfAllKeys = (
156                 mId.mElementId == KeyboardId.ELEMENT_ALPHABET
157                 || mId.mElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED);
158         return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code);
159     }
160 
getProximityInfo()161     public ProximityInfo getProximityInfo() {
162         return mProximityInfo;
163     }
164 
getKey(final int code)165     public Key getKey(final int code) {
166         if (code == CODE_UNSPECIFIED) {
167             return null;
168         }
169         synchronized (mKeyCache) {
170             final int index = mKeyCache.indexOfKey(code);
171             if (index >= 0) {
172                 return mKeyCache.valueAt(index);
173             }
174 
175             for (final Key key : mKeys) {
176                 if (key.mCode == code) {
177                     mKeyCache.put(code, key);
178                     return key;
179                 }
180             }
181             mKeyCache.put(code, null);
182             return null;
183         }
184     }
185 
hasKey(final Key aKey)186     public boolean hasKey(final Key aKey) {
187         if (mKeyCache.indexOfValue(aKey) >= 0) {
188             return true;
189         }
190 
191         for (final Key key : mKeys) {
192             if (key == aKey) {
193                 mKeyCache.put(key.mCode, key);
194                 return true;
195             }
196         }
197         return false;
198     }
199 
isLetterCode(final int code)200     public static boolean isLetterCode(final int code) {
201         return code >= CODE_SPACE;
202     }
203 
204     @Override
toString()205     public String toString() {
206         return mId.toString();
207     }
208 
209     /**
210      * Returns the array of the keys that are closest to the given point.
211      * @param x the x-coordinate of the point
212      * @param y the y-coordinate of the point
213      * @return the array of the nearest keys to the given point. If the given
214      * point is out of range, then an array of size zero is returned.
215      */
getNearestKeys(final int x, final int y)216     public Key[] getNearestKeys(final int x, final int y) {
217         // Avoid dead pixels at edges of the keyboard
218         final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
219         final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
220         return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
221     }
222 
printableCode(final int code)223     public static String printableCode(final int code) {
224         switch (code) {
225         case CODE_SHIFT: return "shift";
226         case CODE_SWITCH_ALPHA_SYMBOL: return "symbol";
227         case CODE_OUTPUT_TEXT: return "text";
228         case CODE_DELETE: return "delete";
229         case CODE_SETTINGS: return "settings";
230         case CODE_SHORTCUT: return "shortcut";
231         case CODE_ACTION_ENTER: return "actionEnter";
232         case CODE_ACTION_NEXT: return "actionNext";
233         case CODE_ACTION_PREVIOUS: return "actionPrevious";
234         case CODE_LANGUAGE_SWITCH: return "languageSwitch";
235         case CODE_UNSPECIFIED: return "unspec";
236         case CODE_TAB: return "tab";
237         case CODE_ENTER: return "enter";
238         default:
239             if (code <= 0) Log.w(TAG, "Unknown non-positive key code=" + code);
240             if (code < CODE_SPACE) return String.format("'\\u%02x'", code);
241             if (code < 0x100) return String.format("'%c'", code);
242             return String.format("'\\u%04x'", code);
243         }
244     }
245 }
246