summaryrefslogtreecommitdiff
path: root/core/java/android/view/KeyCharacterMap.java
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2010-11-10 16:03:06 -0800
committerJeff Brown <jeffbrown@google.com>2010-11-18 09:49:03 -0800
commit6b53e8daa69cba1a2a5a7c95a01e37ce9c53226c (patch)
treedb912c6cdf230ef7f2cf406c545b3bbae3f09ea2 /core/java/android/view/KeyCharacterMap.java
parenta914f340ae5b267dc3ab36c1156c795b8fa18f5d (diff)
Added support for full PC-style keyboards.
BREAKING CHANGE: Redesigned the key character map format to accomodate full keyboards with more comprehensive suite of modifiers. Old key character maps will not work anymore and must be updated. The new format is plain text only and it not compiled to a binary file (so the "kcm" tool will be removed in a subsequent check-in). Added FULL keyboard type to support full PC-style keyboards. Added SPECIAL_FUNCTION keyboard type to support special function keypads that do not have any printable keys suitable for typing and only have keys like HOME and POWER Added a special VIRTUAL_KEYBOARD device id convention that maps to a virtual keyboard with a fixed known layout. This is designed to work around issues injecting input events on devices whose built-in keyboard does not have a useful key character map (ie. when the built-in keyboard is a special function keyboard only.) Modified several places where events were being synthesized to use the virtual keyboard. Removed support for the "qwerty" default layout. The new default layout is "Generic". For the most part "qwerty" was being used as a backstop in case the built-in keyboard did not have a key character map (probably because it was a special function keypad) and the framework needed to be able to inject key events anyways. The latter issue is resolved by using the special VIRTUAL_KEYBOARD device instead of BUILT_IN_KEYBOARD. Added the concept of a key modifier behavior so that MetaKeyKeyListener can distinguish between keyboards that use chorded vs. toggled modifiers. Wrote more robust key layout and key character map parsers to enable support for new keyboard features and user installable key maps. Fixed a bug in InputReader generating key ups when keys are released out of sequence. Updated tons of documentation. Currently QwertyKeyListener is being used for full keyboards with autotext and capitalization disabled. This mostly works but causes some problems with character pickers, etc. These issues will be resolved in subsequent changes. Change-Id: Ica48f6097a551141c215bc0d2c6f7b3fb634d354
Diffstat (limited to 'core/java/android/view/KeyCharacterMap.java')
-rw-r--r--core/java/android/view/KeyCharacterMap.java524
1 files changed, 316 insertions, 208 deletions
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 9981d877ce02..fbd9eaca2574 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -17,36 +17,86 @@
package android.view;
import android.text.method.MetaKeyKeyListener;
+import android.util.AndroidRuntimeException;
import android.util.SparseIntArray;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.util.SparseArray;
import java.lang.Character;
-import java.lang.ref.WeakReference;
/**
- * Describes the keys provided by a device and their associated labels.
+ * Describes the keys provided by a keyboard device and their associated labels.
*/
-public class KeyCharacterMap
-{
+public class KeyCharacterMap {
/**
* The id of the device's primary built in keyboard is always 0.
*/
public static final int BUILT_IN_KEYBOARD = 0;
- /** A numeric (12-key) keyboard. */
+ /**
+ * The id of a generic virtual keyboard with a full layout that can be used to
+ * synthesize key events. Typically used with {@link #getEvents}.
+ */
+ public static final int VIRTUAL_KEYBOARD = -1;
+
+ /**
+ * A numeric (12-key) keyboard.
+ * <p>
+ * A numeric keyboard supports text entry using a multi-tap approach.
+ * It may be necessary to tap a key multiple times to generate the desired letter
+ * or symbol.
+ * </p><p>
+ * This type of keyboard is generally designed for thumb typing.
+ * </p>
+ */
public static final int NUMERIC = 1;
- /** A keyboard with all the letters, but with more than one letter
- * per key. */
+ /**
+ * A keyboard with all the letters, but with more than one letter per key.
+ * <p>
+ * This type of keyboard is generally designed for thumb typing.
+ * </p>
+ */
public static final int PREDICTIVE = 2;
- /** A keyboard with all the letters, and maybe some numbers. */
+ /**
+ * A keyboard with all the letters, and maybe some numbers.
+ * <p>
+ * An alphabetic keyboard supports text entry directly but may have a condensed
+ * layout with a small form factor. In contrast to a {@link #FULL full keyboard}, some
+ * symbols may only be accessible using special on-screen character pickers.
+ * In addition, to improve typing speed and accuracy, the framework provides
+ * special affordances for alphabetic keyboards such as auto-capitalization
+ * and toggled / locked shift and alt keys.
+ * </p><p>
+ * This type of keyboard is generally designed for thumb typing.
+ * </p>
+ */
public static final int ALPHA = 3;
/**
+ * A full PC-style keyboard.
+ * <p>
+ * A full keyboard behaves like a PC keyboard. All symbols are accessed directly
+ * by pressing keys on the keyboard without on-screen support or affordances such
+ * as auto-capitalization.
+ * </p><p>
+ * This type of keyboard is generally designed for full two hand typing.
+ * </p>
+ */
+ public static final int FULL = 4;
+
+ /**
+ * A keyboard that is only used to control special functions rather than for typing.
+ * <p>
+ * A special function keyboard consists only of non-printing keys such as
+ * HOME and POWER that are not actually used for typing.
+ * </p>
+ */
+ public static final int SPECIAL_FUNCTION = 5;
+
+ /**
* This private-use character is used to trigger Unicode character
* input by hex digits.
*/
@@ -58,39 +108,73 @@ public class KeyCharacterMap
*/
public static final char PICKER_DIALOG_INPUT = '\uEF01';
- private static Object sLock = new Object();
- private static SparseArray<WeakReference<KeyCharacterMap>> sInstances
- = new SparseArray<WeakReference<KeyCharacterMap>>();
+ /**
+ * Modifier keys may be chorded with character keys.
+ *
+ * @see {#link #getModifierBehavior()} for more details.
+ */
+ public static final int MODIFIER_BEHAVIOR_CHORDED = 0;
+
+ /**
+ * Modifier keys may be chorded with character keys or they may toggle
+ * into latched or locked states when pressed independently.
+ *
+ * @see {#link #getModifierBehavior()} for more details.
+ */
+ public static final int MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1;
+
+ private static SparseArray<KeyCharacterMap> sInstances = new SparseArray<KeyCharacterMap>();
+
+ private final int mDeviceId;
+ private int mPtr;
+
+ private static native int nativeLoad(int id);
+ private static native void nativeDispose(int ptr);
+
+ private static native char nativeGetCharacter(int ptr, int keyCode, int metaState);
+ private static native char nativeGetNumber(int ptr, int keyCode);
+ private static native char nativeGetMatch(int ptr, int keyCode, char[] chars, int metaState);
+ private static native char nativeGetDisplayLabel(int ptr, int keyCode);
+ private static native int nativeGetKeyboardType(int ptr);
+ private static native KeyEvent[] nativeGetEvents(int ptr, int deviceId, char[] chars);
+
+ private KeyCharacterMap(int deviceId, int ptr) {
+ mDeviceId = deviceId;
+ mPtr = ptr;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mPtr != 0) {
+ nativeDispose(mPtr);
+ mPtr = 0;
+ }
+ }
/**
* Loads the key character maps for the keyboard with the specified device id.
- * @param keyboard The device id of the keyboard.
+ *
+ * @param deviceId The device id of the keyboard.
* @return The associated key character map.
+ * @throws {@link KeyCharacterMapUnavailableException} if the key character map
+ * could not be loaded because it was malformed or the default key character map
+ * is missing from the system.
*/
- public static KeyCharacterMap load(int keyboard)
- {
- synchronized (sLock) {
- KeyCharacterMap result;
- WeakReference<KeyCharacterMap> ref = sInstances.get(keyboard);
- if (ref != null) {
- result = ref.get();
- if (result != null) {
- return result;
- }
+ public static KeyCharacterMap load(int deviceId) {
+ synchronized (sInstances) {
+ KeyCharacterMap map = sInstances.get(deviceId);
+ if (map == null) {
+ int ptr = nativeLoad(deviceId); // might throw
+ map = new KeyCharacterMap(deviceId, ptr);
+ sInstances.put(deviceId, map);
}
- result = new KeyCharacterMap(keyboard);
- sInstances.put(keyboard, new WeakReference<KeyCharacterMap>(result));
- return result;
+ return map;
}
}
- private KeyCharacterMap(int keyboardDevice)
- {
- mKeyboardDevice = keyboardDevice;
- mPointer = ctor_native(keyboardDevice);
- }
-
/**
+ * Gets the Unicode character generated by the specified key and meta
+ * key state combination.
* <p>
* Returns the Unicode character that the specified key would produce
* when the specified meta bits (see {@link MetaKeyKeyListener})
@@ -104,89 +188,116 @@ public class KeyCharacterMap
* actually produce a character -- see {@link #getDeadChar} --
* after masking with {@link #COMBINING_ACCENT_MASK}.
* </p>
+ *
+ * @param keyCode The key code.
+ * @param metaState The meta key modifier state.
+ * @return The associated character or combining accent, or 0 if none.
*/
- public int get(int keyCode, int meta)
- {
- if ((meta & MetaKeyKeyListener.META_CAP_LOCKED) != 0) {
- meta |= KeyEvent.META_SHIFT_ON;
+ public int get(int keyCode, int metaState) {
+ if ((metaState & MetaKeyKeyListener.META_CAP_LOCKED) != 0) {
+ metaState |= KeyEvent.META_CAPS_LOCK_ON;
}
- if ((meta & MetaKeyKeyListener.META_ALT_LOCKED) != 0) {
- meta |= KeyEvent.META_ALT_ON;
+ if ((metaState & MetaKeyKeyListener.META_ALT_LOCKED) != 0) {
+ metaState |= KeyEvent.META_ALT_ON;
}
- // Ignore caps lock on keys where alt and shift have the same effect.
- if ((meta & MetaKeyKeyListener.META_CAP_LOCKED) != 0) {
- if (get_native(mPointer, keyCode, KeyEvent.META_SHIFT_ON) ==
- get_native(mPointer, keyCode, KeyEvent.META_ALT_ON)) {
- meta &= ~KeyEvent.META_SHIFT_ON;
- }
- }
-
- int ret = get_native(mPointer, keyCode, meta);
- int map = COMBINING.get(ret);
-
+ char ch = nativeGetCharacter(mPtr, keyCode, metaState);
+ int map = COMBINING.get(ch);
if (map != 0) {
return map;
} else {
- return ret;
+ return ch;
}
}
/**
- * Gets the number or symbol associated with the key. The character value
- * is returned, not the numeric value. If the key is not a number, but is
- * a symbol, the symbol is retuned.
+ * Gets the number or symbol associated with the key.
+ * <p>
+ * The character value is returned, not the numeric value.
+ * If the key is not a number, but is a symbol, the symbol is retuned.
+ * </p><p>
+ * This method is intended to to support dial pads and other numeric or
+ * symbolic entry on keyboards where certain keys serve dual function
+ * as alphabetic and symbolic keys. This method returns the number
+ * or symbol associated with the key independent of whether the user
+ * has pressed the required modifier.
+ * </p><p>
+ * For example, on one particular keyboard the keys on the top QWERTY row generate
+ * numbers when ALT is pressed such that ALT-Q maps to '1'. So for that keyboard
+ * when {@link #getNumber} is called with {@link KeyEvent#KEYCODE_Q} it returns '1'
+ * so that the user can type numbers without pressing ALT when it makes sense.
+ * </p>
+ *
+ * @param keyCode The key code.
+ * @return The associated numeric or symbolic character, or 0 if none.
*/
- public char getNumber(int keyCode)
- {
- return getNumber_native(mPointer, keyCode);
+ public char getNumber(int keyCode) {
+ return nativeGetNumber(mPtr, keyCode);
}
/**
- * The same as {@link #getMatch(int,char[],int) getMatch(keyCode, chars, 0)}.
+ * Gets the first character in the character array that can be generated
+ * by the specified key code.
+ * <p>
+ * This is a convenience function that returns the same value as
+ * {@link #getMatch(int,char[],int) getMatch(keyCode, chars, 0)}.
+ * </p>
+ *
+ * @param keyCode The keycode.
+ * @param chars The array of matching characters to consider.
+ * @return The matching associated character, or 0 if none.
*/
- public char getMatch(int keyCode, char[] chars)
- {
+ public char getMatch(int keyCode, char[] chars) {
return getMatch(keyCode, chars, 0);
}
/**
- * If one of the chars in the array can be generated by keyCode,
- * return the char; otherwise return '\0'.
- * @param keyCode the key code to look at
- * @param chars the characters to try to find
- * @param modifiers the modifier bits to prefer. If any of these bits
- * are set, if there are multiple choices, that could
- * work, the one for this modifier will be set.
- */
- public char getMatch(int keyCode, char[] chars, int modifiers)
- {
+ * Gets the first character in the character array that can be generated
+ * by the specified key code. If there are multiple choices, prefers
+ * the one that would be generated with the specified meta key modifier state.
+ *
+ * @param keyCode The key code.
+ * @param chars The array of matching characters to consider.
+ * @param metaState The preferred meta key modifier state.
+ * @return The matching associated character, or 0 if none.
+ */
+ public char getMatch(int keyCode, char[] chars, int metaState) {
if (chars == null) {
- // catch it here instead of in native
- throw new NullPointerException();
+ throw new IllegalArgumentException("chars must not be null.");
}
- return getMatch_native(mPointer, keyCode, chars, modifiers);
+ return nativeGetMatch(mPtr, keyCode, chars, metaState);
}
/**
- * Get the primary character for this key. In other words, the label
- * that is physically printed on it.
+ * Gets the primary character for this key.
+ * In other words, the label that is physically printed on it.
+ *
+ * @param keyCode The key code.
+ * @return The display label character, or 0 if none (eg. for non-printing keys).
*/
- public char getDisplayLabel(int keyCode)
- {
- return getDisplayLabel_native(mPointer, keyCode);
+ public char getDisplayLabel(int keyCode) {
+ return nativeGetDisplayLabel(mPtr, keyCode);
}
/**
- * Get the character that is produced by putting accent on the character
- * c.
+ * Get the character that is produced by putting accent on the character c.
* For example, getDeadChar('`', 'e') returns &egrave;.
+ *
+ * @param accent The accent character. eg. '`'
+ * @param c The basic character.
+ * @return The combined character, or 0 if the characters cannot be combined.
*/
- public static int getDeadChar(int accent, int c)
- {
+ public static int getDeadChar(int accent, int c) {
return DEAD.get((accent << 16) | c);
}
+ /**
+ * Describes the character mappings associated with a key.
+ *
+ * @deprecated instead use {@link KeyCharacterMap#getDisplayLabel(int)},
+ * {@link KeyCharacterMap#getNumber(int)} and {@link KeyCharacterMap#get(int, int)}.
+ */
+ @Deprecated
public static class KeyData {
public static final int META_LENGTH = 4;
@@ -212,24 +323,37 @@ public class KeyCharacterMap
*/
public char[] meta = new char[META_LENGTH];
}
-
+
/**
- * Get the characters conversion data for a given keyCode.
+ * Get the character conversion data for a given key code.
*
- * @param keyCode the keyCode to look for
- * @param results a {@link KeyData} that will be filled with the results.
+ * @param keyCode The keyCode to query.
+ * @param results A {@link KeyData} instance that will be filled with the results.
+ * @return True if the key was mapped. If the key was not mapped, results is not modified.
*
- * @return whether the key was mapped or not. If the key was not mapped,
- * results is not modified.
+ * @deprecated instead use {@link KeyCharacterMap#getDisplayLabel(int)},
+ * {@link KeyCharacterMap#getNumber(int)} or {@link KeyCharacterMap#get(int, int)}.
*/
- public boolean getKeyData(int keyCode, KeyData results)
- {
- if (results.meta.length >= KeyData.META_LENGTH) {
- return getKeyData_native(mPointer, keyCode, results);
- } else {
- throw new IndexOutOfBoundsException("results.meta.length must be >= " +
- KeyData.META_LENGTH);
+ @Deprecated
+ public boolean getKeyData(int keyCode, KeyData results) {
+ if (results.meta.length < KeyData.META_LENGTH) {
+ throw new IndexOutOfBoundsException(
+ "results.meta.length must be >= " + KeyData.META_LENGTH);
+ }
+
+ char displayLabel = nativeGetDisplayLabel(mPtr, keyCode);
+ if (displayLabel == 0) {
+ return false;
}
+
+ results.displayLabel = displayLabel;
+ results.number = nativeGetNumber(mPtr, keyCode);
+ results.meta[0] = nativeGetCharacter(mPtr, keyCode, 0);
+ results.meta[1] = nativeGetCharacter(mPtr, keyCode, KeyEvent.META_SHIFT_ON);
+ results.meta[2] = nativeGetCharacter(mPtr, keyCode, KeyEvent.META_ALT_ON);
+ results.meta[3] = nativeGetCharacter(mPtr, keyCode,
+ KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON);
+ return true;
}
/**
@@ -237,102 +361,37 @@ public class KeyCharacterMap
* could plausibly generate the provided sequence of characters. It is
* not guaranteed that the sequence is the only way to generate these
* events or that it is optimal.
- *
- * @return an array of KeyEvent objects, or null if the given char array
+ * <p>
+ * This function is primarily offered for instrumentation and testing purposes.
+ * It may fail to map characters to key codes. In particular, the key character
+ * map for the {@link #BUILT_IN_KEYBOARD built-in keyboard} device id may be empty.
+ * Consider using the key character map associated with the
+ * {@link #VIRTUAL_KEYBOARD virtual keyboard} device id instead.
+ * </p><p>
+ * For robust text entry, do not use this function. Instead construct a
+ * {@link KeyEvent} with action code {@link KeyEvent#ACTION_MULTIPLE} that contains
+ * the desired string using {@link KeyEvent#KeyEvent(long, String, int, int)}.
+ * </p>
+ *
+ * @param chars The sequence of characters to generate.
+ * @return An array of {@link KeyEvent} objects, or null if the given char array
* can not be generated using the current key character map.
*/
- public KeyEvent[] getEvents(char[] chars)
- {
+ public KeyEvent[] getEvents(char[] chars) {
if (chars == null) {
- throw new NullPointerException();
- }
-
- long[] keys = getEvents_native(mPointer, chars);
- if (keys == null) {
- return null;
- }
-
- // how big should the array be
- int len = keys.length*2;
- int N = keys.length;
- for (int i=0; i<N; i++) {
- int mods = (int)(keys[i] >> 32);
- if ((mods & KeyEvent.META_ALT_ON) != 0) {
- len += 2;
- }
- if ((mods & KeyEvent.META_SHIFT_ON) != 0) {
- len += 2;
- }
- if ((mods & KeyEvent.META_SYM_ON) != 0) {
- len += 2;
- }
- }
-
- // create the events
- KeyEvent[] rv = new KeyEvent[len];
- int index = 0;
- long now = SystemClock.uptimeMillis();
- int device = mKeyboardDevice;
- for (int i=0; i<N; i++) {
- int mods = (int)(keys[i] >> 32);
- int meta = 0;
-
- if ((mods & KeyEvent.META_ALT_ON) != 0) {
- meta |= KeyEvent.META_ALT_ON;
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_ALT_LEFT, 0, meta, device, 0);
- index++;
- }
- if ((mods & KeyEvent.META_SHIFT_ON) != 0) {
- meta |= KeyEvent.META_SHIFT_ON;
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_SHIFT_LEFT, 0, meta, device, 0);
- index++;
- }
- if ((mods & KeyEvent.META_SYM_ON) != 0) {
- meta |= KeyEvent.META_SYM_ON;
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_SYM, 0, meta, device, 0);
- index++;
- }
-
- int key = (int)(keys[i]);
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
- key, 0, meta, device, 0);
- index++;
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP,
- key, 0, meta, device, 0);
- index++;
-
- if ((mods & KeyEvent.META_ALT_ON) != 0) {
- meta &= ~KeyEvent.META_ALT_ON;
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP,
- KeyEvent.KEYCODE_ALT_LEFT, 0, meta, device, 0);
- index++;
- }
- if ((mods & KeyEvent.META_SHIFT_ON) != 0) {
- meta &= ~KeyEvent.META_SHIFT_ON;
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP,
- KeyEvent.KEYCODE_SHIFT_LEFT, 0, meta, device, 0);
- index++;
- }
- if ((mods & KeyEvent.META_SYM_ON) != 0) {
- meta &= ~KeyEvent.META_SYM_ON;
- rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP,
- KeyEvent.KEYCODE_SYM, 0, meta, device, 0);
- index++;
- }
+ throw new IllegalArgumentException("chars must not be null.");
}
-
- return rv;
+ return nativeGetEvents(mPtr, mDeviceId, chars);
}
/**
- * Does this character key produce a glyph?
+ * Returns true if the specified key produces a glyph.
+ *
+ * @param keyCode The key code.
+ * @return True if the key is a printing key.
*/
- public boolean isPrintingKey(int keyCode)
- {
- int type = Character.getType(get(keyCode, 0));
+ public boolean isPrintingKey(int keyCode) {
+ int type = Character.getType(nativeGetDisplayLabel(mPtr, keyCode));
switch (type)
{
@@ -347,22 +406,68 @@ public class KeyCharacterMap
}
}
- protected void finalize() throws Throwable
- {
- dtor_native(mPointer);
+ /**
+ * Gets the keyboard type.
+ * Returns {@link #NUMERIC}, {@link #PREDICTIVE}, {@link #ALPHA} or {@link #FULL}.
+ * <p>
+ * Different keyboard types have different semantics. Refer to the documentation
+ * associated with the keyboard type constants for details.
+ * </p>
+ *
+ * @return The keyboard type.
+ */
+ public int getKeyboardType() {
+ return nativeGetKeyboardType(mPtr);
}
/**
- * Returns {@link #NUMERIC}, {@link #PREDICTIVE} or {@link #ALPHA}.
+ * Gets a constant that describes the behavior of this keyboard's modifier keys
+ * such as {@link KeyEvent#KEYCODE_SHIFT_LEFT}.
+ * <p>
+ * Currently there are two behaviors that may be combined:
+ * </p>
+ * <ul>
+ * <li>Chorded behavior: When the modifier key is pressed together with one or more
+ * character keys, the keyboard inserts the modified keys and
+ * then resets the modifier state when the modifier key is released.</li>
+ * <li>Toggled behavior: When the modifier key is pressed and released on its own
+ * it first toggles into a latched state. When latched, the modifier will apply
+ * to next character key that is pressed and will then reset itself to the initial state.
+ * If the modifier is already latched and the modifier key is pressed and release on
+ * its own again, then it toggles into a locked state. When locked, the modifier will
+ * apply to all subsequent character keys that are pressed until unlocked by pressing
+ * the modifier key on its own one more time to reset it to the initial state.
+ * Toggled behavior is useful for small profile keyboards designed for thumb typing.
+ * </ul>
+ * <p>
+ * This function currently returns {@link #MODIFIER_BEHAVIOR_CHORDED} when the
+ * {@link #getKeyboardType() keyboard type} is {@link #FULL} or {@link #SPECIAL_FUNCTION} and
+ * {@link #MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED} otherwise.
+ * In the future, the function may also take into account global keyboard
+ * accessibility settings, other user preferences, or new device capabilities.
+ * </p>
+ *
+ * @return The modifier behavior for this keyboard.
+ *
+ * @see {@link #MODIFIER_BEHAVIOR_CHORDED}
+ * @see {@link #MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED}
*/
- public int getKeyboardType()
- {
- return getKeyboardType_native(mPointer);
+ public int getModifierBehavior() {
+ switch (getKeyboardType()) {
+ case FULL:
+ case SPECIAL_FUNCTION:
+ return MODIFIER_BEHAVIOR_CHORDED;
+ default:
+ return MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED;
+ }
}
/**
* Queries the framework about whether any physical keys exist on the
- * device that are capable of producing the given key codes.
+ * any keyboard attached to the device that are capable of producing the given key code.
+ *
+ * @param keyCode The key code to query.
+ * @return True if at least one attached keyboard supports the specified key code.
*/
public static boolean deviceHasKey(int keyCode) {
int[] codeArray = new int[1];
@@ -370,7 +475,17 @@ public class KeyCharacterMap
boolean[] ret = deviceHasKeys(codeArray);
return ret[0];
}
-
+
+ /**
+ * Queries the framework about whether any physical keys exist on the
+ * any keyboard attached to the device that are capable of producing the given
+ * array of key codes.
+ *
+ * @param keyCodes The array of key codes to query.
+ * @return A new array of the same size as the key codes array whose elements
+ * are set to true if at least one attached keyboard supports the corresponding key code
+ * at the same index in the key codes array.
+ */
public static boolean[] deviceHasKeys(int[] keyCodes) {
boolean[] ret = new boolean[keyCodes.length];
IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
@@ -382,22 +497,6 @@ public class KeyCharacterMap
return ret;
}
- private int mPointer;
- private int mKeyboardDevice;
-
- private static native int ctor_native(int id);
- private static native void dtor_native(int ptr);
- private static native char get_native(int ptr, int keycode,
- int meta);
- private static native char getNumber_native(int ptr, int keycode);
- private static native char getMatch_native(int ptr, int keycode,
- char[] chars, int modifiers);
- private static native char getDisplayLabel_native(int ptr, int keycode);
- private static native boolean getKeyData_native(int ptr, int keycode,
- KeyData results);
- private static native int getKeyboardType_native(int ptr);
- private static native long[] getEvents_native(int ptr, char[] str);
-
/**
* Maps Unicode combining diacritical to display-form dead key
* (display character shifted left 16 bits).
@@ -412,7 +511,7 @@ public class KeyCharacterMap
/*
* TODO: Change the table format to support full 21-bit-wide
- * accent characters and combined characters if ever necessary.
+ * accent characters and combined characters if ever necessary.
*/
private static final int ACUTE = '\u00B4' << 16;
private static final int GRAVE = '`' << 16;
@@ -550,4 +649,13 @@ public class KeyCharacterMap
DEAD.put(UMLAUT | 'x', '\u1E8D');
DEAD.put(UMLAUT | 'y', '\u00FF');
}
+
+ /**
+ * Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded.
+ */
+ public static class KeyCharacterMapUnavailableException extends AndroidRuntimeException {
+ public KeyCharacterMapUnavailableException(String msg) {
+ super(msg);
+ }
+ }
}