summaryrefslogtreecommitdiffstats
path: root/core/java/android/text/method
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/text/method
parenta914f340ae5b267dc3ab36c1156c795b8fa18f5d (diff)
downloadframeworks_base-6b53e8daa69cba1a2a5a7c95a01e37ce9c53226c.zip
frameworks_base-6b53e8daa69cba1a2a5a7c95a01e37ce9c53226c.tar.gz
frameworks_base-6b53e8daa69cba1a2a5a7c95a01e37ce9c53226c.tar.bz2
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/text/method')
-rw-r--r--core/java/android/text/method/BaseKeyListener.java16
-rw-r--r--core/java/android/text/method/DialerKeyListener.java2
-rw-r--r--core/java/android/text/method/MetaKeyKeyListener.java104
-rw-r--r--core/java/android/text/method/NumberKeyListener.java2
-rw-r--r--core/java/android/text/method/QwertyKeyListener.java2
-rw-r--r--core/java/android/text/method/TextKeyListener.java5
-rw-r--r--core/java/android/text/method/Touch.java9
7 files changed, 102 insertions, 38 deletions
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 6df6a3a..350c9a8 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -22,9 +22,15 @@ import android.text.*;
import android.text.method.TextKeyListener.Capitalize;
import android.widget.TextView;
-public abstract class BaseKeyListener
-extends MetaKeyKeyListener
-implements KeyListener {
+/**
+ * Abstract base class for key listeners.
+ *
+ * Provides a basic foundation for entering and editing text.
+ * Subclasses should override {@link #onKeyDown} and {@link #onKeyUp} to insert
+ * characters as keys are pressed.
+ */
+public abstract class BaseKeyListener extends MetaKeyKeyListener
+ implements KeyListener {
/* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
/**
@@ -34,7 +40,7 @@ implements KeyListener {
* if any;
* ALT+DEL deletes everything on the line the cursor is on.
*
- * @return true if anything was deleted; false otherwise.
+ * @return true if anything was deleted; false otherwise.
*/
public boolean backspace(View view, Editable content, int keyCode,
KeyEvent event) {
@@ -72,7 +78,7 @@ implements KeyListener {
private boolean altBackspace(View view, Editable content, int keyCode,
KeyEvent event) {
- if (getMetaState(content, META_ALT_ON) != 1) {
+ if (!event.isAltPressed() && getMetaState(content, META_ALT_ON) != 1) {
return false;
}
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index 1e1812a..07127b7 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -49,7 +49,7 @@ public class DialerKeyListener extends NumberKeyListener
* from the KeyEvent.
*/
protected int lookup(KeyEvent event, Spannable content) {
- int meta = getMetaState(content);
+ int meta = event.getMetaState() | getMetaState(content);
int number = event.getNumber();
/*
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index e7b36d7..923a555 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -22,14 +22,54 @@ import android.text.Spannable;
import android.text.Spanned;
import android.view.KeyEvent;
import android.view.View;
+import android.view.KeyCharacterMap;
/**
- * This base class encapsulates the behavior for handling the meta keys
- * (shift and alt) and the pseudo-meta state of selecting text.
- * Key listeners that care about meta state should
- * inherit from it; you should not instantiate this class directly in a client.
+ * This base class encapsulates the behavior for tracking the state of
+ * meta keys such as SHIFT, ALT and SYM as well as the pseudo-meta state of selecting text.
+ * <p>
+ * Key listeners that care about meta state should inherit from this class;
+ * you should not instantiate this class directly in a client.
+ * </p><p>
+ * This class provides two mechanisms for tracking meta state that can be used
+ * together or independently.
+ * </p>
+ * <ul>
+ * <li>Methods such as {@link #handleKeyDown(long, int, KeyEvent)} and
+ * {@link #getMetaState(long)} operate on a meta key state bit mask.</li>
+ * <li>Methods such as {@link #onKeyDown(View, Editable, int, KeyEvent)} and
+ * {@link #getMetaState(CharSequence, int)} operate on meta key state flags stored
+ * as spans in an {@link Editable} text buffer. The spans only describe the current
+ * meta key state of the text editor; they do not carry any positional information.</li>
+ * </ul>
+ * <p>
+ * The behavior of this class varies according to the keyboard capabilities
+ * described by the {@link KeyCharacterMap} of the keyboard device such as
+ * the {@link KeyCharacterMap#getModifierBehavior() key modifier behavior}.
+ * </p><p>
+ * {@link MetaKeyKeyListener} implements chorded and toggled key modifiers.
+ * When key modifiers are toggled into a latched or locked state, the state
+ * of the modifier is stored in the {@link Editable} text buffer or in a
+ * meta state integer managed by the client. These latched or locked modifiers
+ * should be considered to be held <b>in addition to</b> those that the
+ * keyboard already reported as being pressed in {@link KeyEvent#getMetaState()}.
+ * In other words, the {@link MetaKeyKeyListener} augments the meta state
+ * provided by the keyboard; it does not replace it. This distinction is important
+ * to ensure that meta keys not handled by {@link MetaKeyKeyListener} such as
+ * {@link KeyEvent#KEYCODE_CAPS_LOCK} or {@link KeyEvent#KEYCODE_NUM_LOCK} are
+ * taken into consideration.
+ * </p><p>
+ * To ensure correct meta key behavior, the following pattern should be used
+ * when mapping key codes to characters:
+ * </p>
+ * <code>
+ * private char getUnicodeChar(TextKeyListener listener, KeyEvent event, Editable textBuffer) {
+ * // Use the combined meta states from the event and the key listener.
+ * int metaState = event.getMetaState() | listener.getMetaState(textBuffer);
+ * return event.getUnicodeChar(metaState);
+ * }
+ * </code>
*/
-
public abstract class MetaKeyKeyListener {
/**
* Flag that indicates that the SHIFT key is on.
@@ -227,8 +267,7 @@ public abstract class MetaKeyKeyListener {
/**
* Handles presses of the meta keys.
*/
- public boolean onKeyDown(View view, Editable content,
- int keyCode, KeyEvent event) {
+ public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
press(content, CAP);
return true;
@@ -283,34 +322,41 @@ public abstract class MetaKeyKeyListener {
/**
* Handles release of the meta keys.
*/
- public boolean onKeyUp(View view, Editable content, int keyCode,
- KeyEvent event) {
+ public boolean onKeyUp(View view, Editable content, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
- release(content, CAP);
+ release(content, CAP, event);
return true;
}
if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT
|| keyCode == KeyEvent.KEYCODE_NUM) {
- release(content, ALT);
+ release(content, ALT, event);
return true;
}
if (keyCode == KeyEvent.KEYCODE_SYM) {
- release(content, SYM);
+ release(content, SYM, event);
return true;
}
return false; // no super to call through to
}
- private void release(Editable content, Object what) {
+ private void release(Editable content, Object what, KeyEvent event) {
int current = content.getSpanFlags(what);
- if (current == USED)
- content.removeSpan(what);
- else if (current == PRESSED)
- content.setSpan(what, 0, 0, RELEASED);
+ switch (event.getKeyCharacterMap().getModifierBehavior()) {
+ case KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED:
+ if (current == USED)
+ content.removeSpan(what);
+ else if (current == PRESSED)
+ content.setSpan(what, 0, 0, RELEASED);
+ break;
+
+ default:
+ content.removeSpan(what);
+ break;
+ }
}
public void clearMetaKeyState(View view, Editable content, int states) {
@@ -478,28 +524,36 @@ public abstract class MetaKeyKeyListener {
public static long handleKeyUp(long state, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
return release(state, META_SHIFT_ON, META_SHIFT_MASK,
- META_CAP_PRESSED, META_CAP_RELEASED, META_CAP_USED);
+ META_CAP_PRESSED, META_CAP_RELEASED, META_CAP_USED, event);
}
if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT
|| keyCode == KeyEvent.KEYCODE_NUM) {
return release(state, META_ALT_ON, META_ALT_MASK,
- META_ALT_PRESSED, META_ALT_RELEASED, META_ALT_USED);
+ META_ALT_PRESSED, META_ALT_RELEASED, META_ALT_USED, event);
}
if (keyCode == KeyEvent.KEYCODE_SYM) {
return release(state, META_SYM_ON, META_SYM_MASK,
- META_SYM_PRESSED, META_SYM_RELEASED, META_SYM_USED);
+ META_SYM_PRESSED, META_SYM_RELEASED, META_SYM_USED, event);
}
return state;
}
private static long release(long state, int what, long mask,
- long pressed, long released, long used) {
- if ((state & used) != 0) {
- state &= ~mask;
- } else if ((state & pressed) != 0) {
- state |= what | released;
+ long pressed, long released, long used, KeyEvent event) {
+ switch (event.getKeyCharacterMap().getModifierBehavior()) {
+ case KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED:
+ if ((state & used) != 0) {
+ state &= ~mask;
+ } else if ((state & pressed) != 0) {
+ state |= what | released;
+ }
+ break;
+
+ default:
+ state &= ~mask;
+ break;
}
return state;
}
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 9270ca5..1e72309 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -37,7 +37,7 @@ public abstract class NumberKeyListener extends BaseKeyListener
protected abstract char[] getAcceptedChars();
protected int lookup(KeyEvent event, Spannable content) {
- return event.getMatch(getAcceptedChars(), getMetaState(content));
+ return event.getMatch(getAcceptedChars(), event.getMetaState() | getMetaState(content));
}
public CharSequence filter(CharSequence source, int start, int end,
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index b3926f2..3308172 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -83,7 +83,7 @@ public class QwertyKeyListener extends BaseKeyListener {
// QWERTY keyboard normal case
- int i = event.getUnicodeChar(getMetaState(content));
+ int i = event.getUnicodeChar(event.getMetaState() | getMetaState(content));
int count = event.getRepeatCount();
if (count > 0 && selStart == selEnd && selStart > 0) {
diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java
index 09cbbb8..8ad6f50 100644
--- a/core/java/android/text/method/TextKeyListener.java
+++ b/core/java/android/text/method/TextKeyListener.java
@@ -180,13 +180,16 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
}
private KeyListener getKeyListener(KeyEvent event) {
- KeyCharacterMap kmap = KeyCharacterMap.load(event.getKeyboardDevice());
+ KeyCharacterMap kmap = event.getKeyCharacterMap();
int kind = kmap.getKeyboardType();
if (kind == KeyCharacterMap.ALPHA) {
return QwertyKeyListener.getInstance(mAutoText, mAutoCap);
} else if (kind == KeyCharacterMap.NUMERIC) {
return MultiTapKeyListener.getInstance(mAutoText, mAutoCap);
+ } else if (kind == KeyCharacterMap.FULL
+ || kind == KeyCharacterMap.SPECIAL_FUNCTION) {
+ return QwertyKeyListener.getInstance(false, Capitalize.NONE);
}
return NullKeyListener.getInstance();
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index 9eaab17..78cbdcf 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -143,10 +143,11 @@ public class Touch {
if (ds[0].mFarEnough) {
ds[0].mUsed = true;
- boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
- MetaKeyKeyListener.META_SHIFT_ON) == 1) ||
- (MetaKeyKeyListener.getMetaState(buffer,
- MetaKeyKeyListener.META_SELECTING) != 0);
+ boolean cap = (event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0
+ || MetaKeyKeyListener.getMetaState(buffer,
+ MetaKeyKeyListener.META_SHIFT_ON) == 1
+ || MetaKeyKeyListener.getMetaState(buffer,
+ MetaKeyKeyListener.META_SELECTING) != 0;
float dx;
float dy;
if (cap) {