159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma/* 259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Copyright (C) 2008-2012 OMRON SOFTWARE Co., Ltd. 359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Licensed under the Apache License, Version 2.0 (the "License"); 559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * you may not use this file except in compliance with the License. 659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * You may obtain a copy of the License at 759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * http://www.apache.org/licenses/LICENSE-2.0 959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 1059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Unless required by applicable law or agreed to in writing, software 1159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * distributed under the License is distributed on an "AS IS" BASIS, 1259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * See the License for the specific language governing permissions and 1459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * limitations under the License. 1559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 1659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma/* 1759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * This file is porting from Android framework. 1859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * frameworks/base/core/java/android/inputmethodservice/Keyboard.java 1959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 2059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * package android.inputmethodservice; 2159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 2259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmapackage jp.co.omronsoft.openwnn; 2359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 2459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.content.Context; 2559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.content.res.Resources; 2659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.content.res.TypedArray; 2759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.content.res.XmlResourceParser; 2859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.drawable.Drawable; 2959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.text.TextUtils; 3059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.util.Log; 3159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.util.TypedValue; 3259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.util.Xml; 3359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.util.DisplayMetrics; 3459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 3559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.io.IOException; 3659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.util.ArrayList; 3759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.util.List; 3859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.util.StringTokenizer; 3959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 4059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport org.xmlpull.v1.XmlPullParserException; 4159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 4259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma/** 4359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard 4459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * consists of rows of keys. 4559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p> 4659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * <pre> 4759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * <Keyboard 4859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * android:keyWidth="%10p" 4959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * android:keyHeight="50px" 5059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * android:horizontalGap="2px" 5159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * android:verticalGap="2px" > 5259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * <Row android:keyWidth="32px" > 5359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * <Key android:keyLabel="A" /> 5459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * ... 5559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * </Row> 5659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * ... 5759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * </Keyboard> 5859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * </pre> 5959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 6059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmapublic class Keyboard { 6159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 6259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma static final String TAG = "Keyboard"; 6359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 6459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final String TAG_KEYBOARD = "Keyboard"; 6559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final String TAG_ROW = "Row"; 6659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final String TAG_KEY = "Key"; 6759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 6859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Edge of left */ 6959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int EDGE_LEFT = 0x01; 7059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 7159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Edge of right */ 7259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int EDGE_RIGHT = 0x02; 7359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 7459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Edge of top */ 7559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int EDGE_TOP = 0x04; 7659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 7759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Edge of bottom */ 7859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int EDGE_BOTTOM = 0x08; 7959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 8059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keycode of SHIFT */ 8159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int KEYCODE_SHIFT = -1; 8259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 8359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keycode of MODE_CHANGE */ 8459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int KEYCODE_MODE_CHANGE = -2; 8559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 8659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keycode of CANCEL */ 8759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int KEYCODE_CANCEL = -3; 8859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 8959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keycode of DONE */ 9059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int KEYCODE_DONE = -4; 9159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 9259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keycode of DELETE */ 9359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int KEYCODE_DELETE = -5; 9459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 9559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keycode of ALT */ 9659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static final int KEYCODE_ALT = -6; 9759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 9859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keyboard label **/ 9959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private CharSequence mLabel; 10059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 10159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Horizontal gap default for all rows */ 10259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mDefaultHorizontalGap; 10359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 10459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Default key width */ 10559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mDefaultWidth; 10659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 10759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Default key height */ 10859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mDefaultHeight; 10959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 11059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Default gap between rows */ 11159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mDefaultVerticalGap; 11259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 11359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Is the keyboard in the shifted state */ 11459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mShifted; 11559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 11659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Key instance for the shift key, if present */ 11759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Key mShiftKey; 11859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 11959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Key index for the shift key, if present */ 12059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mShiftKeyIndex = -1; 12159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 12259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Current key width, while loading the keyboard */ 12359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mKeyWidth; 12459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 12559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Current key height, while loading the keyboard */ 12659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mKeyHeight; 12759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 12859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Total height of the keyboard, including the padding and keys */ 12959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mTotalHeight; 13059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 13159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 13259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Total width of the keyboard, including left side gaps and keys, but not any gaps on the 13359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * right side. 13459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 13559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mTotalWidth; 13659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 13759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** List of keys in this keyboard */ 13859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private List<Key> mKeys; 13959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 14059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** List of modifier keys such as Shift & Alt, if any */ 14159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private List<Key> mModifierKeys; 14259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 14359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Width of the screen available to fit the keyboard */ 14459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mDisplayWidth; 14559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 14659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Height of the screen */ 14759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mDisplayHeight; 14859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 14959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Keyboard mode, or zero, if none. */ 15059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mKeyboardMode; 15159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 15259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 15359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int GRID_WIDTH = 10; 15459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int GRID_HEIGHT = 5; 15559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int GRID_SIZE = GRID_WIDTH * GRID_HEIGHT; 15659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mCellWidth; 15759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mCellHeight; 15859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int[][] mGridNeighbors; 15959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mProximityThreshold; 16059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Number of key widths from current touch point to search for nearest keys. */ 16159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static float SEARCH_DISTANCE = 1.8f; 16259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 16359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 16459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. 16559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Some of the key size defaults can be overridden per row from what the {@link Keyboard} 16659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * defines. 16759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 16859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static class Row { 16959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Default width of a key in this row. */ 17059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int defaultWidth; 17159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Default height of a key in this row. */ 17259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int defaultHeight; 17359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Default horizontal gap between keys in this row. */ 17459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int defaultHorizontalGap; 17559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Vertical gap following this row. */ 17659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int verticalGap; 17759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 17859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Edge flags for this row of keys. Possible values that can be assigned are 17959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * {@link Keyboard#EDGE_TOP EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM EDGE_BOTTOM} 18059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 18159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int rowEdgeFlags; 18259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 18359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** The keyboard mode for this row */ 18459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int mode; 18559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 18659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Keyboard parent; 18759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 18859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Constructor */ 18959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Row(Keyboard parent) { 19059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this.parent = parent; 19159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 19259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 19359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Constructor */ 19459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Row(Resources res, Keyboard parent, XmlResourceParser parser) { 19559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this.parent = parent; 19659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), 19759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard); 19859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma defaultWidth = getDimensionOrFraction(a, 19959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_keyWidth, 20059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma parent.mDisplayWidth, parent.mDefaultWidth); 20159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma defaultHeight = getDimensionOrFraction(a, 20259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_keyHeight, 20359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma parent.mDisplayHeight, parent.mDefaultHeight); 20459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma defaultHorizontalGap = getDimensionOrFraction(a, 20559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_horizontalGap, 20659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma parent.mDisplayWidth, parent.mDefaultHorizontalGap); 20759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma verticalGap = getDimensionOrFraction(a, 20859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_verticalGap, 20959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma parent.mDisplayHeight, parent.mDefaultVerticalGap); 21059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.recycle(); 21159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a = res.obtainAttributes(Xml.asAttributeSet(parser), 21259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Row); 21359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma rowEdgeFlags = a.getInt(android.R.styleable.Keyboard_Row_rowEdgeFlags, 0); 21459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mode = a.getResourceId(android.R.styleable.Keyboard_Row_keyboardMode, 21559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 0); 21659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 21759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 21859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 21959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 22059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Class for describing the position and characteristics of a single key in the keyboard. 22159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 22259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public static class Key { 22359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 22459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * All the key codes (unicode or custom code) that this key could generate, zero'th 22559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * being the most important. 22659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 22759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int[] codes; 22859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 22959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Label to display */ 23059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public CharSequence label; 23159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 23259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Icon to display instead of a label. Icon takes precedence over a label */ 23359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Drawable icon; 23459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Preview version of the icon, for the preview popup */ 23559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Drawable iconPreview; 23659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Width of the key, not including the gap */ 23759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int width; 23859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Height of the key, not including the gap */ 23959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int height; 24059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** The horizontal gap before this key */ 24159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int gap; 24259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Whether this key is sticky, i.e., a toggle key */ 24359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean sticky; 24459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** X coordinate of the key in the keyboard layout */ 24559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int x; 24659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Y coordinate of the key in the keyboard layout */ 24759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int y; 24859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** The current pressed state of this key */ 24959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean pressed; 25059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** If this is a sticky key, is it on? */ 25159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean on; 25259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Text to output when pressed. This can be multiple characters, like ".com" */ 25359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public CharSequence text; 25459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Popup characters */ 25559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public CharSequence popupCharacters; 25659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 25759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 25859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Flags that specify the anchoring to edges of the keyboard for detecting touch events 25959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * that are just out of the boundary of the key. This is a bit mask of 26059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * {@link Keyboard#EDGE_LEFT}, {@link Keyboard#EDGE_RIGHT}, {@link Keyboard#EDGE_TOP} and 26159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * {@link Keyboard#EDGE_BOTTOM}. 26259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 26359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int edgeFlags; 26459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Whether this is a modifier key, such as Shift or Alt */ 26559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean modifier; 26659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** The keyboard that this key belongs to */ 26759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Keyboard keyboard; 26859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 26959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * If this key pops up a mini keyboard, this is the resource id for the XML layout for that 27059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * keyboard. 27159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 27259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int popupResId; 27359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Whether this key repeats itself when held down */ 27459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean repeatable; 27559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Whether this key is 2nd key */ 27659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isSecondKey; 27759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 27859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private final static int[] KEY_STATE_NORMAL_ON = { 27959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_checkable, 28059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_checked 28159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 28259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 28359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private final static int[] KEY_STATE_PRESSED_ON = { 28459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_pressed, 28559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_checkable, 28659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_checked 28759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 28859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 28959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private final static int[] KEY_STATE_NORMAL_OFF = { 29059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_checkable 29159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 29259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 29359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private final static int[] KEY_STATE_PRESSED_OFF = { 29459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_pressed, 29559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_checkable 29659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 29759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 29859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private final static int[] KEY_STATE_NORMAL = { 29959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 30059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 30159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private final static int[] KEY_STATE_PRESSED = { 30259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_pressed 30359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 30459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 30559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Create an empty key with no attributes. */ 30659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Key(Row parent) { 30759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyboard = parent.parent; 30859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma height = parent.defaultHeight; 30959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma width = parent.defaultWidth; 31059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma gap = parent.defaultHorizontalGap; 31159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma edgeFlags = parent.rowEdgeFlags; 31259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 31359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 31459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Create a key with the given top-left coordinate and extract its attributes from 31559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * the XML parser. 31659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param res resources associated with the caller's context 31759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param parent the row that this key belongs to. The row must already be attached to 31859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * a {@link Keyboard}. 31959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param x the x coordinate of the top-left 32059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param y the y coordinate of the top-left 32159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param parser the XML parser containing the attributes for this key 32259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 32359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Key(Resources res, Row parent, int x, int y, XmlResourceParser parser) { 32459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this(parent); 32559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 32659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this.x = x; 32759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this.y = y; 32859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 32959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), 33059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard); 33159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 33259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma width = getDimensionOrFraction(a, 33359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_keyWidth, 33459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyboard.mDisplayWidth, parent.defaultWidth); 33559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma height = getDimensionOrFraction(a, 33659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_keyHeight, 33759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyboard.mDisplayHeight, parent.defaultHeight); 33859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma gap = getDimensionOrFraction(a, 33959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_horizontalGap, 34059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyboard.mDisplayWidth, parent.defaultHorizontalGap); 34159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.recycle(); 34259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a = res.obtainAttributes(Xml.asAttributeSet(parser), 34359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Key); 34459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this.x += gap; 34559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma TypedValue codesValue = new TypedValue(); 34659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.getValue(android.R.styleable.Keyboard_Key_codes, 34759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma codesValue); 34859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (codesValue.type == TypedValue.TYPE_INT_DEC 34959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma || codesValue.type == TypedValue.TYPE_INT_HEX) { 35059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma codes = new int[] { codesValue.data }; 35159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (codesValue.type == TypedValue.TYPE_STRING) { 35259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma codes = parseCSV(codesValue.string.toString()); 35359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 35459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 35559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma iconPreview = a.getDrawable(android.R.styleable.Keyboard_Key_iconPreview); 35659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (iconPreview != null) { 35759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma iconPreview.setBounds(0, 0, iconPreview.getIntrinsicWidth(), 35859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma iconPreview.getIntrinsicHeight()); 35959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 36059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma popupCharacters = a.getText( 36159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Key_popupCharacters); 36259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma popupResId = a.getResourceId( 36359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Key_popupKeyboard, 0); 36459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma repeatable = a.getBoolean( 36559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Key_isRepeatable, false); 36659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma modifier = a.getBoolean( 36759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Key_isModifier, false); 36859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma sticky = a.getBoolean( 36959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Key_isSticky, false); 37059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma edgeFlags = a.getInt(android.R.styleable.Keyboard_Key_keyEdgeFlags, 0); 37159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma edgeFlags |= parent.rowEdgeFlags; 37259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 37359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma icon = a.getDrawable( 37459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_Key_keyIcon); 37559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (icon != null) { 37659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); 37759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 37859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma label = a.getText(android.R.styleable.Keyboard_Key_keyLabel); 37959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma text = a.getText(android.R.styleable.Keyboard_Key_keyOutputText); 38059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 38159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (codes == null && !TextUtils.isEmpty(label)) { 38259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma codes = new int[] { label.charAt(0) }; 38359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 38459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.recycle(); 38559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.WnnKeyboard_Key); 38659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma isSecondKey = a.getBoolean(R.styleable.WnnKeyboard_Key_isSecondKey, false); 38759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.recycle(); 38859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 38959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 39059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 39159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Informs the key that it has been pressed, in case it needs to change its appearance or 39259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * state. 39359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #onReleased(boolean) 39459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 39559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onPressed() { 39659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma pressed = !pressed; 39759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 39859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 39959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 40059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Changes the pressed state of the key. If it is a sticky key, it will also change the 40159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * toggled state of the key if the finger was release inside. 40259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param inside whether the finger was released inside the key 40359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #onPressed() 40459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 40559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onReleased(boolean inside) { 40659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma pressed = !pressed; 40759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (sticky) { 40859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma on = !on; 40959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 41059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 41159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 41259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int[] parseCSV(String value) { 41359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int count = 0; 41459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int lastIndex = 0; 41559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (value.length() > 0) { 41659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma count++; 41759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) { 41859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma count++; 41959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 42059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 42159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int[] values = new int[count]; 42259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma count = 0; 42359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma StringTokenizer st = new StringTokenizer(value, ","); 42459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma while (st.hasMoreTokens()) { 42559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma try { 42659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma values[count++] = Integer.parseInt(st.nextToken()); 42759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } catch (NumberFormatException nfe) { 42859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Log.e(TAG, "Error parsing keycodes " + value); 42959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 43059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 43159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return values; 43259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 43359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 43459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 43559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Detects if a point falls inside this key. 43659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param x the x-coordinate of the point 43759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param y the y-coordinate of the point 43859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return whether or not the point falls inside the key. If the key is attached to an edge, 43959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * it will assume that all points between the key and the edge are considered to be inside 44059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * the key. 44159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 44259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isInside(int x, int y) { 44359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean leftEdge = (edgeFlags & EDGE_LEFT) > 0; 44459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean rightEdge = (edgeFlags & EDGE_RIGHT) > 0; 44559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean topEdge = (edgeFlags & EDGE_TOP) > 0; 44659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean bottomEdge = (edgeFlags & EDGE_BOTTOM) > 0; 44759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if ((x >= this.x || (leftEdge && x <= this.x + this.width)) 44859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (x < this.x + this.width || (rightEdge && x >= this.x)) 44959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (y >= this.y || (topEdge && y <= this.y + this.height)) 45059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (y < this.y + this.height || (bottomEdge && y >= this.y))) { 45159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 45259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 45359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 45459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 45559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 45659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 45759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 45859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Detects if a area falls inside this key. 45959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param x the x-coordinate of the area 46059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param y the y-coordinate of the area 46159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param w the width of the area 46259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param h the height of the area 46359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return whether or not the area falls inside the key. 46459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 46559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isInside(int x, int y, int w, int h) { 46659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if ((this.x <= (x + w)) && (x <= (this.x + this.width)) 46759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (this.y <= (y + h)) && (y <= (this.y + this.height))) { 46859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 46959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 47059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 47159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 47259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 47359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 47459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 47559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the square of the distance between the center of the key and the given point. 47659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param x the x-coordinate of the point 47759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param y the y-coordinate of the point 47859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the square of the distance of the point from the center of the key 47959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 48059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int squaredDistanceFrom(int x, int y) { 48159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int xDist = this.x + width / 2 - x; 48259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int yDist = this.y + height / 2 - y; 48359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return xDist * xDist + yDist * yDist; 48459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 48559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 48659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 48759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the drawable state for the key, based on the current state and type of the key. 48859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the drawable state of the key. 48959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see android.graphics.drawable.StateListDrawable#setState(int[]) 49059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 49159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int[] getCurrentDrawableState() { 49259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int[] states = KEY_STATE_NORMAL; 49359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 49459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (on) { 49559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (pressed) { 49659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma states = KEY_STATE_PRESSED_ON; 49759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 49859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma states = KEY_STATE_NORMAL_ON; 49959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 50059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 50159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (sticky) { 50259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (pressed) { 50359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma states = KEY_STATE_PRESSED_OFF; 50459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 50559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma states = KEY_STATE_NORMAL_OFF; 50659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 50759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 50859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (pressed) { 50959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma states = KEY_STATE_PRESSED; 51059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return states; 51459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 51759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 51859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Creates a keyboard from the given xml key layout file. 51959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param context the application or service context 52059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. 52159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 52259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Keyboard(Context context, int xmlLayoutResId) { 52359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this(context, xmlLayoutResId, 0); 52459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 52559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 52659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 52759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Creates a keyboard from the given xml key layout file. Weeds out rows 52859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * that have a keyboard mode defined but don't match the specified mode. 52959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param context the application or service context 53059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. 53159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param modeId keyboard mode identifier 53259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 53359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Keyboard(Context context, int xmlLayoutResId, int modeId) { 53459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma DisplayMetrics dm = context.getResources().getDisplayMetrics(); 53559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDisplayWidth = dm.widthPixels; 53659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDisplayHeight = dm.heightPixels; 53759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 53859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultHorizontalGap = 0; 53959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultWidth = mDisplayWidth / 10; 54059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultVerticalGap = 0; 54159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultHeight = mDefaultWidth; 54259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeys = new ArrayList<Key>(); 54359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mModifierKeys = new ArrayList<Key>(); 54459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardMode = modeId; 54559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma loadKeyboard(context, context.getResources().getXml(xmlLayoutResId)); 54659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 54759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 54859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 54959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * <p>Creates a blank keyboard from the given resource file and populates it with the specified 55059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * characters in left-to-right, top-to-bottom fashion, using the specified number of columns. 55159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * </p> 55259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * <p>If the specified number of columns is -1, then the keyboard will fit as many keys as 55359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * possible in each row.</p> 55459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param context the application or service context 55559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param layoutTemplateResId the layout template file, containing no keys. 55659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param characters the list of characters to display on the keyboard. One key will be created 55759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * for each character. 55859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param columns the number of columns of keys to display. If this number is greater than the 55959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * number of keys that can fit in a row, it will be ignored. If this number is -1, the 56059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * keyboard will fit as many keys as possible in each row. 56159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 56259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Keyboard(Context context, int layoutTemplateResId, 56359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma CharSequence characters, int columns, int horizontalPadding) { 56459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this(context, layoutTemplateResId); 56559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int x = 0; 56659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int y = 0; 56759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int column = 0; 56859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTotalWidth = 0; 56959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 57059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Row row = new Row(this); 57159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma row.defaultHeight = mDefaultHeight; 57259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma row.defaultWidth = mDefaultWidth; 57359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma row.defaultHorizontalGap = mDefaultHorizontalGap; 57459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma row.verticalGap = mDefaultVerticalGap; 57559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma row.rowEdgeFlags = EDGE_TOP | EDGE_BOTTOM; 57659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns; 57759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i = 0; i < characters.length(); i++) { 57859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma char c = characters.charAt(i); 57959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (column >= maxColumns 58059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma || x + mDefaultWidth + horizontalPadding > mDisplayWidth) { 58159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma x = 0; 58259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma y += mDefaultVerticalGap + mDefaultHeight; 58359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma column = 0; 58459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 58559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key key = new Key(row); 58659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.x = x; 58759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.y = y; 58859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.label = String.valueOf(c); 58959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.codes = new int[] { c }; 59059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma column++; 59159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma x += key.width + key.gap; 59259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeys.add(key); 59359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (x > mTotalWidth) { 59459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTotalWidth = x; 59559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 59659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 59759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTotalHeight = y + mDefaultHeight; 59859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 59959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 60059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 60159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Get the list of keys in this keyboard. 60259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 60359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return The list of keys. 60459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 60559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public List<Key> getKeys() { 60659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mKeys; 60759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 60859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 60959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 61059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Get the list of modifier keys such as Shift & Alt, if any. 61159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 61259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return The list of modifier keys. 61359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 61459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public List<Key> getModifierKeys() { 61559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mModifierKeys; 61659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 61759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 61859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected int getHorizontalGap() { 61959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mDefaultHorizontalGap; 62059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 62159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 62259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void setHorizontalGap(int gap) { 62359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultHorizontalGap = gap; 62459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 62559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 62659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected int getVerticalGap() { 62759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mDefaultVerticalGap; 62859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 62959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 63059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void setVerticalGap(int gap) { 63159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultVerticalGap = gap; 63259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 63359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 63459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected int getKeyHeight() { 63559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mDefaultHeight; 63659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 63759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 63859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void setKeyHeight(int height) { 63959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultHeight = height; 64059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 64159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 64259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected int getKeyWidth() { 64359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mDefaultWidth; 64459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 64559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 64659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void setKeyWidth(int width) { 64759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultWidth = width; 64859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 64959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 65059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 65159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the total height of the keyboard 65259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the total height of the keyboard 65359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 65459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int getHeight() { 65559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mTotalHeight; 65659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 65759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 65859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 65959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the total minimum width of the keyboard 66059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the total minimum width of the keyboard 66159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 66259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int getMinWidth() { 66359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mTotalWidth; 66459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 66559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 66659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 66759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Sets the keyboard to be shifted. 66859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 66959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param shiftState the keyboard shift state. 67059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return {@code true} if shift state changed. 67159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 67259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean setShifted(boolean shiftState) { 67359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mShiftKey != null) { 67459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShiftKey.on = shiftState; 67559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 67659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mShifted != shiftState) { 67759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShifted = shiftState; 67859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 67959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 68059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 68159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 68259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 68359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 68459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns whether keyboard is shift state or not. 68559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 68659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return {@code true} if keyboard is shift state; otherwise, {@code false}. 68759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 68859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isShifted() { 68959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mShifted; 69059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 69159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 69259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 69359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the shift key index. 69459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 69559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the shift key index. 69659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 69759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int getShiftKeyIndex() { 69859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mShiftKeyIndex; 69959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 70059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 70159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void computeNearestNeighbors() { 70259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH; 70359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT; 70459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mGridNeighbors = new int[GRID_SIZE][]; 70559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int[] indices = new int[mKeys.size()]; 70659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int gridWidth = GRID_WIDTH * mCellWidth; 70759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int gridHeight = GRID_HEIGHT * mCellHeight; 70859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int x = 0; x < gridWidth; x += mCellWidth) { 70959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int y = 0; y < gridHeight; y += mCellHeight) { 71059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int count = 0; 71159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i = 0; i < mKeys.size(); i++) { 71259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key key = mKeys.get(i); 71359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.squaredDistanceFrom(x, y) < mProximityThreshold || 71459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.squaredDistanceFrom(x + mCellWidth - 1, y) < mProximityThreshold || 71559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1) 71659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma < mProximityThreshold || 71759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.squaredDistanceFrom(x, y + mCellHeight - 1) < mProximityThreshold || 71859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.isInside(x, y, mCellWidth, mCellHeight)) { 71959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma indices[count++] = i; 72059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 72159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 72259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int [] cell = new int[count]; 72359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma System.arraycopy(indices, 0, cell, 0, count); 72459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell; 72559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 72659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 72759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 72859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 72959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 73059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the indices of the keys that are closest to the given point. 73159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param x the x-coordinate of the point 73259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param y the y-coordinate of the point 73359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the array of integer indices for the nearest keys to the given point. If the given 73459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * point is out of range, then an array of size zero is returned. 73559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 73659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public int[] getNearestKeys(int x, int y) { 73759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mGridNeighbors == null) computeNearestNeighbors(); 73859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) { 73959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth); 74059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (index < GRID_SIZE) { 74159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mGridNeighbors[index]; 74259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 74359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 74459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return new int[0]; 74559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 74659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 74759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected Row createRowFromXml(Resources res, XmlResourceParser parser) { 74859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return new Row(res, this, parser); 74959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 75059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 75159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected Key createKeyFromXml(Resources res, Row parent, int x, int y, 75259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma XmlResourceParser parser) { 75359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return new Key(res, parent, x, y, parser); 75459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 75559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 75659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void loadKeyboard(Context context, XmlResourceParser parser) { 75759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean inKey = false; 75859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean inRow = false; 75959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean leftMostKey = false; 76059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int row = 0; 76159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int x = 0; 76259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int y = 0; 76359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Key key = null; 76459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Row currentRow = null; 76559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Resources res = context.getResources(); 76659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean skipRow = false; 76759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 76859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma try { 76959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int event; 77059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) { 77159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (event == XmlResourceParser.START_TAG) { 77259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma String tag = parser.getName(); 77359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (TAG_ROW.equals(tag)) { 77459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma inRow = true; 77559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma x = 0; 77659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma currentRow = createRowFromXml(res, parser); 77759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode; 77859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (skipRow) { 77959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma skipToEndOfRow(parser); 78059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma inRow = false; 78159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 78259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (TAG_KEY.equals(tag)) { 78359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma inKey = true; 78459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key = createKeyFromXml(res, currentRow, x, y, parser); 78559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeys.add(key); 78659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.codes[0] == KEYCODE_SHIFT) { 78759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShiftKey = key; 78859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShiftKeyIndex = mKeys.size()-1; 78959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mModifierKeys.add(key); 79059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (key.codes[0] == KEYCODE_ALT) { 79159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mModifierKeys.add(key); 79259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 79359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (TAG_KEYBOARD.equals(tag)) { 79459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma parseKeyboardAttributes(res, parser); 79559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 79659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (event == XmlResourceParser.END_TAG) { 79759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (inKey) { 79859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma inKey = false; 79959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma x += key.gap + key.width; 80059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (x > mTotalWidth) { 80159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTotalWidth = x; 80259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 80359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (inRow) { 80459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma inRow = false; 80559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma y += currentRow.verticalGap; 80659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma y += currentRow.defaultHeight; 80759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma row++; 80859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 80959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 81059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 81159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 81259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } catch (Exception e) { 81359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Log.e(TAG, "Parse error:" + e); 81459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma e.printStackTrace(); 81559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 81659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTotalHeight = y - mDefaultVerticalGap; 81759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 81859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 81959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void skipToEndOfRow(XmlResourceParser parser) 82059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma throws XmlPullParserException, IOException { 82159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int event; 82259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) { 82359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (event == XmlResourceParser.END_TAG 82459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && parser.getName().equals(TAG_ROW)) { 82559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 82659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 82759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 82859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 82959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 83059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void parseKeyboardAttributes(Resources res, XmlResourceParser parser) { 83159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), 83259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard); 83359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 83459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultWidth = getDimensionOrFraction(a, 83559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_keyWidth, 83659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDisplayWidth, mDisplayWidth / 10); 83759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultHeight = getDimensionOrFraction(a, 83859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_keyHeight, 83959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDisplayHeight, 75); 84059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultHorizontalGap = getDimensionOrFraction(a, 84159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_horizontalGap, 84259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDisplayWidth, 0); 84359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDefaultVerticalGap = getDimensionOrFraction(a, 84459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Keyboard_verticalGap, 84559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDisplayHeight, 0); 84659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mProximityThreshold = (int) (mDefaultWidth * SEARCH_DISTANCE); 84759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mProximityThreshold = mProximityThreshold * mProximityThreshold; 84859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.recycle(); 84959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 85059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 85159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma static int getDimensionOrFraction(TypedArray a, int index, int base, int defValue) { 85259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma TypedValue value = a.peekValue(index); 85359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (value == null) return defValue; 85459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (value.type == TypedValue.TYPE_DIMENSION) { 85559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return a.getDimensionPixelOffset(index, defValue); 85659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (value.type == TypedValue.TYPE_FRACTION) { 85759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return Math.round(a.getFraction(index, base, base, defValue)); 85859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 85959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return defValue; 86059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 86159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma} 862