Fix quotation marks

This change
* Allows snap back from symbols shifted to symbol layout.
* Add "left single", "right single", "single low" and "single high
  reversed" quotation marks to popup characters of "single quote".
* Add "double low" and "double high reversed" quatation marks to popup
  characters of "double quote".
* Add "prime" and "double prime" to popup characters of "degree".
* Disable non-ASCII key of symbol more layout on passowrd input.

Bug: 4345054
Bug: 4347045
Change-Id: I8168ce6a74a9536e4966f7f9d1099ac0132925c7
main
Tadashi G. Takaoka 2011-04-26 14:27:35 +09:00
parent 1123bcaf2e
commit 717cef79ea
8 changed files with 146 additions and 44 deletions

View File

@ -211,9 +211,10 @@
latin:keyLabel="-" /> latin:keyLabel="-" />
</case> </case>
<default> <default>
<!-- Note: DroidSans doesn't have double-high-reversed-quotation '\u201f' glyph. -->
<Key <Key
latin:keyLabel="&quot;" latin:keyLabel="&quot;"
latin:popupCharacters="“,”,«,»,˝" /> latin:popupCharacters="“,”,„,‟,«,»,,,," />
<Key <Key
latin:keyLabel="_" /> latin:keyLabel="_" />
</default> </default>

View File

@ -99,7 +99,8 @@
latin:popupCharacters="↑,↓,←,→" /> latin:popupCharacters="↑,↓,←,→" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle" latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="°" /> latin:keyLabel="°"
latin:popupCharacters=",″" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle" latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="±" latin:keyLabel="±"

View File

@ -312,4 +312,27 @@
latin:popupCharacters="@string/alternates_for_smiley" latin:popupCharacters="@string/alternates_for_smiley"
latin:maxPopupKeyboardColumn="5" latin:maxPopupKeyboardColumn="5"
latin:parentStyle="functionalKeyStyle" /> latin:parentStyle="functionalKeyStyle" />
<switch>
<case
latin:passwordInput="true"
>
<key-style
latin:styleName="nonPasswordSymbolKeyStyle"
latin:enabled="false" />
<key-style
latin:styleName="nonPasswordFunctionalKeyStyle"
latin:enabled="false"
latin:parentStyle="functionalKeyStyle" />
</case>
<!-- latin:passwordInput="false" -->
<default>
<key-style
latin:styleName="nonPasswordSymbolKeyStyle"
latin:enabled="true" />
<key-style
latin:styleName="nonPasswordFunctionalKeyStyle"
latin:enabled="true"
latin:parentStyle="functionalKeyStyle" />
</default>
</switch>
</merge> </merge>

View File

@ -105,12 +105,14 @@
<Key <Key
latin:keyLabel="!" latin:keyLabel="!"
latin:popupCharacters="¡" /> latin:popupCharacters="¡" />
<!-- Note: DroidSans doesn't have double-high-reversed-quotation '\u201f' glyph. -->
<Key <Key
latin:keyLabel="&quot;" latin:keyLabel="&quot;"
latin:popupCharacters="“,”,«,»,˝" /> latin:popupCharacters="“,”,„,‟,«,»"
latin:maxPopupKeyboardColumn="6" />
<Key <Key
latin:keyLabel="\'" latin:keyLabel="\'"
latin:popupCharacters="," /> latin:popupCharacters=",,,,´" />
<Key <Key
latin:keyLabel=":" /> latin:keyLabel=":" />
<Key <Key

View File

