Keyboardpublic class Keyboard extends Object 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>
|
Fields Summary |
---|
static final String | TAG | private static final String | TAG_KEYBOARD | private static final String | TAG_ROW | private static final String | TAG_KEY | public static final int | EDGE_LEFT | public static final int | EDGE_RIGHT | public static final int | EDGE_TOP | public static final int | EDGE_BOTTOM | public static final int | KEYCODE_SHIFT | public static final int | KEYCODE_MODE_CHANGE | public static final int | KEYCODE_CANCEL | public static final int | KEYCODE_DONE | public static final int | KEYCODE_DELETE | public static final int | KEYCODE_ALT | private CharSequence | mLabelKeyboard label | private int | mDefaultHorizontalGapHorizontal gap default for all rows | private int | mDefaultWidthDefault key width | private int | mDefaultHeightDefault key height | private int | mDefaultVerticalGapDefault gap between rows | private boolean | mShiftedIs the keyboard in the shifted state | private Key | mShiftKeyKey instance for the shift key, if present | private int | mShiftKeyIndexKey index for the shift key, if present | private int | mKeyWidthCurrent key width, while loading the keyboard | private int | mKeyHeightCurrent key height, while loading the keyboard | private int | mTotalHeightTotal height of the keyboard, including the padding and keys | private int | mTotalWidthTotal width of the keyboard, including left side gaps and keys, but not any gaps on the
right side. | private List | mKeysList of keys in this keyboard | private List | mModifierKeysList of modifier keys such as Shift & Alt, if any | private int | mDisplayWidthWidth of the screen available to fit the keyboard | private int | mDisplayHeightHeight of the screen | private int | mKeyboardModeKeyboard mode, or zero, if none. | private static final int | GRID_WIDTH | private static final int | GRID_HEIGHT | private static final int | GRID_SIZE | private int | mCellWidth | private int | mCellHeight | private int[] | mGridNeighbors | private int | mProximityThreshold | private static float | SEARCH_DISTANCENumber of key widths from current touch point to search for nearest keys. |
Constructors Summary |
---|
public Keyboard(android.content.Context context, int xmlLayoutResId)Creates a keyboard from the given xml key layout file.
this(context, xmlLayoutResId, 0);
| public Keyboard(android.content.Context context, int xmlLayoutResId, int modeId)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.
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
mDisplayWidth = display.getWidth();
mDisplayHeight = display.getHeight();
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));
| public Keyboard(android.content.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.
If the specified number of columns is -1, then the keyboard will fit as many keys as
possible in each row.
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.width = mDefaultWidth;
key.height = mDefaultHeight;
key.gap = mDefaultHorizontalGap;
key.label = String.valueOf(c);
key.codes = new int[] { c };
column++;
x += key.width + key.gap;
mKeys.add(key);
if (x > mTotalWidth) {
mTotalWidth = x;
}
}
mTotalHeight = y + mDefaultHeight;
|
Methods Summary |
---|
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;
}
}
| protected android.inputmethodservice.Keyboard$Key | createKeyFromXml(android.content.res.Resources res, android.inputmethodservice.Keyboard$Row parent, int x, int y, android.content.res.XmlResourceParser parser)
return new Key(res, parent, x, y, parser);
| protected android.inputmethodservice.Keyboard$Row | createRowFromXml(android.content.res.Resources res, android.content.res.XmlResourceParser parser)
return new Row(res, this, parser);
| static int | getDimensionOrFraction(android.content.res.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;
| public int | getHeight()Returns the total height of the keyboard
return mTotalHeight;
| protected int | getHorizontalGap()
return mDefaultHorizontalGap;
| protected int | getKeyHeight()
return mDefaultHeight;
| protected int | getKeyWidth()
return mDefaultWidth;
| public java.util.List | getKeys()
return mKeys;
| public int | getMinWidth()
return mTotalWidth;
| public java.util.List | getModifierKeys()
return mModifierKeys;
| public int[] | getNearestKeys(int x, int y)Returns the indices of the keys that are closest to the given point.
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];
| public int | getShiftKeyIndex()
return mShiftKeyIndex;
| protected int | getVerticalGap()
return mDefaultVerticalGap;
| public boolean | isShifted()
return mShifted;
| private void | loadKeyboard(android.content.Context context, android.content.res.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);
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) {
mShiftKey = key;
mShiftKeyIndex = mKeys.size()-1;
mModifierKeys.add(key);
} else if (key.codes[0] == KEYCODE_ALT) {
mModifierKeys.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 | parseKeyboardAttributes(android.content.res.Resources res, android.content.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();
| protected void | setHorizontalGap(int gap)
mDefaultHorizontalGap = gap;
| protected void | setKeyHeight(int height)
mDefaultHeight = height;
| protected void | setKeyWidth(int width)
mDefaultWidth = width;
| public boolean | setShifted(boolean shiftState)
if (mShiftKey != null) {
mShiftKey.on = shiftState;
}
if (mShifted != shiftState) {
mShifted = shiftState;
return true;
}
return false;
| protected void | setVerticalGap(int gap)
mDefaultVerticalGap = gap;
| private void | skipToEndOfRow(android.content.res.XmlResourceParser parser)
int event;
while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
if (event == XmlResourceParser.END_TAG
&& parser.getName().equals(TAG_ROW)) {
break;
}
}
|
|