【SoftKeyboard研究系列】Keyboard研究

一、Keyboard doc位置


本地:%ANDROID_HOME%/sdk/docs/reference/android/inputmethodservice/Keyboard.html

Web:


二、Keyboard doc内容



public class

Keyboard

extends  Object
java.lang.Object
   ↳ android.inputmethodservice.Keyboard

Class Overview


Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard consists of rows of keys.

The layout file for a keyboard contains XML that looks like the following snippet:

 <Keyboard
         android:keyWidth="%10p"
         android:keyHeight="50px"
         android:horizontalGap="2px"
         android:verticalGap="2px" >
     <Row android:keyWidth="32px" >
         <Key android:keyLabel="A" />
         ...
     </Row>
     ...
 </Keyboard>
 

Summary


Nested Classes
class Keyboard.Key Class for describing the position and characteristics of a single key in the keyboard. 
class Keyboard.Row Container for keys in the keyboard. 

XML Attributes
Attribute Name Related Method Description
android:horizontalGap   Default horizontal gap between keys. 
android:keyHeight   Default height of a key, in pixels or percentage of display width. 
android:keyWidth   Default width of a key, in pixels or percentage of display width. 
android:verticalGap   Default vertical gap between rows of keys. 
Constants
int EDGE_BOTTOM  
int EDGE_LEFT  
int EDGE_RIGHT  
int EDGE_TOP  
int KEYCODE_ALT  
int KEYCODE_CANCEL  
int KEYCODE_DELETE  
int KEYCODE_DONE  
int KEYCODE_MODE_CHANGE  
int KEYCODE_SHIFT  
Public Constructors
Keyboard( Context context, int xmlLayoutResId)
Creates a keyboard from the given xml key layout file.
Keyboard( Context context, int xmlLayoutResId, int modeId, int width, int height)
Creates a keyboard from the given xml key layout file.
Keyboard( Context context, int xmlLayoutResId, int modeId)
Creates a keyboard from the given xml key layout file.
Keyboard( Context context, int layoutTemplateResId,  CharSequence characters, int columns, int horizontalPadding)

Creates a blank keyboard from the given resource file and populates it with the specified characters in left-to-right, top-to-bottom fashion, using the specified number of columns.

Public Methods
int getHeight()
Returns the total height of the keyboard
List< Keyboard.Key> getKeys()
int getMinWidth()
List< Keyboard.Key> getModifierKeys()
int[] getNearestKeys(int x, int y)
Returns the indices of the keys that are closest to the given point.
int getShiftKeyIndex()
boolean isShifted()
boolean setShifted(boolean shiftState)
Protected Methods
Keyboard.Key createKeyFromXml( Resources res,  Keyboard.Row parent, int x, int y,  XmlResourceParser parser)
Keyboard.Row createRowFromXml( Resources res,  XmlResourceParser parser)
int getHorizontalGap()
int getKeyHeight()
int getKeyWidth()
int getVerticalGap()
void setHorizontalGap(int gap)
void setKeyHeight(int height)
void setKeyWidth(int width)
void setVerticalGap(int gap)
[Expand]
Inherited Methods
From class java.lang.Object

XML Attributes


 

android:horizontalGap

Default horizontal gap between keys.

May be a dimension value, which is a floating point number appended with a unit such as "14.5sp". Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), in (inches), mm (millimeters).

May be a fractional value, which is a floating point number appended with either % or %p, such as "14.5%". The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to some parent container.

This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

This corresponds to the global attribute resource symbol horizontalGap.