@ -42,16 +42,21 @@
<Key <Key
latin:keyLabel="|" /> latin:keyLabel="|" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="•" latin:keyLabel="•"
latin:popupCharacters="♪,♥,♠,♦,♣" /> latin:popupCharacters="♪,♥,♠,♦,♣" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="√" /> latin:keyLabel="√" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="π" latin:keyLabel="π"
latin:popupCharacters="Π" /> latin:popupCharacters="Π" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="÷" /> latin:keyLabel="÷" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="×" /> latin:keyLabel="×" />
<Key <Key
latin:keyLabel="{" /> latin:keyLabel="{" />
@ -64,13 +69,18 @@
latin:keyStyle="nonSpecialBackgroundTabKeyStyle" latin:keyStyle="nonSpecialBackgroundTabKeyStyle"
latin:keyEdgeFlags="left" /> latin:keyEdgeFlags="left" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="£" /> latin:keyLabel="£" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="¢" /> latin:keyLabel="¢" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="€" /> latin:keyLabel="€" />
<Key <Key
latin:keyLabel="°" /> latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="°"
latin:popupCharacters=",″" />
<Key <Key
latin:keyLabel="^" latin:keyLabel="^"
latin:popupCharacters="↑,↓,←,→" /> latin:popupCharacters="↑,↓,←,→" />
@ -92,12 +102,16 @@
latin:visualInsetsRight="1%p" latin:visualInsetsRight="1%p"
latin:keyEdgeFlags="left" /> latin:keyEdgeFlags="left" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="™" /> latin:keyLabel="™" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="®" /> latin:keyLabel="®" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="©" /> latin:keyLabel="©" />
<Key <Key
latin:keyStyle="nonPasswordSymbolKeyStyle"
latin:keyLabel="¶" latin:keyLabel="¶"
latin:popupCharacters="§" /> latin:popupCharacters="§" />
<Key <Key

View File

@ -34,13 +34,14 @@
latin:keyEdgeFlags="left" /> latin:keyEdgeFlags="left" />
<Key <Key
latin:keyLabel="„" latin:keyLabel="„"
latin:keyStyle="functionalKeyStyle" /> latin:popupCharacters="“,”,„,‟,«,»,,,,"
latin:keyStyle="nonPasswordFunctionalKeyStyle" />
<Key <Key
latin:keyStyle="spaceKeyStyle" latin:keyStyle="spaceKeyStyle"
latin:keyWidth="40%p" /> latin:keyWidth="40%p" />
<Key <Key
latin:keyLabel="…" latin:keyLabel="…"
latin:keyStyle="functionalKeyStyle" /> latin:keyStyle="nonPasswordFunctionalKeyStyle" />
<switch> <switch>
<case <case
latin:mode="im" latin:mode="im"
@ -69,13 +70,14 @@
latin:keyStyle="settingsKeyStyle" /> latin:keyStyle="settingsKeyStyle" />
<Key <Key
latin:keyLabel="„" latin:keyLabel="„"
latin:keyStyle="functionalKeyStyle" /> latin:popupCharacters="“,”,„,‟,«,»,,,,"
latin:keyStyle="nonPasswordFunctionalKeyStyle" />
<Key <Key
latin:keyStyle="spaceKeyStyle" latin:keyStyle="spaceKeyStyle"
latin:keyWidth="30%p" /> latin:keyWidth="30%p" />
<Key <Key
latin:keyLabel="…" latin:keyLabel="…"
latin:keyStyle="functionalKeyStyle" /> latin:keyStyle="nonPasswordFunctionalKeyStyle" />
<switch> <switch>
<case <case
latin:mode="im" latin:mode="im"

View File

