Keyboard.java revision 0ea82be889df77546956c0fe93664622fa4ccb29
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.inputmethod.keyboard; 18 19import android.util.SparseArray; 20 21import com.android.inputmethod.keyboard.internal.KeyVisualAttributes; 22import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 23import com.android.inputmethod.keyboard.internal.KeyboardParams; 24import com.android.inputmethod.latin.Constants; 25import com.android.inputmethod.latin.utils.CollectionUtils; 26import com.android.inputmethod.latin.utils.CoordinateUtils; 27 28import java.util.Collections; 29import java.util.List; 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 * <Keyboard 37 * latin:keyWidth="10%p" 38 * latin:rowHeight="50px" 39 * latin:horizontalGap="2%p" 40 * latin:verticalGap="2%p" > 41 * <Row latin:keyWidth="10%p" > 42 * <Key latin:keyLabel="A" /> 43 * ... 44 * </Row> 45 * ... 46 * </Keyboard> 47 * </pre> 48 */ 49public class Keyboard { 50 public final KeyboardId mId; 51 public final int mThemeId; 52 53 /** Total height of the keyboard, including the padding and keys */ 54 public final int mOccupiedHeight; 55 /** Total width of the keyboard, including the padding and keys */ 56 public final int mOccupiedWidth; 57 58 /** Base height of the keyboard, used to calculate rows' height */ 59 public final int mBaseHeight; 60 /** Base width of the keyboard, used to calculate keys' width */ 61 public final int mBaseWidth; 62 63 /** The padding above the keyboard */ 64 public final int mTopPadding; 65 /** Default gap between rows */ 66 public final int mVerticalGap; 67 68 /** Per keyboard key visual parameters */ 69 public final KeyVisualAttributes mKeyVisualAttributes; 70 71 public final int mMostCommonKeyHeight; 72 public final int mMostCommonKeyWidth; 73 74 /** More keys keyboard template */ 75 public final int mMoreKeysTemplate; 76 77 /** Maximum column for more keys keyboard */ 78 public final int mMaxMoreKeysKeyboardColumn; 79 80 /** List of keys in this keyboard */ 81 private final List<Key> mSortedKeys; 82 public final List<Key> mShiftKeys; 83 public final List<Key> mAltCodeKeysWhileTyping; 84 public final KeyboardIconsSet mIconsSet; 85 86 private final SparseArray<Key> mKeyCache = CollectionUtils.newSparseArray(); 87 88 private final ProximityInfo mProximityInfo; 89 private final boolean mProximityCharsCorrectionEnabled; 90 91 public Keyboard(final KeyboardParams params) { 92 mId = params.mId; 93 mThemeId = params.mThemeId; 94 mOccupiedHeight = params.mOccupiedHeight; 95 mOccupiedWidth = params.mOccupiedWidth; 96 mBaseHeight = params.mBaseHeight; 97 mBaseWidth = params.mBaseWidth; 98 mMostCommonKeyHeight = params.mMostCommonKeyHeight; 99 mMostCommonKeyWidth = params.mMostCommonKeyWidth; 100 mMoreKeysTemplate = params.mMoreKeysTemplate; 101 mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn; 102 mKeyVisualAttributes = params.mKeyVisualAttributes; 103 mTopPadding = params.mTopPadding; 104 mVerticalGap = params.mVerticalGap; 105 106 mSortedKeys = Collections.unmodifiableList( 107 CollectionUtils.newArrayList(params.mSortedKeys)); 108 mShiftKeys = Collections.unmodifiableList(params.mShiftKeys); 109 mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping); 110 mIconsSet = params.mIconsSet; 111 112 mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), 113 params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, 114 mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys, 115 params.mTouchPositionCorrection); 116 mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled; 117 } 118 119 protected Keyboard(final Keyboard keyboard) { 120 mId = keyboard.mId; 121 mThemeId = keyboard.mThemeId; 122 mOccupiedHeight = keyboard.mOccupiedHeight; 123 mOccupiedWidth = keyboard.mOccupiedWidth; 124 mBaseHeight = keyboard.mBaseHeight; 125 mBaseWidth = keyboard.mBaseWidth; 126 mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight; 127 mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth; 128 mMoreKeysTemplate = keyboard.mMoreKeysTemplate; 129 mMaxMoreKeysKeyboardColumn = keyboard.mMaxMoreKeysKeyboardColumn; 130 mKeyVisualAttributes = keyboard.mKeyVisualAttributes; 131 mTopPadding = keyboard.mTopPadding; 132 mVerticalGap = keyboard.mVerticalGap; 133 134 mSortedKeys = keyboard.mSortedKeys; 135 mShiftKeys = keyboard.mShiftKeys; 136 mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping; 137 mIconsSet = keyboard.mIconsSet; 138 139 mProximityInfo = keyboard.mProximityInfo; 140 mProximityCharsCorrectionEnabled = keyboard.mProximityCharsCorrectionEnabled; 141 } 142 143 public boolean hasProximityCharsCorrection(final int code) { 144 if (!mProximityCharsCorrectionEnabled) { 145 return false; 146 } 147 // Note: The native code has the main keyboard layout only at this moment. 148 // TODO: Figure out how to handle proximity characters information of all layouts. 149 final boolean canAssumeNativeHasProximityCharsInfoOfAllKeys = ( 150 mId.mElementId == KeyboardId.ELEMENT_ALPHABET 151 || mId.mElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED); 152 return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code); 153 } 154 155 public ProximityInfo getProximityInfo() { 156 return mProximityInfo; 157 } 158 159 /** 160 * Return the sorted list of keys of this keyboard. 161 * The keys are sorted from top-left to bottom-right order. 162 * The list may contain {@link Spacer} object as well. 163 * @return the sorted unmodifiable list of {@link Key}s of this keyboard. 164 */ 165 public List<Key> getSortedKeys() { 166 return mSortedKeys; 167 } 168 169 public Key getKey(final int code) { 170 if (code == Constants.CODE_UNSPECIFIED) { 171 return null; 172 } 173 synchronized (mKeyCache) { 174 final int index = mKeyCache.indexOfKey(code); 175 if (index >= 0) { 176 return mKeyCache.valueAt(index); 177 } 178 179 for (final Key key : getSortedKeys()) { 180 if (key.getCode() == code) { 181 mKeyCache.put(code, key); 182 return key; 183 } 184 } 185 mKeyCache.put(code, null); 186 return null; 187 } 188 } 189 190 public boolean hasKey(final Key aKey) { 191 if (mKeyCache.indexOfValue(aKey) >= 0) { 192 return true; 193 } 194 195 for (final Key key : getSortedKeys()) { 196 if (key == aKey) { 197 mKeyCache.put(key.getCode(), key); 198 return true; 199 } 200 } 201 return false; 202 } 203 204 @Override 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 list 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 */ 216 public List<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 223 public int[] getCoordinates(final int[] codePoints) { 224 final int length = codePoints.length; 225 final int[] coordinates = CoordinateUtils.newCoordinateArray(length); 226 for (int i = 0; i < length; ++i) { 227 final Key key = getKey(codePoints[i]); 228 if (null != key) { 229 CoordinateUtils.setXYInArray(coordinates, i, 230 key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2); 231 } else { 232 CoordinateUtils.setXYInArray(coordinates, i, 233 Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 234 } 235 } 236 return coordinates; 237 } 238} 239