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