@ -57,6 +57,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private LatinKeyboardView mInputView; private LatinKeyboardView mInputView;
private LatinIME mInputMethodService; private LatinIME mInputMethodService;
// TODO: Combine these key state objects with auto mode switch state.
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
@ -75,13 +76,17 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private boolean mVoiceKeyEnabled; private boolean mVoiceKeyEnabled;
private boolean mVoiceButtonOnPrimary; private boolean mVoiceButtonOnPrimary;
private static final int AUTO_MODE_SWITCH_STATE_ALPHA = 0; // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState
private static final int AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN = 1; // and ModifierKeyState.
private static final int AUTO_MODE_SWITCH_STATE_SYMBOL = 2; private static final int SWITCH_STATE_ALPHA = 0;
private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
private static final int SWITCH_STATE_SYMBOL = 2;
// The following states are used only on the distinct multi-touch panel devices. // The following states are used only on the distinct multi-touch panel devices.
private static final int AUTO_MODE_SWITCH_STATE_MOMENTARY = 3; private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4; private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
private int mSwitchState = SWITCH_STATE_ALPHA;
// Indicates whether or not we have the settings key in option of settings // Indicates whether or not we have the settings key in option of settings
private boolean mSettingsKeyEnabledInSettings; private boolean mSettingsKeyEnabledInSettings;
@ -124,7 +129,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void loadKeyboard(EditorInfo attribute, boolean voiceKeyEnabled, public void loadKeyboard(EditorInfo attribute, boolean voiceKeyEnabled,
boolean voiceButtonOnPrimary) { boolean voiceButtonOnPrimary) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; mSwitchState = SWITCH_STATE_ALPHA;
try { try {
loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false); loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false);
} catch (RuntimeException e) { } catch (RuntimeException e) {
@ -465,6 +470,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// In symbol mode, just toggle symbol and symbol more keyboard. // In symbol mode, just toggle symbol and symbol more keyboard.
shiftKeyState.onPress(); shiftKeyState.onPress();
toggleShift(); toggleShift();
mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
} }
} }
@ -496,6 +502,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// transited from automatic temporary upper case. // transited from automatic temporary upper case.
toggleShift(); toggleShift();
} }
} else {
// In symbol mode, snap back to the previous keyboard mode if the user chords the shift
// key and another key, then releases the shift key.
if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
toggleShift();
}
} }
shiftKeyState.onRelease(); shiftKeyState.onRelease();
} }
@ -510,7 +522,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
+ " symbolKeyState=" + mSymbolKeyState); + " symbolKeyState=" + mSymbolKeyState);
changeKeyboardMode(); changeKeyboardMode();
mSymbolKeyState.onPress(); mSymbolKeyState.onPress();
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_MOMENTARY; mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
} }
public void onReleaseSymbol() { public void onReleaseSymbol() {
@ -522,9 +534,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
+ " keyboard=" + getLatinKeyboard().getKeyboardShiftState() + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ " symbolKeyState=" + mSymbolKeyState); + " symbolKeyState=" + mSymbolKeyState);
// Snap back to the previous keyboard mode if the user chords the mode change key and // Snap back to the previous keyboard mode if the user chords the mode change key and
// other key, then released the mode change key. // another key, then releases the mode change key.
if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_CHORDING) if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
changeKeyboardMode(); changeKeyboardMode();
}
mSymbolKeyState.onRelease(); mSymbolKeyState.onRelease();
} }
@ -543,8 +556,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void onCancelInput() { public void onCancelInput() {
// Snap back to the previous keyboard mode if the user cancels sliding input. // Snap back to the previous keyboard mode if the user cancels sliding input.
if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY && getPointerCount() == 1) if (getPointerCount() == 1) {
changeKeyboardMode(); if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
changeKeyboardMode();
} else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
toggleShift();
}
}
} }
private void toggleShiftInSymbol() { private void toggleShiftInSymbol() {
@ -567,8 +585,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
setKeyboard(keyboard); setKeyboard(keyboard);
} }
public boolean isInMomentaryAutoModeSwitchState() { public boolean isInMomentarySwitchState() {
return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY; return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
|| mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
} }
public boolean isVibrateAndSoundFeedbackRequired() { public boolean isVibrateAndSoundFeedbackRequired() {
@ -582,9 +601,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private void toggleKeyboardMode() { private void toggleKeyboardMode() {
loadKeyboardInternal(mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary, !mIsSymbols); loadKeyboardInternal(mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary, !mIsSymbols);
if (mIsSymbols) { if (mIsSymbols) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else { } else {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; mSwitchState = SWITCH_STATE_ALPHA;
} }
} }
@ -596,28 +615,52 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mInputView != null && mInputView.hasDistinctMultitouch(); return mInputView != null && mInputView.hasDistinctMultitouch();
} }
private static boolean isSpaceCharacter(int c) {
return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
}
private static boolean isQuoteCharacter(int c) {
// Apostrophe, quotation mark.
if (c == '\'' || c == '"')
return true;
// \u2018: Left single quotation mark
// \u2019: Right single quotation mark
// \u201a: Single low-9 quotation mark
// \u201b: Single high-reversed-9 quotation mark
// \u201c: Left double quotation mark
// \u201d: Right double quotation mark
// \u201e: Double low-9 quotation mark
// \u201f: Double high-reversed-9 quotation mark
if (c >= '\u2018' && c <= '\u201f')
return true;
// \u00ab: Left-pointing double angle quotation mark
// \u00bb: Right-pointing double angle quotation mark
if (c == '\u00ab' || c == '\u00bb')
return true;
return false;
}
/** /**
* Updates state machine to figure out when to automatically snap back to the previous mode. * Updates state machine to figure out when to automatically snap back to the previous mode.
*/ */
public void onKey(int key) { public void onKey(int code) {
if (DEBUG_STATE) if (DEBUG_STATE)
Log.d(TAG, "onKey: code=" + key + " autoModeSwitchState=" + mAutoModeSwitchState Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState
+ " pointers=" + getPointerCount()); + " pointers=" + getPointerCount());
switch (mAutoModeSwitchState) { switch (mSwitchState) {
case AUTO_MODE_SWITCH_STATE_MOMENTARY: case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
// Only distinct multi touch devices can be in this state. // Only distinct multi touch devices can be in this state.
// On non-distinct multi touch devices, mode change key is handled by // On non-distinct multi touch devices, mode change key is handled by
// {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
// {@link LatinIME#onRelease}. So, on such devices, {@link #mAutoModeSwitchState} starts // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
// from {@link #AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, or // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
// {@link #AUTO_MODE_SWITCH_STATE_ALPHA}, not from // {@link #SWITCH_STATE_MOMENTARY}.
// {@link #AUTO_MODE_SWITCH_STATE_MOMENTARY}. if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released. // Detected only the mode change key has been pressed, and then released.
if (mIsSymbols) { if (mIsSymbols) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else { } else {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; mSwitchState = SWITCH_STATE_ALPHA;
} }
} else if (getPointerCount() == 1) { } else if (getPointerCount() == 1) {
// Snap back to the previous keyboard mode if the user pressed the mode change key // Snap back to the previous keyboard mode if the user pressed the mode change key
@ -628,18 +671,34 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else { } else {
// Chording input is being started. The keyboard mode will be snapped back to the // Chording input is being started. The keyboard mode will be snapped back to the
// previous mode in {@link onReleaseSymbol} when the mode change key is released. // previous mode in {@link onReleaseSymbol} when the mode change key is released.
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING; mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
} }
break; break;
case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN: case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key >= 0) { if (code == Keyboard.CODE_SHIFT) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL; // Detected only the shift key has been pressed on symbol layout, and then released.
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else if (getPointerCount() == 1) {
// Snap back to the previous keyboard mode if the user pressed the shift key on
// symbol mode and slid to other key, then released the finger.
toggleShift();
mSwitchState = SWITCH_STATE_SYMBOL;
} else {
// Chording input is being started. The keyboard mode will be snapped back to the
// previous mode in {@link onReleaseShift} when the shift key is released.
mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
} }
break; break;
case AUTO_MODE_SWITCH_STATE_SYMBOL: case SWITCH_STATE_SYMBOL_BEGIN:
if (!isSpaceCharacter(code) && code >= 0) {
mSwitchState = SWITCH_STATE_SYMBOL;
}
break;
case SWITCH_STATE_SYMBOL:
case SWITCH_STATE_CHORDING_SYMBOL:
// Snap back to alpha keyboard mode if user types one or more non-space/enter // Snap back to alpha keyboard mode if user types one or more non-space/enter
// characters followed by a space/enter. // characters followed by a space/enter or quotation mark.
if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) { if (isSpaceCharacter(code) || isQuoteCharacter(code)) {
changeKeyboardMode(); changeKeyboardMode();
} }
break; break;

View File

@ -662,7 +662,7 @@ public class PointerTracker {
// We need not start long press timer on the key which has manual temporary upper case // We need not start long press timer on the key which has manual temporary upper case
// code defined and the keyboard is in manual temporary upper case mode. // code defined and the keyboard is in manual temporary upper case mode.
return; return;
} else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) { } else if (mKeyboardSwitcher.isInMomentarySwitchState()) {
// We use longer timeout for sliding finger input started from the symbols mode key. // We use longer timeout for sliding finger input started from the symbols mode key.
mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this); mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this);
} else { } else {