Related Methods

     

    android:keyHeight

    Default height of a key, in pixels or percentage of display width.

    May be a dimension value, which is a floating point number appended with a unit such as "14.5sp". Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), in (inches), mm (millimeters).

    May be a fractional value, which is a floating point number appended with either % or %p, such as "14.5%". The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to some parent container.

    This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

    This corresponds to the global attribute resource symbol keyHeight.

    Related Methods

       

      android:keyWidth

      Default width of a key, in pixels or percentage of display width.

      May be a dimension value, which is a floating point number appended with a unit such as "14.5sp". Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), in (inches), mm (millimeters).

      May be a fractional value, which is a floating point number appended with either % or %p, such as "14.5%". The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to some parent container.

      This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

      This corresponds to the global attribute resource symbol keyWidth.

      Related Methods

         

        android:verticalGap

        Default vertical gap between rows of keys.

        May be a dimension value, which is a floating point number appended with a unit such as "14.5sp". Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), in (inches), mm (millimeters).

        May be a fractional value, which is a floating point number appended with either % or %p, such as "14.5%". The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to some parent container.

        This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

        This corresponds to the global attribute resource symbol verticalGap.

        Related Methods

          Constants


           

          public static final int EDGE_BOTTOM
          Added in  API level 3

          Constant Value: 8 (0x00000008)

           

          public static final int EDGE_LEFT
          Added in  API level 3

          Constant Value: 1 (0x00000001)

           

          public static final int EDGE_RIGHT
          Added in  API level 3

          Constant Value: 2 (0x00000002)

           

          public static final int EDGE_TOP
          Added in  API level 3

          Constant Value: 4 (0x00000004)

           

          public static final int KEYCODE_ALT
          Added in  API level 3

          Constant Value: -6 (0xfffffffa)

           

          public static final int KEYCODE_CANCEL
          Added in  API level 3

          Constant Value: -3 (0xfffffffd)

           

          public static final int KEYCODE_DELETE
          Added in  API level 3

          Constant Value: -5 (0xfffffffb)

           

          public static final int KEYCODE_DONE
          Added in  API level 3

          Constant Value: -4 (0xfffffffc)

           

          public static final int KEYCODE_MODE_CHANGE
          Added in  API level 3

          Constant Value: -2 (0xfffffffe)

           

          public static final int KEYCODE_SHIFT
          Added in  API level 3

          Constant Value: -1 (0xffffffff)

          Public Constructors


           

          public Keyboard (Context context, int xmlLayoutResId)
          Added in  API level 3

          Creates a keyboard from the given xml key layout file.

          Parameters
          context the application or service context
          xmlLayoutResId the resource file that contains the keyboard layout and keys.

           

          public Keyboard (Context context, int xmlLayoutResId, int modeId, int width, int height)
          Added in  API level 11

          Creates a keyboard from the given xml key layout file. Weeds out rows that have a keyboard mode defined but don't match the specified mode.

          Parameters
          context the application or service context
          xmlLayoutResId the resource file that contains the keyboard layout and keys.
          modeId keyboard mode identifier
          width sets width of keyboard
          height sets height of keyboard

           

          public Keyboard (Context context, int xmlLayoutResId, int modeId)
          Added in  API level 3

          Creates a keyboard from the given xml key layout file. Weeds out rows that have a keyboard mode defined but don't match the specified mode.

          Parameters
          context the application or service context
          xmlLayoutResId the resource file that contains the keyboard layout and keys.
          modeId keyboard mode identifier

           

          public Keyboard (Context context, int layoutTemplateResId, CharSequence characters, int columns, int horizontalPadding)
          Added in  API level 3

          Creates a blank keyboard from the given resource file and populates it with the specified characters in left-to-right, top-to-bottom fashion, using the specified number of columns.

          If the specified number of columns is -1, then the keyboard will fit as many keys as possible in each row.

          Parameters
          context the application or service context
          layoutTemplateResId the layout template file, containing no keys.
          characters the list of characters to display on the keyboard. One key will be created for each character.
          columns the number of columns of keys to display. If this number is greater than the number of keys that can fit in a row, it will be ignored. If this number is -1, the keyboard will fit as many keys as possible in each row.

          Public Methods


           

          public int getHeight ()
          Added in  API level 3

          Returns the total height of the keyboard

          Returns
          • the total height of the keyboard

           

          public List<Keyboard.KeygetKeys ()
          Added in  API level 3

           

          public int getMinWidth ()
          Added in  API level 3

           

          public List<Keyboard.KeygetModifierKeys ()
          Added in  API level 3

           

          public int[] getNearestKeys (int x, int y)
          Added in  API level 3

          Returns the indices of the keys that are closest to the given point.

          Parameters
          x the x-coordinate of the point
          y the y-coordinate of the point
          Returns
          • the array of integer indices for the nearest keys to the given point. If the given point is out of range, then an array of size zero is returned.

           

          public int getShiftKeyIndex ()
          Added in  API level 3

           

          public boolean isShifted ()
          Added in  API level 3

           

          public boolean setShifted (boolean shiftState)
          Added in  API level 3

          Protected Methods


           

          protected Keyboard.Key createKeyFromXml (Resources res, Keyboard.Row parent, int x, int y, XmlResourceParserparser)
          Added in  API level 3

           

          protected Keyboard.Row createRowFromXml (Resources res, XmlResourceParser parser)
          Added in  API level 3

           

          protected int getHorizontalGap ()
          Added in  API level 3

           

          protected int getKeyHeight ()
          Added in  API level 3

           

          protected int getKeyWidth ()
          Added in  API level 3

           

          protected int getVerticalGap ()
          Added in  API level 3

           

          protected void setHorizontalGap (int gap)
          Added in  API level 3

           

          protected void setKeyHeight (int height)
          Added in  API level 3

           

          protected void setKeyWidth (int width)
          Added in  API level 3

           

          protected void setVerticalGap (int gap)
          Added in  API level 3


          三、Keyboard源码


          /*
           * Copyright (C) 2008-2009 Google Inc.
           * 
           * Licensed under the Apache License, Version 2.0 (the "License"); you may not
           * use this file except in compliance with the License. You may obtain a copy of
           * the License at
           * 
           * http://www.apache.org/licenses/LICENSE-2.0
           * 
           * Unless required by applicable law or agreed to in writing, software
           * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
           * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
           * License for the specific language governing permissions and limitations under
           * the License.
           */
          
          package android.inputmethodservice;
          
          import org.xmlpull.v1.XmlPullParserException;
          
          import android.content.Context;
          import android.content.res.Resources;
          import android.content.res.TypedArray;
          import android.content.res.XmlResourceParser;
          import android.graphics.drawable.Drawable;
          import android.text.TextUtils;
          import android.util.Log;
          import android.util.TypedValue;
          import android.util.Xml;
          import android.util.DisplayMetrics;
          
          import java.io.IOException;
          import java.util.ArrayList;
          import java.util.List;
          import java.util.StringTokenizer;
          
          
          /**
           * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
           * consists of rows of keys.
           * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
           * <pre>
           * <Keyboard
           *         android:keyWidth="%10p"
           *         android:keyHeight="50px"
           *         android:horizontalGap="2px"
           *         android:verticalGap="2px" >
           *     <Row android:keyWidth="32px" >
           *         <Key android:keyLabel="A" />
           *         ...
           *     </Row>
           *     ...
           * </Keyboard>
           * </pre>
           * @attr ref android.R.styleable#Keyboard_keyWidth
           * @attr ref android.R.styleable#Keyboard_keyHeight
           * @attr ref android.R.styleable#Keyboard_horizontalGap
           * @attr ref android.R.styleable#Keyboard_verticalGap
           */
          public class Keyboard {
          
              static final String TAG = "Keyboard";
              
              // Keyboard XML Tags
              private static final String TAG_KEYBOARD = "Keyboard";
              private static final String TAG_ROW = "Row";
              private static final String TAG_KEY = "Key";
          
              public static final int EDGE_LEFT = 0x01;
              public static final int EDGE_RIGHT = 0x02;
              public static final int EDGE_TOP = 0x04;
              public static final int EDGE_BOTTOM = 0x08;
          
              public static final int KEYCODE_SHIFT = -1;
              public static final int KEYCODE_MODE_CHANGE = -2;
              public static final int KEYCODE_CANCEL = -3;
              public static final int KEYCODE_DONE = -4;
              public static final int KEYCODE_DELETE = -5;
              public static final int KEYCODE_ALT = -6;
              
              /** Keyboard label **/
              private CharSequence mLabel;
          
              /** Horizontal gap default for all rows */
              private int mDefaultHorizontalGap;
              
              /** Default key width */
              private int mDefaultWidth;
          
              /** Default key height */
              private int mDefaultHeight;
          
              /** Default gap between rows */
              private int mDefaultVerticalGap;
          
              /** Is the keyboard in the shifted state */
              private boolean mShifted;
              
              /** Key instance for the shift key, if present */
              private Key[] mShiftKeys = { null, null };
          
              /** Key index for the shift key, if present */
              private int[] mShiftKeyIndices = {-1, -1};
          
              /** Current key width, while loading the keyboard */
              private int mKeyWidth;
              
              /** Current key height, while loading the keyboard */
              private int mKeyHeight;
              
              /** Total height of the keyboard, including the padding and keys */
              private int mTotalHeight;
              
              /** 
               * Total width of the keyboard, including left side gaps and keys, but not any gaps on the
               * right side.
               */
              private int mTotalWidth;
              
              /** List of keys in this keyboard */
              private List<Key> mKeys;
              
              /** List of modifier keys such as Shift & Alt, if any */
              private List<Key> mModifierKeys;
              
              /** Width of the screen available to fit the keyboard */
              private int mDisplayWidth;
          
              /** Height of the screen */
              private int mDisplayHeight;
          
              /** Keyboard mode, or zero, if none.  */
              private int mKeyboardMode;
          
              // Variables for pre-computing nearest keys.
              
              private static final int GRID_WIDTH = 10;
              private static final int GRID_HEIGHT = 5;
              private static final int GRID_SIZE = GRID_WIDTH * GRID_HEIGHT;
              private int mCellWidth;
              private int mCellHeight;
              private int[][] mGridNeighbors;
              private int mProximityThreshold;
              /** Number of key widths from current touch point to search for nearest keys. */
              private static float SEARCH_DISTANCE = 1.8f;
          
              private ArrayList<Row> rows = new ArrayList<Row>();
          
              /**
              public static class Row { }
          	public static class Key { }
          	*/
          	
              /**
               * Creates a keyboard from the given xml key layout file.
               * @param context the application or service context
               * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
               */
              public Keyboard(Context context, int xmlLayoutResId) {
                  this(context, xmlLayoutResId, 0);
              }
          
              /**
               * Creates a keyboard from the given xml key layout file. Weeds out rows
               * that have a keyboard mode defined but don't match the specified mode.
               * @param context the application or service context
               * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
               * @param modeId keyboard mode identifier
               * @param width sets width of keyboard
               * @param height sets height of keyboard
               */
              public Keyboard(Context context, int xmlLayoutResId, int modeId, int width, int height) {
                  mDisplayWidth = width;
                  mDisplayHeight = height;
          
                  mDefaultHorizontalGap = 0;
                  mDefaultWidth = mDisplayWidth / 10;
                  mDefaultVerticalGap = 0;
                  mDefaultHeight = mDefaultWidth;
                  mKeys = new ArrayList<Key>();
                  mModifierKeys = new ArrayList<Key>();
                  mKeyboardMode = modeId;
                  loadKeyboard(context, context.getResources().getXml(xmlLayoutResId));
              }
          
              /**
               * Creates a keyboard from the given xml key layout file. Weeds out rows
               * that have a keyboard mode defined but don't match the specified mode. 
               * @param context the application or service context
               * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
               * @param modeId keyboard mode identifier
               */
              public Keyboard(Context context, int xmlLayoutResId, int modeId) {
                  DisplayMetrics dm = context.getResources().getDisplayMetrics();
                  mDisplayWidth = dm.widthPixels;
                  mDisplayHeight = dm.heightPixels;
                  //Log.v(TAG, "keyboard's display metrics:" + dm);
          
                  mDefaultHorizontalGap = 0;
                  mDefaultWidth = mDisplayWidth / 10;
                  mDefaultVerticalGap = 0;
                  mDefaultHeight = mDefaultWidth;
                  mKeys = new ArrayList<Key>();
                  mModifierKeys = new ArrayList<Key>();
                  mKeyboardMode = modeId;
                  loadKeyboard(context, context.getResources().getXml(xmlLayoutResId));
              }
          
              /**
               * <p>Creates a blank keyboard from the given resource file and populates it with the specified
               * characters in left-to-right, top-to-bottom fashion, using the specified number of columns.
               * </p>
               * <p>If the specified number of columns is -1, then the keyboard will fit as many keys as
               * possible in each row.</p>
               * @param context the application or service context
               * @param layoutTemplateResId the layout template file, containing no keys.
               * @param characters the list of characters to display on the keyboard. One key will be created
               * for each character.
               * @param columns the number of columns of keys to display. If this number is greater than the 
               * number of keys that can fit in a row, it will be ignored. If this number is -1, the 
               * keyboard will fit as many keys as possible in each row.
               */
              public Keyboard(Context context, int layoutTemplateResId, 
                      CharSequence characters, int columns, int horizontalPadding) {
                  this(context, layoutTemplateResId);
                  int x = 0;
                  int y = 0;
                  int column = 0;
                  mTotalWidth = 0;
                  
                  Row row = new Row(this);
                  row.defaultHeight = mDefaultHeight;
                  row.defaultWidth = mDefaultWidth;
                  row.defaultHorizontalGap = mDefaultHorizontalGap;
                  row.verticalGap = mDefaultVerticalGap;
                  row.rowEdgeFlags = EDGE_TOP | EDGE_BOTTOM;
                  final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns;
                  for (int i = 0; i < characters.length(); i++) {
                      char c = characters.charAt(i);
                      if (column >= maxColumns 
                              || x + mDefaultWidth + horizontalPadding > mDisplayWidth) {
                          x = 0;
                          y += mDefaultVerticalGap + mDefaultHeight;
                          column = 0;
                      }
                      final Key key = new Key(row);
                      key.x = x;
                      key.y = y;
                      key.label = String.valueOf(c);
                      key.codes = new int[] { c };
                      column++;
                      x += key.width + key.gap;
                      mKeys.add(key);
                      row.mKeys.add(key);
                      if (x > mTotalWidth) {
                          mTotalWidth = x;
                      }
                  }
                  mTotalHeight = y + mDefaultHeight;
                  rows.add(row);
              }
          
              final void resize(int newWidth, int newHeight) {
                  int numRows = rows.size();
                  for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) {
                      Row row = rows.get(rowIndex);
                      int numKeys = row.mKeys.size();
                      int totalGap = 0;
                      int totalWidth = 0;
                      for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) {
                          Key key = row.mKeys.get(keyIndex);
                          if (keyIndex > 0) {
                              totalGap += key.gap;
                          }
                          totalWidth += key.width;
                      }
                      if (totalGap + totalWidth > newWidth) {
                          int x = 0;
                          float scaleFactor = (float)(newWidth - totalGap) / totalWidth;
                          for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) {
                              Key key = row.mKeys.get(keyIndex);
                              key.width *= scaleFactor;
                              key.x = x;
                              x += key.width + key.gap;
                          }
                      }
                  }
                  mTotalWidth = newWidth;
                  // TODO: This does not adjust the vertical placement according to the new size.
                  // The main problem in the previous code was horizontal placement/size, but we should
                  // also recalculate the vertical sizes/positions when we get this resize call.
              }
              
              public List<Key> getKeys() {
                  return mKeys;
              }
              
              public List<Key> getModifierKeys() {
                  return mModifierKeys;
              }
              
              protected int getHorizontalGap() {
                  return mDefaultHorizontalGap;
              }
              
              protected void setHorizontalGap(int gap) {
                  mDefaultHorizontalGap = gap;
              }
          
              protected int getVerticalGap() {
                  return mDefaultVerticalGap;
              }
          
              protected void setVerticalGap(int gap) {
                  mDefaultVerticalGap = gap;
              }
          
              protected int getKeyHeight() {
                  return mDefaultHeight;
              }
          
              protected void setKeyHeight(int height) {
                  mDefaultHeight = height;
              }
          
              protected int getKeyWidth() {
                  return mDefaultWidth;
              }
              
              protected void setKeyWidth(int width) {
                  mDefaultWidth = width;
              }
          
              /**
               * Returns the total height of the keyboard
               * @return the total height of the keyboard
               */
              public int getHeight() {
                  return mTotalHeight;
              }
              
              public int getMinWidth() {
                  return mTotalWidth;
              }
          
              public boolean setShifted(boolean shiftState) {
                  for (Key shiftKey : mShiftKeys) {
                      if (shiftKey != null) {
                          shiftKey.on = shiftState;
                      }
                  }
                  if (mShifted != shiftState) {
                      mShifted = shiftState;
                      return true;
                  }
                  return false;
              }
          
              public boolean isShifted() {
                  return mShifted;
              }
          
              /**
               * @hide
               */
              public int[] getShiftKeyIndices() {
                  return mShiftKeyIndices;
              }
          
              public int getShiftKeyIndex() {
                  return mShiftKeyIndices[0];
              }
              
              private void computeNearestNeighbors() {
                  // Round-up so we don't have any pixels outside the grid
                  mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH;
                  mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT;
                  mGridNeighbors = new int[GRID_SIZE][];
                  int[] indices = new int[mKeys.size()];
                  final int gridWidth = GRID_WIDTH * mCellWidth;
                  final int gridHeight = GRID_HEIGHT * mCellHeight;
                  for (int x = 0; x < gridWidth; x += mCellWidth) {
                      for (int y = 0; y < gridHeight; y += mCellHeight) {
                          int count = 0;
                          for (int i = 0; i < mKeys.size(); i++) {
                              final Key key = mKeys.get(i);
                              if (key.squaredDistanceFrom(x, y) < mProximityThreshold ||
                                      key.squaredDistanceFrom(x + mCellWidth - 1, y) < mProximityThreshold ||
                                      key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1) 
                                          < mProximityThreshold ||
                                      key.squaredDistanceFrom(x, y + mCellHeight - 1) < mProximityThreshold) {
                                  indices[count++] = i;
                              }
                          }
                          int [] cell = new int[count];
                          System.arraycopy(indices, 0, cell, 0, count);
                          mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell;
                      }
                  }
              }
              
              /**
               * Returns the indices of the keys that are closest to the given point.
               * @param x the x-coordinate of the point
               * @param y the y-coordinate of the point
               * @return the array of integer indices for the nearest keys to the given point. If the given
               * point is out of range, then an array of size zero is returned.
               */
              public int[] getNearestKeys(int x, int y) {
                  if (mGridNeighbors == null) computeNearestNeighbors();
                  if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) {
                      int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth);
                      if (index < GRID_SIZE) {
                          return mGridNeighbors[index];
                      }
                  }
                  return new int[0];
              }
          
              protected Row createRowFromXml(Resources res, XmlResourceParser parser) {
                  return new Row(res, this, parser);
              }
              
              protected Key createKeyFromXml(Resources res, Row parent, int x, int y, 
                      XmlResourceParser parser) {
                  return new Key(res, parent, x, y, parser);
              }
          
              private void loadKeyboard(Context context, XmlResourceParser parser) {
                  boolean inKey = false;
                  boolean inRow = false;
                  boolean leftMostKey = false;
                  int row = 0;
                  int x = 0;
                  int y = 0;
                  Key key = null;
                  Row currentRow = null;
                  Resources res = context.getResources();
                  boolean skipRow = false;
          
                  try {
                      int event;
                      while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
                          if (event == XmlResourceParser.START_TAG) {
                              String tag = parser.getName();
                              if (TAG_ROW.equals(tag)) {
                                  inRow = true;
                                  x = 0;
                                  currentRow = createRowFromXml(res, parser);
                                  rows.add(currentRow);
                                  skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode;
                                  if (skipRow) {
                                      skipToEndOfRow(parser);
                                      inRow = false;
                                  }
                             } else if (TAG_KEY.equals(tag)) {
                                  inKey = true;
                                  key = createKeyFromXml(res, currentRow, x, y, parser);
                                  mKeys.add(key);
                                  if (key.codes[0] == KEYCODE_SHIFT) {
                                      // Find available shift key slot and put this shift key in it
                                      for (int i = 0; i < mShiftKeys.length; i++) {
                                          if (mShiftKeys[i] == null) {
                                              mShiftKeys[i] = key;
                                              mShiftKeyIndices[i] = mKeys.size()-1;
                                              break;
                                          }
                                      }
                                      mModifierKeys.add(key);
                                  } else if (key.codes[0] == KEYCODE_ALT) {
                                      mModifierKeys.add(key);
                                  }
                                  currentRow.mKeys.add(key);
                              } else if (TAG_KEYBOARD.equals(tag)) {
                                  parseKeyboardAttributes(res, parser);
                              }
                          } else if (event == XmlResourceParser.END_TAG) {
                              if (inKey) {
                                  inKey = false;
                                  x += key.gap + key.width;
                                  if (x > mTotalWidth) {
                                      mTotalWidth = x;
                                  }
                              } else if (inRow) {
                                  inRow = false;
                                  y += currentRow.verticalGap;
                                  y += currentRow.defaultHeight;
                                  row++;
                              } else {
                                  // TODO: error or extend?
                              }
                          }
                      }
                  } catch (Exception e) {
                      Log.e(TAG, "Parse error:" + e);
                      e.printStackTrace();
                  }
                  mTotalHeight = y - mDefaultVerticalGap;
              }
          
              private void skipToEndOfRow(XmlResourceParser parser) 
                      throws XmlPullParserException, IOException {
                  int event;
                  while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
                      if (event == XmlResourceParser.END_TAG 
                              && parser.getName().equals(TAG_ROW)) {
                          break;
                      }
                  }
              }
              
              private void parseKeyboardAttributes(Resources res, XmlResourceParser parser) {
                  TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), 
                          com.android.internal.R.styleable.Keyboard);
          
                  mDefaultWidth = getDimensionOrFraction(a,
                          com.android.internal.R.styleable.Keyboard_keyWidth,
                          mDisplayWidth, mDisplayWidth / 10);
                  mDefaultHeight = getDimensionOrFraction(a,
                          com.android.internal.R.styleable.Keyboard_keyHeight,
                          mDisplayHeight, 50);
                  mDefaultHorizontalGap = getDimensionOrFraction(a,
                          com.android.internal.R.styleable.Keyboard_horizontalGap,
                          mDisplayWidth, 0);
                  mDefaultVerticalGap = getDimensionOrFraction(a,
                          com.android.internal.R.styleable.Keyboard_verticalGap,
                          mDisplayHeight, 0);
                  mProximityThreshold = (int) (mDefaultWidth * SEARCH_DISTANCE);
                  mProximityThreshold = mProximityThreshold * mProximityThreshold; // Square it for comparison
                  a.recycle();
              }
              
              static int getDimensionOrFraction(TypedArray a, int index, int base, int defValue) {
                  TypedValue value = a.peekValue(index);
                  if (value == null) return defValue;
                  if (value.type == TypedValue.TYPE_DIMENSION) {
                      return a.getDimensionPixelOffset(index, defValue);
                  } else if (value.type == TypedValue.TYPE_FRACTION) {
                      // Round it to avoid values like 47.9999 from getting truncated
                      return Math.round(a.getFraction(index, base, base, defValue));
                  }
                  return defValue;
              }
          }
          



          四、Keyboard研究



          评论
          添加红包

          请填写红包祝福语或标题

          红包个数最小为10个

          红包金额最低5元

          当前余额3.43前往充值 >
          需支付:10.00
          成就一亿技术人!
          领取后你会自动成为博主和红包主的粉丝 规则
          hope_wisdom
          发出的红包
          实付
          使用余额支付
          点击重新获取
          扫码支付
          钱包余额 0

          抵扣说明:

          1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
          2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

          余额充值