Add Key.altCode attribute
* Registering alternate code and while key is typing. * Showing press/release graphics of the key that has the above altenate code. * Showing press/release graphics of all shift keys. * Renaming Key.ignoreWhileTyping to Key.altCodeWhileTyping. Bug: 5639503 Change-Id: I67fb45bae76284a1f0deb6fd12ae5fb781d06cc3main
parent
70b8934f0e
commit
2013bab89c
|
@ -185,6 +185,8 @@
|
||||||
<declare-styleable name="Keyboard_Key">
|
<declare-styleable name="Keyboard_Key">
|
||||||
<!-- The unicode value that this key outputs. -->
|
<!-- The unicode value that this key outputs. -->
|
||||||
<attr name="code" format="integer" />
|
<attr name="code" format="integer" />
|
||||||
|
<!-- The alternate unicode value that this key outputs while typing. -->
|
||||||
|
<attr name="altCode" format="integer" />
|
||||||
<!-- The keys to display in the more keys keyboard. -->
|
<!-- The keys to display in the more keys keyboard. -->
|
||||||
<attr name="moreKeys" format="string" />
|
<attr name="moreKeys" format="string" />
|
||||||
<!-- Maximum column of more keys keyboard -->
|
<!-- Maximum column of more keys keyboard -->
|
||||||
|
@ -201,7 +203,7 @@
|
||||||
<!-- This should be aligned with Key.ACTION_FLAGS_* -->
|
<!-- This should be aligned with Key.ACTION_FLAGS_* -->
|
||||||
<flag name="isRepeatable" value="0x01" />
|
<flag name="isRepeatable" value="0x01" />
|
||||||
<flag name="noKeyPreview" value="0x02" />
|
<flag name="noKeyPreview" value="0x02" />
|
||||||
<flag name="ignoreWhileTyping" value="0x04" />
|
<flag name="altCodeWhileTyping" value="0x04" />
|
||||||
</attr>
|
</attr>
|
||||||
<!-- The string of characters to output when this key is pressed. -->
|
<!-- The string of characters to output when this key is pressed. -->
|
||||||
<attr name="keyOutputText" format="string" />
|
<attr name="keyOutputText" format="string" />
|
||||||
|
|
|
@ -77,13 +77,15 @@
|
||||||
latin:styleName="shortcutKeyStyle"
|
latin:styleName="shortcutKeyStyle"
|
||||||
latin:code="@integer/key_shortcut"
|
latin:code="@integer/key_shortcut"
|
||||||
latin:keyIcon="iconShortcutKey"
|
latin:keyIcon="iconShortcutKey"
|
||||||
latin:keyActionFlags="noKeyPreview|ignoreWhileTyping"
|
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
|
||||||
|
latin:altCode="@integer/key_space"
|
||||||
latin:parentStyle="f2PopupStyle" />
|
latin:parentStyle="f2PopupStyle" />
|
||||||
<key-style
|
<key-style
|
||||||
latin:styleName="settingsKeyStyle"
|
latin:styleName="settingsKeyStyle"
|
||||||
latin:code="@integer/key_settings"
|
latin:code="@integer/key_settings"
|
||||||
latin:keyIcon="iconSettingsKey"
|
latin:keyIcon="iconSettingsKey"
|
||||||
latin:keyActionFlags="noKeyPreview|ignoreWhileTyping"
|
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
|
||||||
|
latin:altCode="@integer/key_space"
|
||||||
latin:backgroundType="functional" />
|
latin:backgroundType="functional" />
|
||||||
<key-style
|
<key-style
|
||||||
latin:styleName="tabKeyStyle"
|
latin:styleName="tabKeyStyle"
|
||||||
|
|
|
@ -59,13 +59,15 @@
|
||||||
latin:styleName="shortcutKeyStyle"
|
latin:styleName="shortcutKeyStyle"
|
||||||
latin:code="@integer/key_shortcut"
|
latin:code="@integer/key_shortcut"
|
||||||
latin:keyIcon="iconShortcutKey"
|
latin:keyIcon="iconShortcutKey"
|
||||||
latin:keyActionFlags="noKeyPreview|ignoreWhileTyping"
|
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
|
||||||
|
latin:altCode="@integer/key_space"
|
||||||
latin:backgroundType="functional" />
|
latin:backgroundType="functional" />
|
||||||
<key-style
|
<key-style
|
||||||
latin:styleName="settingsKeyStyle"
|
latin:styleName="settingsKeyStyle"
|
||||||
latin:code="@integer/key_settings"
|
latin:code="@integer/key_settings"
|
||||||
latin:keyIcon="iconSettingsKey"
|
latin:keyIcon="iconSettingsKey"
|
||||||
latin:keyActionFlags="noKeyPreview|ignoreWhileTyping"
|
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
|
||||||
|
latin:altCode="@integer/key_space"
|
||||||
latin:backgroundType="functional" />
|
latin:backgroundType="functional" />
|
||||||
<key-style
|
<key-style
|
||||||
latin:styleName="tabKeyStyle"
|
latin:styleName="tabKeyStyle"
|
||||||
|
|
|
@ -163,13 +163,15 @@
|
||||||
latin:styleName="shortcutKeyStyle"
|
latin:styleName="shortcutKeyStyle"
|
||||||
latin:code="@integer/key_shortcut"
|
latin:code="@integer/key_shortcut"
|
||||||
latin:keyIcon="iconShortcutKey"
|
latin:keyIcon="iconShortcutKey"
|
||||||
latin:keyActionFlags="noKeyPreview|ignoreWhileTyping"
|
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
|
||||||
|
latin:altCode="@integer/key_space"
|
||||||
latin:parentStyle="f1PopupStyle" />
|
latin:parentStyle="f1PopupStyle" />
|
||||||
<key-style
|
<key-style
|
||||||
latin:styleName="settingsKeyStyle"
|
latin:styleName="settingsKeyStyle"
|
||||||
latin:code="@integer/key_settings"
|
latin:code="@integer/key_settings"
|
||||||
latin:keyIcon="iconSettingsKey"
|
latin:keyIcon="iconSettingsKey"
|
||||||
latin:keyActionFlags="noKeyPreview|ignoreWhileTyping"
|
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
|
||||||
|
latin:altCode="@integer/key_space"
|
||||||
latin:backgroundType="functional" />
|
latin:backgroundType="functional" />
|
||||||
<key-style
|
<key-style
|
||||||
latin:styleName="tabKeyStyle"
|
latin:styleName="tabKeyStyle"
|
||||||
|
|
|
@ -46,6 +46,7 @@ public class Key {
|
||||||
* The key code (unicode or custom code) that this key generates.
|
* The key code (unicode or custom code) that this key generates.
|
||||||
*/
|
*/
|
||||||
public final int mCode;
|
public final int mCode;
|
||||||
|
public final int mAltCode;
|
||||||
|
|
||||||
/** Label to display */
|
/** Label to display */
|
||||||
public final CharSequence mLabel;
|
public final CharSequence mLabel;
|
||||||
|
@ -108,7 +109,7 @@ public class Key {
|
||||||
private final int mActionFlags;
|
private final int mActionFlags;
|
||||||
private static final int ACTION_FLAGS_IS_REPEATABLE = 0x01;
|
private static final int ACTION_FLAGS_IS_REPEATABLE = 0x01;
|
||||||
private static final int ACTION_FLAGS_NO_KEY_PREVIEW = 0x02;
|
private static final int ACTION_FLAGS_NO_KEY_PREVIEW = 0x02;
|
||||||
private static final int ACTION_FLAGS_IGNORE_WHILE_TYPING = 0x04;
|
private static final int ACTION_FLAGS_ALT_CODE_WHILE_TYPING = 0x04;
|
||||||
|
|
||||||
/** The current pressed state of this key */
|
/** The current pressed state of this key */
|
||||||
private boolean mPressed;
|
private boolean mPressed;
|
||||||
|
@ -191,6 +192,7 @@ public class Key {
|
||||||
mLabel = label;
|
mLabel = label;
|
||||||
mOutputText = outputText;
|
mOutputText = outputText;
|
||||||
mCode = code;
|
mCode = code;
|
||||||
|
mAltCode = Keyboard.CODE_DUMMY;
|
||||||
mIcon = icon;
|
mIcon = icon;
|
||||||
// Horizontal gap is divided equally to both sides of the key.
|
// Horizontal gap is divided equally to both sides of the key.
|
||||||
mX = x + mHorizontalGap / 2;
|
mX = x + mHorizontalGap / 2;
|
||||||
|
@ -290,6 +292,8 @@ public class Key {
|
||||||
} else {
|
} else {
|
||||||
mCode = Keyboard.CODE_DUMMY;
|
mCode = Keyboard.CODE_DUMMY;
|
||||||
}
|
}
|
||||||
|
mAltCode = style.getInt(keyAttr,
|
||||||
|
R.styleable.Keyboard_Key_altCode, Keyboard.CODE_DUMMY);
|
||||||
|
|
||||||
keyAttr.recycle();
|
keyAttr.recycle();
|
||||||
}
|
}
|
||||||
|
@ -334,8 +338,8 @@ public class Key {
|
||||||
return (mActionFlags & ACTION_FLAGS_NO_KEY_PREVIEW) != 0;
|
return (mActionFlags & ACTION_FLAGS_NO_KEY_PREVIEW) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ignoreWhileTyping() {
|
public boolean altCodeWhileTyping() {
|
||||||
return (mActionFlags & ACTION_FLAGS_IGNORE_WHILE_TYPING) != 0;
|
return (mActionFlags & ACTION_FLAGS_ALT_CODE_WHILE_TYPING) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Typeface selectTypeface(Typeface defaultTypeface) {
|
public Typeface selectTypeface(Typeface defaultTypeface) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardParams;
|
||||||
import com.android.inputmethod.keyboard.internal.KeyboardShiftState;
|
import com.android.inputmethod.keyboard.internal.KeyboardShiftState;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -65,7 +66,6 @@ public class Keyboard {
|
||||||
public static final int CODE_DIGIT0 = '0';
|
public static final int CODE_DIGIT0 = '0';
|
||||||
public static final int CODE_PLUS = '+';
|
public static final int CODE_PLUS = '+';
|
||||||
|
|
||||||
|
|
||||||
/** Special keys code. These should be aligned with values/keycodes.xml */
|
/** Special keys code. These should be aligned with values/keycodes.xml */
|
||||||
public static final int CODE_DUMMY = 0;
|
public static final int CODE_DUMMY = 0;
|
||||||
public static final int CODE_SHIFT = -1;
|
public static final int CODE_SHIFT = -1;
|
||||||
|
@ -111,6 +111,7 @@ public class Keyboard {
|
||||||
public final Map<Key, Drawable> mUnshiftedIcons;
|
public final Map<Key, Drawable> mUnshiftedIcons;
|
||||||
public final KeyboardIconsSet mIconsSet;
|
public final KeyboardIconsSet mIconsSet;
|
||||||
|
|
||||||
|
private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>();
|
||||||
private final KeyboardShiftState mShiftState = new KeyboardShiftState();
|
private final KeyboardShiftState mShiftState = new KeyboardShiftState();
|
||||||
|
|
||||||
private final ProximityInfo mProximityInfo;
|
private final ProximityInfo mProximityInfo;
|
||||||
|
@ -145,6 +146,22 @@ public class Keyboard {
|
||||||
return mProximityInfo;
|
return mProximityInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Key getKey(int code) {
|
||||||
|
final Integer keyCode = code;
|
||||||
|
if (mKeyCache.containsKey(keyCode)) {
|
||||||
|
return mKeyCache.get(keyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Key key : mKeys) {
|
||||||
|
if (key.mCode == code) {
|
||||||
|
mKeyCache.put(keyCode, key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mKeyCache.put(keyCode, null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasShiftLockKey() {
|
public boolean hasShiftLockKey() {
|
||||||
return !mShiftLockKeys.isEmpty();
|
return !mShiftLockKeys.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,23 +258,27 @@ public class PointerTracker {
|
||||||
// primaryCode is different from {@link Key#mCode}.
|
// primaryCode is different from {@link Key#mCode}.
|
||||||
private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) {
|
private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) {
|
||||||
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
|
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
|
||||||
if (DEBUG_LISTENER)
|
final boolean alterCode = key.altCodeWhileTyping() && mTimerProxy.isTyping();
|
||||||
Log.d(TAG, "onCodeInput: " + keyCodePrintable(primaryCode)
|
final int code = alterCode ? key.mAltCode : primaryCode;
|
||||||
|
// If code is CODE_DUMMY here, this key will be ignored or generate text.
|
||||||
|
final CharSequence text = (code != Keyboard.CODE_DUMMY) ? null : key.mOutputText;
|
||||||
|
if (DEBUG_LISTENER) {
|
||||||
|
Log.d(TAG, "onCodeInput: " + keyCodePrintable(code) + " text=" + text
|
||||||
+ " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y
|
+ " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y
|
||||||
+ " ignoreModifier=" + ignoreModifierKey);
|
+ " ignoreModifier=" + ignoreModifierKey + " alterCode=" + alterCode);
|
||||||
|
}
|
||||||
if (ignoreModifierKey) {
|
if (ignoreModifierKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (key.isEnabled()) {
|
if (key.isEnabled()) {
|
||||||
mListener.onCodeInput(primaryCode, keyCodes, x, y);
|
if (code != Keyboard.CODE_DUMMY) {
|
||||||
}
|
mListener.onCodeInput(code, keyCodes, x, y);
|
||||||
}
|
} else if (text != null) {
|
||||||
|
mListener.onTextInput(text);
|
||||||
private void callListenerOnTextInput(Key key) {
|
}
|
||||||
if (DEBUG_LISTENER)
|
if (!key.altCodeWhileTyping() && !key.isModifier()) {
|
||||||
Log.d(TAG, "onTextInput: text=" + key.mOutputText);
|
mTimerProxy.startKeyTypedTimer(sIgnoreSpecialKeyTimeout);
|
||||||
if (key.isEnabled()) {
|
}
|
||||||
mListener.onTextInput(key.mOutputText);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,6 +332,23 @@ public class PointerTracker {
|
||||||
if (key != null && key.isEnabled()) {
|
if (key != null && key.isEnabled()) {
|
||||||
key.onReleased();
|
key.onReleased();
|
||||||
mDrawingProxy.invalidateKey(key);
|
mDrawingProxy.invalidateKey(key);
|
||||||
|
|
||||||
|
if (key.isShift()) {
|
||||||
|
for (final Key shiftKey : mKeyboard.mShiftKeys) {
|
||||||
|
if (shiftKey != key) {
|
||||||
|
shiftKey.onReleased();
|
||||||
|
mDrawingProxy.invalidateKey(shiftKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.altCodeWhileTyping()) {
|
||||||
|
final Key altKey = mKeyboard.getKey(key.mAltCode);
|
||||||
|
if (altKey != null) {
|
||||||
|
altKey.onReleased();
|
||||||
|
mDrawingProxy.invalidateKey(altKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,6 +359,24 @@ public class PointerTracker {
|
||||||
}
|
}
|
||||||
key.onPressed();
|
key.onPressed();
|
||||||
mDrawingProxy.invalidateKey(key);
|
mDrawingProxy.invalidateKey(key);
|
||||||
|
|
||||||
|
if (key.isShift()) {
|
||||||
|
for (final Key shiftKey : mKeyboard.mShiftKeys) {
|
||||||
|
if (shiftKey != key) {
|
||||||
|
shiftKey.onPressed();
|
||||||
|
mDrawingProxy.invalidateKey(shiftKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.altCodeWhileTyping() && mTimerProxy.isTyping()) {
|
||||||
|
final Key altKey = mKeyboard.getKey(key.mAltCode);
|
||||||
|
if (altKey != null) {
|
||||||
|
// TODO: Show altKey's preview.
|
||||||
|
altKey.onPressed();
|
||||||
|
mDrawingProxy.invalidateKey(altKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,45 +735,27 @@ public class PointerTracker {
|
||||||
callListenerOnCancelInput();
|
callListenerOnCancelInput();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (key.mOutputText != null) {
|
|
||||||
final boolean ignoreText = key.ignoreWhileTyping() && mTimerProxy.isTyping();
|
|
||||||
if (!ignoreText) {
|
|
||||||
callListenerOnTextInput(key);
|
|
||||||
}
|
|
||||||
callListenerOnRelease(key, key.mCode, false);
|
|
||||||
if (!ignoreText) {
|
|
||||||
mTimerProxy.startKeyTypedTimer(sIgnoreSpecialKeyTimeout);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int code = key.mCode;
|
|
||||||
final int[] codes = mKeyDetector.newCodeArray();
|
|
||||||
mKeyDetector.getKeyAndNearbyCodes(x, y, codes);
|
|
||||||
|
|
||||||
// If keyboard is in manual temporary upper case state and key has manual temporary
|
int code = key.mCode;
|
||||||
// uppercase letter as key hint letter, alternate character code should be sent.
|
final int[] codes = mKeyDetector.newCodeArray();
|
||||||
if (mKeyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter()) {
|
mKeyDetector.getKeyAndNearbyCodes(x, y, codes);
|
||||||
code = key.mHintLabel.charAt(0);
|
|
||||||
codes[0] = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap the first and second values in the codes array if the primary code is not the
|
// If keyboard is in manual temporary upper case state and key has manual temporary
|
||||||
// first value but the second value in the array. This happens when key debouncing is
|
// uppercase letter as key hint letter, alternate character code should be sent.
|
||||||
// in effect.
|
if (mKeyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter()) {
|
||||||
if (codes.length >= 2 && codes[0] != code && codes[1] == code) {
|
code = key.mHintLabel.charAt(0);
|
||||||
codes[1] = codes[0];
|
codes[0] = code;
|
||||||
codes[0] = code;
|
|
||||||
}
|
|
||||||
final boolean ignoreCode = key.ignoreWhileTyping() && mTimerProxy.isTyping();
|
|
||||||
if (!ignoreCode) {
|
|
||||||
// TODO: It might be useful to register the nearest key code in codes[] instead of
|
|
||||||
// just ignoring.
|
|
||||||
callListenerOnCodeInput(key, code, codes, x, y);
|
|
||||||
}
|
|
||||||
callListenerOnRelease(key, code, false);
|
|
||||||
if (!key.ignoreWhileTyping() && !key.isModifier()) {
|
|
||||||
mTimerProxy.startKeyTypedTimer(sIgnoreSpecialKeyTimeout);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swap the first and second values in the codes array if the primary code is not the
|
||||||
|
// first value but the second value in the array. This happens when key debouncing is
|
||||||
|
// in effect.
|
||||||
|
if (codes.length >= 2 && codes[0] != code && codes[1] == code) {
|
||||||
|
codes[1] = codes[0];
|
||||||
|
codes[0] = code;
|
||||||
|
}
|
||||||
|
callListenerOnCodeInput(key, code, codes, x, y);
|
||||||
|
callListenerOnRelease(key, code, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long mPreviousEventTime;
|
private long mPreviousEventTime;
|
||||||
|
|
|
@ -152,6 +152,7 @@ public class KeyStyles {
|
||||||
private void parseKeyStyleAttributes(TypedArray keyAttr) {
|
private void parseKeyStyleAttributes(TypedArray keyAttr) {
|
||||||
// TODO: Currently not all Key attributes can be declared as style.
|
// TODO: Currently not all Key attributes can be declared as style.
|
||||||
readInt(keyAttr, R.styleable.Keyboard_Key_code);
|
readInt(keyAttr, R.styleable.Keyboard_Key_code);
|
||||||
|
readInt(keyAttr, R.styleable.Keyboard_Key_altCode);
|
||||||
readText(keyAttr, R.styleable.Keyboard_Key_keyLabel);
|
readText(keyAttr, R.styleable.Keyboard_Key_keyLabel);
|
||||||
readText(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
|
readText(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
|
||||||
readText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
|
readText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
|
||||||
|
|
Loading…
Reference in New Issue