Merge "Refactor keyboard layout test more customizable"

This commit is contained in:
Tadashi G. Takaoka 2014-03-13 12:09:46 +00:00 committed by Android (Google) Code Review
commit a8e3ae6e96
10 changed files with 608 additions and 327 deletions

View file

@ -34,29 +34,47 @@ public final class KeyboardIconsSet {
public static final int ICON_UNDEFINED = 0; public static final int ICON_UNDEFINED = 0;
private static final int ATTR_UNDEFINED = 0; private static final int ATTR_UNDEFINED = 0;
private static final String NAME_UNDEFINED = "undefined";
public static final String NAME_SHIFT_KEY = "shift_key";
public static final String NAME_SHIFT_KEY_SHIFTED = "shift_key_shifted";
public static final String NAME_DELETE_KEY = "delete_key";
public static final String NAME_SETTINGS_KEY = "settings_key";
public static final String NAME_SPACE_KEY = "space_key";
public static final String NAME_SPACE_KEY_FOR_NUMBER_LAYOUT = "space_key_for_number_layout";
public static final String NAME_ENTER_KEY = "enter_key";
public static final String NAME_SEARCH_KEY = "search_key";
public static final String NAME_TAB_KEY = "tab_key";
public static final String NANE_TAB_KEY_PREVIEW = "tab_key_preview";
public static final String NAME_SHORTCUT_KEY = "shortcut_key";
public static final String NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled";
public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key";
public static final String NAME_ZWNJ_KEY = "zwnj_key";
public static final String NAME_ZWJ_KEY = "zwj_key";
public static final String NAME_EMOJI_KEY = "emoji_key";
private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray(); private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray();
// Icon name to icon id map. // Icon name to icon id map.
private static final HashMap<String, Integer> sNameToIdsMap = CollectionUtils.newHashMap(); private static final HashMap<String, Integer> sNameToIdsMap = CollectionUtils.newHashMap();
private static final Object[] NAMES_AND_ATTR_IDS = { private static final Object[] NAMES_AND_ATTR_IDS = {
"undefined", ATTR_UNDEFINED, NAME_UNDEFINED, ATTR_UNDEFINED,
"shift_key", R.styleable.Keyboard_iconShiftKey, NAME_SHIFT_KEY, R.styleable.Keyboard_iconShiftKey,
"delete_key", R.styleable.Keyboard_iconDeleteKey, NAME_DELETE_KEY, R.styleable.Keyboard_iconDeleteKey,
"settings_key", R.styleable.Keyboard_iconSettingsKey, NAME_SETTINGS_KEY, R.styleable.Keyboard_iconSettingsKey,
"space_key", R.styleable.Keyboard_iconSpaceKey, NAME_SPACE_KEY, R.styleable.Keyboard_iconSpaceKey,
"enter_key", R.styleable.Keyboard_iconEnterKey, NAME_ENTER_KEY, R.styleable.Keyboard_iconEnterKey,
"search_key", R.styleable.Keyboard_iconSearchKey, NAME_SEARCH_KEY, R.styleable.Keyboard_iconSearchKey,
"tab_key", R.styleable.Keyboard_iconTabKey, NAME_TAB_KEY, R.styleable.Keyboard_iconTabKey,
"shortcut_key", R.styleable.Keyboard_iconShortcutKey, NAME_SHORTCUT_KEY, R.styleable.Keyboard_iconShortcutKey,
"space_key_for_number_layout", R.styleable.Keyboard_iconSpaceKeyForNumberLayout, NAME_SPACE_KEY_FOR_NUMBER_LAYOUT, R.styleable.Keyboard_iconSpaceKeyForNumberLayout,
"shift_key_shifted", R.styleable.Keyboard_iconShiftKeyShifted, NAME_SHIFT_KEY_SHIFTED, R.styleable.Keyboard_iconShiftKeyShifted,
"shortcut_key_disabled", R.styleable.Keyboard_iconShortcutKeyDisabled, NAME_SHORTCUT_KEY_DISABLED, R.styleable.Keyboard_iconShortcutKeyDisabled,
"tab_key_preview", R.styleable.Keyboard_iconTabKeyPreview, NANE_TAB_KEY_PREVIEW, R.styleable.Keyboard_iconTabKeyPreview,
"language_switch_key", R.styleable.Keyboard_iconLanguageSwitchKey, NAME_LANGUAGE_SWITCH_KEY, R.styleable.Keyboard_iconLanguageSwitchKey,
"zwnj_key", R.styleable.Keyboard_iconZwnjKey, NAME_ZWNJ_KEY, R.styleable.Keyboard_iconZwnjKey,
"zwj_key", R.styleable.Keyboard_iconZwjKey, NAME_ZWJ_KEY, R.styleable.Keyboard_iconZwjKey,
"emoji_key", R.styleable.Keyboard_iconEmojiKey, NAME_EMOJI_KEY, R.styleable.Keyboard_iconEmojiKey,
}; };
private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2; private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2;

View file

@ -1,45 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.inputmethod.keyboard.layout;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
import com.android.inputmethod.latin.Constants;
import java.util.Locale;
/**
* The generic upper case alphabet keyboard layout.
*/
public final class AlphabetShifted extends LayoutBase {
public static ExpectedKey[][] getDefaultLayout(final ExpectedKey[][] lowerCaseKeyboard,
final Locale locale) {
final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(lowerCaseKeyboard);
builder.toUpperCase(locale);
builder.replaceKeysOfAll(SHIFT_KEY, SHIFTED_SHIFT_KEY);
return builder.build();
}
// Icon id.
private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId("shift_key_shifted");
// Functional key.
private static final ExpectedKey SHIFTED_SHIFT_KEY = key(
ICON_SHIFTED_SHIFT, Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
}

View file

@ -0,0 +1,346 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.inputmethod.keyboard.layout;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import com.android.inputmethod.latin.Constants;
import java.util.Locale;
/**
* The base class of keyboard layout.
*/
public abstract class LayoutBase extends AbstractLayoutBase {
/**
* This class is used to customize common keyboard layout to language specific layout.
*/
public static class LayoutCustomizer {
private final Locale mLocale;
// Empty keys definition to remove keys by adding this.
protected static final ExpectedKey[] EMPTY_KEYS = joinKeys();
public LayoutCustomizer(final Locale locale) {
mLocale = locale;
}
public final Locale getLocale() {
return mLocale;
}
/**
* Set accented letters to common layout.
* @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
* layout.
* @return the {@link ExpectedKeyboardBuilder} object that contains accented letters as
* "more keys".
*/
public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
return builder;
}
/**
* Get the function key to switch to alphabet layout.
* @return the {@link ExpectedKey} of the alphabet key.
*/
public ExpectedKey getAlphabetKey() { return ALPHABET_KEY; }
/**
* Get the function key to switch to symbols layout.
* @return the {@link ExpectedKey} of the symbols key.
*/
public ExpectedKey getSymbolsKey() { return SYMBOLS_KEY; }
/**
* Get the function key to switch to symbols shift layout.
* @param isPhone true if requesting phone's key.
* @return the {@link ExpectedKey} of the symbols shift key.
*/
public ExpectedKey getSymbolsShiftKey(boolean isPhone) {
return isPhone ? SYMBOLS_SHIFT_KEY : TABLET_SYMBOLS_SHIFT_KEY;
}
/**
* Get the function key to switch from symbols shift to symbols layout.
* @return the {@link ExpectedKey} of the back to symbols key.
*/
public ExpectedKey getBackToSymbolsKey() { return BACK_TO_SYMBOLS_KEY; }
/**
* Get the currency key.
* @return the {@link ExpectedKey} of the currency key.
*/
public ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_DOLLAR; }
/**
* Get other currencies keys.
* @return the array of {@link ExpectedKey} that represents other currency keys.
*/
public ExpectedKey[] getOtherCurrencyKeys() {
return SymbolsShifted.CURRENCIES_OTHER_THAN_DOLLAR;
}
/**
* Get "more keys" of double quotation mark.
* @return the array of {@link ExpectedKey} of more double quotation marks in natural order.
*/
public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_9LR; }
/**
* Get "more keys" of single quotation mark.
* @return the array of {@link ExpectedKey} of more single quotation marks in natural order.
*/
public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_9LR; }
/**
* Get double angle quotation marks in natural order.
* @return the array of {@link ExpectedKey} of double angle quotation marks in natural
* order.
*/
public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_LR; }
/**
* Get single angle quotation marks in natural order.
* @return the array of {@link ExpectedKey} of single angle quotation marks in natural
* order.
*/
public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_LR; }
/**
* Get the left shift keys.
* @param isPhone true if requesting phone's keys.
* @return the array of {@link ExpectedKey} that should be placed at left edge of the
* keyboard.
*/
public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) {
return joinKeys(SHIFT_KEY);
}
/**
* Get the right shift keys.
* @param isPhone true if requesting phone's keys.
* @return the array of {@link ExpectedKey} that should be placed at right edge of the
* keyboard.
*/
public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
return isPhone ? EMPTY_KEYS : joinKeys(EXCLAMATION_AND_QUESTION_MARKS, SHIFT_KEY);
}
/**
* Get the keys left to the spacebar.
* @param isPhone true if requesting phone's keys.
* @return the array of {@link ExpectedKey} that should be placed at left of the spacebar.
*/
public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
return isPhone ? joinKeys(key(",", SETTINGS_KEY)) : joinKeys(key("/"));
}
/**
* Get the keys right to the spacebar.
* @param isPhone true if requesting phone's keys.
* @return the array of {@link ExpectedKey} that should be placed at right of the spacebar.
*/
public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
final ExpectedKey periodKey = key(".", getPunctuationMoreKeys(isPhone));
return isPhone ? joinKeys(periodKey) : joinKeys(key(","), periodKey);
}
/**
* Get "more keys" for the punctuation key (usually the period key).
* @param isPhone true if requesting phone's keys.
* @return the array of {@link ExpectedKey} that are "more keys" of the punctuation key.
*/
public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) {
return isPhone ? PHONE_PUNCTUATION_MORE_KEYS
: TABLET_PUNCTUATION_MORE_KEYS;
}
}
/**
* The layout customize class for countries that use Euro.
*/
public static class EuroLayoutCustomizer extends LayoutCustomizer {
public EuroLayoutCustomizer(final Locale locale) {
super(locale);
}
@Override
public final ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_EURO; }
@Override
public final ExpectedKey[] getOtherCurrencyKeys() {
return SymbolsShifted.CURRENCIES_OTHER_THAN_EURO;
}
}
private final LayoutCustomizer mCustomizer;
private final Symbols mSymbols;
private final SymbolsShifted mSymbolsShifted;
LayoutBase(final LayoutCustomizer customizer, final Class<? extends Symbols> symbolsClass,
final Class<? extends SymbolsShifted> symbolsShiftedClass) {
mCustomizer = customizer;
try {
mSymbols = symbolsClass.getDeclaredConstructor(LayoutCustomizer.class)
.newInstance(customizer);
mSymbolsShifted = symbolsShiftedClass.getDeclaredConstructor(LayoutCustomizer.class)
.newInstance(customizer);
} catch (final Exception e) {
throw new RuntimeException("Unknown Symbols/SymbolsShifted class", e);
}
}
/**
* The layout name.
* @return the name of this layout.
*/
public abstract String getName();
/**
* The locale of this layout.
* @return the locale of this layout.
*/
public final Locale getLocale() { return mCustomizer.getLocale(); }
/**
* The layout customizer for this layout.
* @return the layout customizer;
*/
public final LayoutCustomizer getCustomizer() { return mCustomizer; }
// Icon id.
private static final int ICON_SHIFT = KeyboardIconsSet.getIconId(
KeyboardIconsSet.NAME_SHIFT_KEY);
private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId(
KeyboardIconsSet.NAME_SHIFT_KEY_SHIFTED);
// Functional key.
static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK);
static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT,
Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT,
Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL);
static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL);
static final ExpectedKey BACK_TO_SYMBOLS_KEY = key("?123", Constants.CODE_SHIFT);
static final ExpectedKey SYMBOLS_SHIFT_KEY = key("= \\ <", Constants.CODE_SHIFT);
static final ExpectedKey TABLET_SYMBOLS_SHIFT_KEY = key("~ [ <", Constants.CODE_SHIFT);
// U+00A1: "¡" INVERTED EXCLAMATION MARK
// U+00BF: "¿" INVERTED QUESTION MARK
static final ExpectedKey[] EXCLAMATION_AND_QUESTION_MARKS = joinKeys(
key("!", moreKey("\u00A1")), key("?", moreKey("\u00BF")));
// Punctuation more keys for phone form factor.
public static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = joinKeys(
";", "/", "(", ")", "#", "!", ",", "?",
"&", "%", "+", "\"", "-", ":", "'", "@");
// Punctuation more keys for tablet form factor.
public static final ExpectedKey[] TABLET_PUNCTUATION_MORE_KEYS = joinKeys(
";", "/", "(", ")", "#", "'", ",",
"&", "%", "+", "\"", "-", ":", "@");
/**
* Helper method to create alphabet layout adding special function keys.
* @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
* layout
* @param isPhone true if requesting phone's layout.
* @return the {@link ExpectedKeyboardBuilder} object that is customized and have special keys.
*/
ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
final boolean isPhone) {
final LayoutCustomizer customizer = getCustomizer();
final ExpectedKey[] spacebar = joinKeys(
customizer.getKeysLeftToSpacebar(isPhone),
SPACEBAR,
customizer.getKeysRightToSpacebar(isPhone));
builder.setKeysOfRow(4, spacebar);
if (isPhone) {
builder.addKeysOnTheRightOfRow(3, DELETE_KEY)
.addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey())
.addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY));
} else {
builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
.addKeysOnTheRightOfRow(2, ENTER_KEY)
.addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey(), SETTINGS_KEY)
.addKeysOnTheRightOfRow(4, EMOJI_KEY);
}
builder.addKeysOnTheLeftOfRow(3, customizer.getLeftShiftKeys(isPhone))
.addKeysOnTheRightOfRow(3, customizer.getRightShiftKeys(isPhone));
return builder;
}
/**
* Get common alphabet layout. This layout doesn't contain any special keys.
* @param isPhone true if requesting phone's layout.
* @return the common alphabet keyboard layout.
*/
abstract ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone);
/**
* Get common alphabet shifted layout. This layout doesn't contain any special keys.
* @param isPhone true if requesting phone's layout.
* @param elementId the element id of the requesting shifted mode.
* @return the common alphabet shifted keyboard layout.
*/
ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) {
final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
getCommonAlphabetLayout(isPhone));
getCustomizer().setAccentedLetters(builder);
builder.toUpperCase(getLocale());
return builder.build();
}
/**
* Get the complete expected keyboard layout.
* @param isPhone true if requesting phone's layout.
* @param elementId the element id of the requesting keyboard mode.
* @return
*/
public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) {
if (elementId == KeyboardId.ELEMENT_SYMBOLS) {
return mSymbols.getLayout(isPhone);
}
if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
return mSymbolsShifted.getLayout(isPhone);
}
final ExpectedKeyboardBuilder builder;
if (elementId == KeyboardId.ELEMENT_ALPHABET) {
builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone));
getCustomizer().setAccentedLetters(builder);
} else {
final ExpectedKey[][] commonLayout = getCommonAlphabetShiftLayout(isPhone, elementId);
if (commonLayout == null) {
return null;
}
builder = new ExpectedKeyboardBuilder(commonLayout);
}
convertCommonLayoutToKeyboard(builder, isPhone);
if (elementId != KeyboardId.ELEMENT_ALPHABET) {
builder.replaceKeysOfAll(SHIFT_KEY, SHIFTED_SHIFT_KEY);
}
return builder.build();
}
}

View file

@ -18,18 +18,23 @@ package com.android.inputmethod.keyboard.layout;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
/** /**
* The QWERTY alphabet keyboard. * The QWERTY alphabet keyboard.
*/ */
public final class Qwerty extends LayoutBase { public final class Qwerty extends LayoutBase {
public static final String LAYOUT_NAME = "qwerty"; private static final String LAYOUT_NAME = "qwerty";
public static ExpectedKey[][] getLayout(final boolean isPhone) { public Qwerty(final LayoutCustomizer customizer) {
return getDefaultAlphabetLayout(ALPHABET_COMMON, isPhone); super(customizer, Symbols.class, SymbolsShifted.class);
} }
@Override
public String getName() { return LAYOUT_NAME; }
@Override
ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; }
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder(10, 9, 7, 3) private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder(10, 9, 7, 3)
.setLabelsOfRow(1, "q", "w", "e", "r", "t", "y", "u", "i", "o", "p") .setLabelsOfRow(1, "q", "w", "e", "r", "t", "y", "u", "i", "o", "p")
.setMoreKeysOf("q", "1") .setMoreKeysOf("q", "1")

View file

@ -16,36 +16,34 @@
package com.android.inputmethod.keyboard.layout; package com.android.inputmethod.keyboard.layout;
import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer;
import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
import com.android.inputmethod.latin.Constants;
/** /**
* The symbols keyboard layout. * The symbols keyboard layout.
*/ */
public final class Symbols extends LayoutBase { public class Symbols extends AbstractLayoutBase {
public static ExpectedKey[][] getLayout(final boolean isPhone) { private final LayoutCustomizer mCustomizer;
return isPhone ? toPhoneSymbol(SYMBOLS_COMMON) : toTabletSymbols(SYMBOLS_COMMON);
public Symbols(final LayoutCustomizer customizer) {
mCustomizer = customizer;
} }
public static ExpectedKey[][] getDefaultLayout(final boolean isPhone) { public ExpectedKey[][] getLayout(final boolean isPhone) {
final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(getLayout(isPhone)); final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(isPhone
builder.replaceKeyOfLabel(CURRENCY, Symbols.CURRENCY_DOLLAR); ? toPhoneSymbol(SYMBOLS_COMMON) : toTabletSymbols(SYMBOLS_COMMON));
builder.replaceKeyOfLabel(DOUBLE_QUOTE, builder.replaceKeyOfLabel(CURRENCY, mCustomizer.getCurrencyKey());
key("\"", join(Symbols.DOUBLE_QUOTES_9LR, Symbols.DOUBLE_ANGLE_QUOTES_LR))); builder.replaceKeyOfLabel(DOUBLE_QUOTE, key("\"", joinKeys(
builder.replaceKeyOfLabel(SINGLE_QUOTE, mCustomizer.getDoubleQuoteMoreKeys(), mCustomizer.getDoubleAngleQuoteKeys())));
key("'", join(Symbols.SINGLE_QUOTES_9LR, Symbols.SINGLE_ANGLE_QUOTES_LR))); builder.replaceKeyOfLabel(SINGLE_QUOTE, key("'", joinKeys(
mCustomizer.getSingleQuoteMoreKeys(), mCustomizer.getSingleAngleQuoteKeys())));
return builder.build(); return builder.build();
} }
// Functional keys.
public static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL);
public static final ExpectedKey SYMBOLS_SHIFT_KEY = key("= \\ <", Constants.CODE_SHIFT);
public static final ExpectedKey TABLET_SYMBOLS_SHIFT_KEY = key("~ [ <", Constants.CODE_SHIFT);
// Variations of the "currency" key on the 2nd row. // Variations of the "currency" key on the 2nd row.
public static final String CURRENCY = "currency"; public static final String CURRENCY = "CURRENCY";
// U+00A2: "¢" CENT SIGN // U+00A2: "¢" CENT SIGN
// U+00A3: "£" POUND SIGN // U+00A3: "£" POUND SIGN
// U+00A5: "¥" YEN SIGN // U+00A5: "¥" YEN SIGN
@ -63,13 +61,13 @@ public final class Symbols extends LayoutBase {
CENT_SIGN, POUND_SIGN, DOLLAR_SIGN, YEN_SIGN, PESO_SIGN); CENT_SIGN, POUND_SIGN, DOLLAR_SIGN, YEN_SIGN, PESO_SIGN);
// Variations of the "double quote" key's "more keys" on the 3rd row. // Variations of the "double quote" key's "more keys" on the 3rd row.
public static final String DOUBLE_QUOTE = "double_quote"; public static final String DOUBLE_QUOTE = "DOUBLE_QUOTE";
// U+201C: "" LEFT DOUBLE QUOTATION MARK // U+201C: "" LEFT DOUBLE QUOTATION MARK
// U+201D: "" RIGHT DOUBLE QUOTATION MARK // U+201D: "" RIGHT DOUBLE QUOTATION MARK
// U+201E: "" DOUBLE LOW-9 QUOTATION MARK // U+201E: "" DOUBLE LOW-9 QUOTATION MARK
static final ExpectedKey DQUOTE_LEFT = key("\u201C"); private static final ExpectedKey DQUOTE_LEFT = key("\u201C");
static final ExpectedKey DQUOTE_RIGHT = key("\u201D"); private static final ExpectedKey DQUOTE_RIGHT = key("\u201D");
static final ExpectedKey DQUOTE_LOW9 = key("\u201E"); private static final ExpectedKey DQUOTE_LOW9 = key("\u201E");
public static ExpectedKey[] DOUBLE_QUOTES_9LR = { DQUOTE_LOW9, DQUOTE_LEFT, DQUOTE_RIGHT }; public static ExpectedKey[] DOUBLE_QUOTES_9LR = { DQUOTE_LOW9, DQUOTE_LEFT, DQUOTE_RIGHT };
public static ExpectedKey[] DOUBLE_QUOTES_R9L = { DQUOTE_RIGHT, DQUOTE_LOW9, DQUOTE_LEFT }; public static ExpectedKey[] DOUBLE_QUOTES_R9L = { DQUOTE_RIGHT, DQUOTE_LOW9, DQUOTE_LEFT };
public static ExpectedKey[] DOUBLE_QUOTES_L9R = { DQUOTE_LEFT, DQUOTE_LOW9, DQUOTE_RIGHT }; public static ExpectedKey[] DOUBLE_QUOTES_L9R = { DQUOTE_LEFT, DQUOTE_LOW9, DQUOTE_RIGHT };
@ -78,20 +76,17 @@ public final class Symbols extends LayoutBase {
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
private static final ExpectedKey DAQUOTE_LEFT = key("\u00AB"); private static final ExpectedKey DAQUOTE_LEFT = key("\u00AB");
private static final ExpectedKey DAQUOTE_RIGHT = key("\u00BB"); private static final ExpectedKey DAQUOTE_RIGHT = key("\u00BB");
private static final ExpectedKey DAQUOTE_LEFT_RTL = key("\u00AB", "\u00BB");
private static final ExpectedKey DAQUOTE_RIGHT_RTL = key("\u00BB", "\u00AB");
public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_LR = { DAQUOTE_LEFT, DAQUOTE_RIGHT }; public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_LR = { DAQUOTE_LEFT, DAQUOTE_RIGHT };
public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_RL = { DAQUOTE_RIGHT, DAQUOTE_LEFT }; public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_RL = { DAQUOTE_RIGHT, DAQUOTE_LEFT };
public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_RTL = { DAQUOTE_LEFT_RTL, DAQUOTE_RIGHT_RTL };
// Variations of the "single quote" key's "more keys" on the 3rd row. // Variations of the "single quote" key's "more keys" on the 3rd row.
public static final String SINGLE_QUOTE = "single_quote"; public static final String SINGLE_QUOTE = "SINGLE_QUOTE";
// U+2018: "" LEFT SINGLE QUOTATION MARK // U+2018: "" LEFT SINGLE QUOTATION MARK
// U+2019: "" RIGHT SINGLE QUOTATION MARK // U+2019: "" RIGHT SINGLE QUOTATION MARK
// U+201A: "" SINGLE LOW-9 QUOTATION MARK // U+201A: "" SINGLE LOW-9 QUOTATION MARK
static final ExpectedKey SQUOTE_LEFT = key("\u2018"); private static final ExpectedKey SQUOTE_LEFT = key("\u2018");
static final ExpectedKey SQUOTE_RIGHT = key("\u2019"); private static final ExpectedKey SQUOTE_RIGHT = key("\u2019");
static final ExpectedKey SQUOTE_LOW9 = key("\u201A"); private static final ExpectedKey SQUOTE_LOW9 = key("\u201A");
public static ExpectedKey[] SINGLE_QUOTES_9LR = { SQUOTE_LOW9, SQUOTE_LEFT, SQUOTE_RIGHT }; public static ExpectedKey[] SINGLE_QUOTES_9LR = { SQUOTE_LOW9, SQUOTE_LEFT, SQUOTE_RIGHT };
public static ExpectedKey[] SINGLE_QUOTES_R9L = { SQUOTE_RIGHT, SQUOTE_LOW9, SQUOTE_LEFT }; public static ExpectedKey[] SINGLE_QUOTES_R9L = { SQUOTE_RIGHT, SQUOTE_LOW9, SQUOTE_LEFT };
public static ExpectedKey[] SINGLE_QUOTES_L9R = { SQUOTE_LEFT, SQUOTE_LOW9, SQUOTE_RIGHT }; public static ExpectedKey[] SINGLE_QUOTES_L9R = { SQUOTE_LEFT, SQUOTE_LOW9, SQUOTE_RIGHT };
@ -100,14 +95,11 @@ public final class Symbols extends LayoutBase {
// U+203A: "" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK // U+203A: "" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
private static final ExpectedKey SAQUOTE_LEFT = key("\u2039"); private static final ExpectedKey SAQUOTE_LEFT = key("\u2039");
private static final ExpectedKey SAQUOTE_RIGHT = key("\u203A"); private static final ExpectedKey SAQUOTE_RIGHT = key("\u203A");
private static final ExpectedKey SAQUOTE_LEFT_RTL = key("\u2039", "\u203A");
private static final ExpectedKey SAQUOTE_RIGHT_RTL = key("\u203A", "\u2039");
public static ExpectedKey[] SINGLE_ANGLE_QUOTES_LR = { SAQUOTE_LEFT, SAQUOTE_RIGHT }; public static ExpectedKey[] SINGLE_ANGLE_QUOTES_LR = { SAQUOTE_LEFT, SAQUOTE_RIGHT };
public static ExpectedKey[] SINGLE_ANGLE_QUOTES_RL = { SAQUOTE_RIGHT, SAQUOTE_LEFT }; public static ExpectedKey[] SINGLE_ANGLE_QUOTES_RL = { SAQUOTE_RIGHT, SAQUOTE_LEFT };
public static ExpectedKey[] SINGLE_ANGLE_QUOTES_RTL = { SAQUOTE_LEFT_RTL, SAQUOTE_RIGHT_RTL };
// Common symbols keyboard layout. // Common symbols keyboard layout.
public static final ExpectedKey[][] SYMBOLS_COMMON = new ExpectedKeyboardBuilder(10, 9, 7, 5) private static final ExpectedKey[][] SYMBOLS_COMMON = new ExpectedKeyboardBuilder(10, 9, 7, 5)
.setLabelsOfRow(1, "1", "2", "3", "4", "5", "6", "7", "8", "9", "0") .setLabelsOfRow(1, "1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
// U+00B9: "¹" SUPERSCRIPT ONE // U+00B9: "¹" SUPERSCRIPT ONE
// U+00BD: "½" VULGAR FRACTION ONE HALF // U+00BD: "½" VULGAR FRACTION ONE HALF
@ -156,25 +148,56 @@ public final class Symbols extends LayoutBase {
.setMoreKeysOf(".", "\u2026") .setMoreKeysOf(".", "\u2026")
.build(); .build();
private static ExpectedKey[][] toPhoneSymbol(final ExpectedKey[][] common) { private ExpectedKey[][] toPhoneSymbol(final ExpectedKey[][] common) {
return new ExpectedKeyboardBuilder(common) return new ExpectedKeyboardBuilder(common)
.addKeysOnTheLeftOfRow(3, Symbols.SYMBOLS_SHIFT_KEY) .addKeysOnTheLeftOfRow(3, mCustomizer.getSymbolsShiftKey(true /* isPhone */))
.addKeysOnTheRightOfRow(3, DELETE_KEY) .addKeysOnTheRightOfRow(3, DELETE_KEY)
.addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY) .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
.addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY)) .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY))
.build(); .build();
} }
private static ExpectedKey[][] toTabletSymbols(final ExpectedKey[][] common) { private ExpectedKey[][] toTabletSymbols(final ExpectedKey[][] common) {
return new ExpectedKeyboardBuilder(common) return new ExpectedKeyboardBuilder(common)
.addKeysOnTheLeftOfRow(3, .addKeysOnTheLeftOfRow(3,
key("\\"), key("=")) key("\\"), key("="))
.addKeysOnTheRightOfRow(1, DELETE_KEY) .addKeysOnTheRightOfRow(1, DELETE_KEY)
.addKeysOnTheRightOfRow(2, ENTER_KEY) .addKeysOnTheRightOfRow(2, ENTER_KEY)
.addKeysOnTheLeftOfRow(3, Symbols.TABLET_SYMBOLS_SHIFT_KEY) .addKeysOnTheLeftOfRow(3, mCustomizer.getSymbolsShiftKey(false /* isPhone */))
.addKeysOnTheRightOfRow(3, Symbols.TABLET_SYMBOLS_SHIFT_KEY) .addKeysOnTheRightOfRow(3, mCustomizer.getSymbolsShiftKey(false /* isPhone */))
.addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY) .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
.addKeysOnTheRightOfRow(4, EMOJI_KEY) .addKeysOnTheRightOfRow(4, EMOJI_KEY)
.build(); .build();
} }
public static class RtlSymbols extends Symbols {
public RtlSymbols(final LayoutCustomizer customizer) {
super(customizer);
}
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
private static final ExpectedKey DAQUOTE_LEFT_RTL = key("\u00AB", "\u00BB");
private static final ExpectedKey DAQUOTE_RIGHT_RTL = key("\u00BB", "\u00AB");
public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_LR_RTL = {
DAQUOTE_LEFT_RTL, DAQUOTE_RIGHT_RTL
};
// U+2039: "" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
private static final ExpectedKey SAQUOTE_LEFT_RTL = key("\u2039", "\u203A");
private static final ExpectedKey SAQUOTE_RIGHT_RTL = key("\u203A", "\u2039");
public static ExpectedKey[] SINGLE_ANGLE_QUOTES_LR_RTL = {
SAQUOTE_LEFT_RTL, SAQUOTE_RIGHT_RTL
};
@Override
public ExpectedKey[][] getLayout(final boolean isPhone) {
return new ExpectedKeyboardBuilder(super.getLayout(isPhone))
.replaceKeyOfLabel("(", key("(", ")",
moreKey("<", ">"), moreKey("{", "}"), moreKey("[", "]")))
.replaceKeyOfLabel(")", key(")", "(",
moreKey(">", "<"), moreKey("}", "{"), moreKey("]", "[")))
.build();
}
}
} }

View file

@ -16,31 +16,31 @@
package com.android.inputmethod.keyboard.layout; package com.android.inputmethod.keyboard.layout;
import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import com.android.inputmethod.keyboard.layout.expected.LayoutBase; import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
import com.android.inputmethod.latin.Constants;
/** /**
* The symbols shifted keyboard layout. * The symbols shifted keyboard layout.
*/ */
public final class SymbolsShifted extends LayoutBase { public class SymbolsShifted extends AbstractLayoutBase {
public static ExpectedKey[][] getLayout(final boolean isPhone) { private final LayoutCustomizer mCustomizer;
return isPhone ? toPhoneSymbolsShifted(SYMBOLS_SHIFTED_COMMON)
: toTabletSymbolsShifted(SYMBOLS_SHIFTED_COMMON); public SymbolsShifted(final LayoutCustomizer customizer) {
mCustomizer = customizer;
} }
public static ExpectedKey[][] getDefaultLayout(final boolean isPhone) { public ExpectedKey[][] getLayout(final boolean isPhone) {
final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(getLayout(isPhone)); final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(isPhone
builder.replaceKeyOfLabel(OTHER_CURRENCIES, SymbolsShifted.CURRENCIES_OTHER_THAN_DOLLAR); ? toPhoneSymbolsShifted(SYMBOLS_SHIFTED_COMMON)
: toTabletSymbolsShifted(SYMBOLS_SHIFTED_COMMON));
builder.replaceKeyOfLabel(OTHER_CURRENCIES, mCustomizer.getOtherCurrencyKeys());
return builder.build(); return builder.build();
} }
// Functional key.
public static final ExpectedKey BACK_TO_SYMBOLS_KEY = key("?123", Constants.CODE_SHIFT);
// Variations of the "other currencies" keys on the 2rd row. // Variations of the "other currencies" keys on the 2rd row.
public static final String OTHER_CURRENCIES = "other_currencies"; public static final String OTHER_CURRENCIES = "OTHER_CURRENCY";
public static final ExpectedKey[] CURRENCIES_OTHER_THAN_DOLLAR = { public static final ExpectedKey[] CURRENCIES_OTHER_THAN_DOLLAR = {
Symbols.POUND_SIGN, Symbols.CENT_SIGN, Symbols.EURO_SIGN, Symbols.YEN_SIGN Symbols.POUND_SIGN, Symbols.CENT_SIGN, Symbols.EURO_SIGN, Symbols.YEN_SIGN
}; };
@ -50,7 +50,7 @@ public final class SymbolsShifted extends LayoutBase {
}; };
// Common symbols shifted keyboard layout. // Common symbols shifted keyboard layout.
public static final ExpectedKey[][] SYMBOLS_SHIFTED_COMMON = private static final ExpectedKey[][] SYMBOLS_SHIFTED_COMMON =
new ExpectedKeyboardBuilder(10, 1 /* other_currencies */ + 5, 7, 5) new ExpectedKeyboardBuilder(10, 1 /* other_currencies */ + 5, 7, 5)
// U+0060: "`" GRAVE ACCENT // U+0060: "`" GRAVE ACCENT
// U+2022: "" BULLET // U+2022: "" BULLET
@ -112,16 +112,16 @@ public final class SymbolsShifted extends LayoutBase {
.setMoreKeysOf(".", "\u2026") .setMoreKeysOf(".", "\u2026")
.build(); .build();
private static ExpectedKey[][] toPhoneSymbolsShifted(final ExpectedKey[][] common) { private ExpectedKey[][] toPhoneSymbolsShifted(final ExpectedKey[][] common) {
return new ExpectedKeyboardBuilder(common) return new ExpectedKeyboardBuilder(common)
.addKeysOnTheLeftOfRow(3, BACK_TO_SYMBOLS_KEY) .addKeysOnTheLeftOfRow(3, mCustomizer.getBackToSymbolsKey())
.addKeysOnTheRightOfRow(3, DELETE_KEY) .addKeysOnTheRightOfRow(3, DELETE_KEY)
.addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY) .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
.addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY)) .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY))
.build(); .build();
} }
private static ExpectedKey[][] toTabletSymbolsShifted(final ExpectedKey[][] common) { private ExpectedKey[][] toTabletSymbolsShifted(final ExpectedKey[][] common) {
return new ExpectedKeyboardBuilder(common) return new ExpectedKeyboardBuilder(common)
// U+00BF: "¿" INVERTED QUESTION MARK // U+00BF: "¿" INVERTED QUESTION MARK
// U+00A1: "¡" INVERTED EXCLAMATION MARK // U+00A1: "¡" INVERTED EXCLAMATION MARK
@ -129,10 +129,38 @@ public final class SymbolsShifted extends LayoutBase {
key("\u00A1"), key("\u00BF")) key("\u00A1"), key("\u00BF"))
.addKeysOnTheRightOfRow(1, DELETE_KEY) .addKeysOnTheRightOfRow(1, DELETE_KEY)
.addKeysOnTheRightOfRow(2, ENTER_KEY) .addKeysOnTheRightOfRow(2, ENTER_KEY)
.addKeysOnTheLeftOfRow(3, BACK_TO_SYMBOLS_KEY) .addKeysOnTheLeftOfRow(3, mCustomizer.getBackToSymbolsKey())
.addKeysOnTheRightOfRow(3, BACK_TO_SYMBOLS_KEY) .addKeysOnTheRightOfRow(3, mCustomizer.getBackToSymbolsKey())
.addKeysOnTheLeftOfRow(4, Symbols.ALPHABET_KEY) .addKeysOnTheLeftOfRow(4, mCustomizer.getAlphabetKey())
.addKeysOnTheRightOfRow(4, EMOJI_KEY) .addKeysOnTheRightOfRow(4, EMOJI_KEY)
.build(); .build();
} }
public static class RtlSymbolsShifted extends SymbolsShifted {
public RtlSymbolsShifted(final LayoutCustomizer customizer) {
super(customizer);
}
@Override
public ExpectedKey[][] getLayout(final boolean isPhone) {
return new ExpectedKeyboardBuilder(super.getLayout(isPhone))
.replaceKeyOfLabel("{", key("{", "}"))
.replaceKeyOfLabel("}", key("}", "{"))
.replaceKeyOfLabel("[", key("[", "]"))
.replaceKeyOfLabel("]", key("]", "["))
// U+2039: "" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+2264: "" LESS-THAN OR EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
.replaceKeyOfLabel("<", key("<", ">",
moreKey("\u2039", "\u203A"), moreKey("\u2264", "\u2265"),
moreKey("\u00AB", "\u00BB")))
// U+203A: "" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
// U+2265: "" GREATER-THAN EQUAL TO
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
.replaceKeyOfLabel(">", key(">", "<",
moreKey("\u203A", "\u2039"), moreKey("\u2265", "\u2264"),
moreKey("\u00BB", "\u00AB")))
.build();
}
}
} }

View file

@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard.layout.expected;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -26,7 +27,7 @@ import java.util.Arrays;
/** /**
* Base class to create an expected keyboard for unit test. * Base class to create an expected keyboard for unit test.
*/ */
public class LayoutBase { public abstract class AbstractLayoutBase {
// Those helper methods have a lower case name to be readable when defining expected keyboard // Those helper methods have a lower case name to be readable when defining expected keyboard
// layouts. // layouts.
@ -77,7 +78,7 @@ public class LayoutBase {
// Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey},
// {@link ExpectedKey} array, and {@link String}. // {@link ExpectedKey} array, and {@link String}.
public static ExpectedKey[] join(final Object ... keys) { public static ExpectedKey[] joinKeys(final Object ... keys) {
final ArrayList<ExpectedKey> list = CollectionUtils.newArrayList(); final ArrayList<ExpectedKey> list = CollectionUtils.newArrayList();
for (final Object key : keys) { for (final Object key : keys) {
if (key instanceof ExpectedKey) { if (key instanceof ExpectedKey) {
@ -94,81 +95,20 @@ public class LayoutBase {
} }
// Icon ids. // Icon ids.
private static final int ICON_SHIFT = KeyboardIconsSet.getIconId("shift_key"); private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
private static final int ICON_DELETE = KeyboardIconsSet.getIconId("delete_key"); KeyboardIconsSet.NAME_DELETE_KEY);
private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId("settings_key"); private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId(
private static final int ICON_ENTER = KeyboardIconsSet.getIconId("enter_key"); KeyboardIconsSet.NAME_SETTINGS_KEY);
private static final int ICON_EMOJI = KeyboardIconsSet.getIconId("emoji_key"); private static final int ICON_ENTER = KeyboardIconsSet.getIconId(
KeyboardIconsSet.NAME_ENTER_KEY);
private static final int ICON_EMOJI = KeyboardIconsSet.getIconId(
KeyboardIconsSet.NAME_EMOJI_KEY);
// Functional keys. // Functional keys.
public static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK);
public static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT, Constants.CODE_SHIFT);
public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE); public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE);
public static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL);
public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS); public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS);
public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER); public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
public static final ExpectedKey EMOJI_KEY = key(ICON_EMOJI, Constants.CODE_EMOJI); public static final ExpectedKey EMOJI_KEY = key(ICON_EMOJI, Constants.CODE_EMOJI);
public static final ExpectedKey SPACEBAR = key(
// Punctuation more keys for phone form factor. StringUtils.newSingleCodePointString(Constants.CODE_SPACE));
public static final String[] PHONE_PUNCTUATION_MORE_KEYS = {
";", "/", "(", ")", "#", "!", ",", "?",
"&", "%", "+", "\"", "-", ":", "'", "@"
};
// Punctuation more keys for tablet form factor.
public static final String[] TABLET_PUNCTUATION_MORE_KEYS = {
";", "/", "(", ")", "#", "'", ",",
"&", "%", "+", "\"", "-", ":", "@"
};
// Helper method to create alphabet layout for phone by adding special function keys except
// shift key.
private static ExpectedKeyboardBuilder convertToPhoneAlphabetKeyboardBuilder(
final ExpectedKey[][] commonLayout) {
return new ExpectedKeyboardBuilder(commonLayout)
.addKeysOnTheRightOfRow(3, DELETE_KEY)
.setLabelsOfRow(4, ",", " ", ".")
.setMoreKeysOf(",", SETTINGS_KEY)
.setMoreKeysOf(".", PHONE_PUNCTUATION_MORE_KEYS)
.addKeysOnTheLeftOfRow(4, SYMBOLS_KEY)
.addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY));
}
// Helper method to create alphabet layout for tablet by adding special function keys except
// shift key.
private static ExpectedKeyboardBuilder convertToTabletAlphabetKeyboardBuilder(
final ExpectedKey[][] commonLayout) {
return new ExpectedKeyboardBuilder(commonLayout)
// U+00BF: "¿" INVERTED QUESTION MARK
// U+00A1: "¡" INVERTED EXCLAMATION MARK
.addKeysOnTheRightOfRow(3,
key("!", moreKey("\u00A1")), key("?", moreKey("\u00BF")))
.addKeysOnTheRightOfRow(1, DELETE_KEY)
.addKeysOnTheRightOfRow(2, ENTER_KEY)
.setLabelsOfRow(4, "/", " ", ",", ".")
.setMoreKeysOf(".", TABLET_PUNCTUATION_MORE_KEYS)
.addKeysOnTheLeftOfRow(4, SYMBOLS_KEY, SETTINGS_KEY)
.addKeysOnTheRightOfRow(4, EMOJI_KEY);
}
// Helper method to create alphabet layout by adding special function keys.
public static ExpectedKey[][] getAlphabetLayoutWithoutShiftKeys(
final ExpectedKey[][] commonLayout, final boolean isPhone) {
return isPhone ? convertToPhoneAlphabetKeyboardBuilder(commonLayout).build()
: convertToTabletAlphabetKeyboardBuilder(commonLayout).build();
}
// Helper method to create alphabet layout by adding special function keys.
public static ExpectedKey[][] getDefaultAlphabetLayout(final ExpectedKey[][] commonLayout,
final boolean isPhone) {
final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
getAlphabetLayoutWithoutShiftKeys(commonLayout, isPhone));
if (isPhone) {
builder.addKeysOnTheLeftOfRow(3, key(SHIFT_KEY, CAPSLOCK_MORE_KEY));
} else {
builder.addKeysOnTheLeftOfRow(3, key(SHIFT_KEY, CAPSLOCK_MORE_KEY))
.addKeysOnTheRightOfRow(3, key(SHIFT_KEY, CAPSLOCK_MORE_KEY));
}
return builder.build();
}
} }

View file

@ -120,6 +120,17 @@ public final class ExpectedKeyboardBuilder extends AbstractKeyboardBuilder<Expec
return this; return this;
} }
/**
* Set the row with specified keys.
* @param row the row number to set keys.
* @param keys the keys to be set at <code>row</code>.
* @return this builder.
*/
public ExpectedKeyboardBuilder setKeysOfRow(final int row, final ExpectedKey ... keys) {
setRowAt(row, keys);
return this;
}
/** /**
* Set the "more keys" of the key that has the specified label. * Set the "more keys" of the key that has the specified label.
* @param label the label of the key to set the "more keys". * @param label the label of the key to set the "more keys".

View file

@ -24,22 +24,20 @@ import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardLayoutSet; import com.android.inputmethod.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.keyboard.KeyboardLayoutSetTestsBase; import com.android.inputmethod.keyboard.KeyboardLayoutSetTestsBase;
import com.android.inputmethod.keyboard.layout.AlphabetShifted; import com.android.inputmethod.keyboard.layout.LayoutBase;
import com.android.inputmethod.keyboard.layout.Symbols; import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase;
import com.android.inputmethod.keyboard.layout.SymbolsShifted;
import com.android.inputmethod.keyboard.layout.expected.ActualKeyboardBuilder; import com.android.inputmethod.keyboard.layout.expected.ActualKeyboardBuilder;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import com.android.inputmethod.keyboard.layout.expected.LayoutBase;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale;
/** /**
* Base class for keyboard layout unit test. * Base class for keyboard layout unit test.
*/ */
abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase { abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase {
private LayoutBase mLayout;
private InputMethodSubtype mSubtype; private InputMethodSubtype mSubtype;
private String mLogTag; private String mLogTag;
private KeyboardLayoutSet mKeyboardLayoutSet; private KeyboardLayoutSet mKeyboardLayoutSet;
@ -48,7 +46,8 @@ abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase {
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
mSubtype = getSubtype(getTestLocale(), getTestKeyboardLayout()); mLayout = getLayout();
mSubtype = getSubtype(mLayout.getLocale(), mLayout.getName());
mLogTag = SubtypeLocaleUtils.getSubtypeNameForLogging(mSubtype) + "/" mLogTag = SubtypeLocaleUtils.getSubtypeNameForLogging(mSubtype) + "/"
+ (isPhone() ? "phone" : "tablet"); + (isPhone() ? "phone" : "tablet");
mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */); mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */);
@ -59,115 +58,77 @@ abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase {
// Helper method to create {@link ExpectedKey} object that has the label. // Helper method to create {@link ExpectedKey} object that has the label.
static ExpectedKey key(final String label, final ExpectedKey ... moreKeys) { static ExpectedKey key(final String label, final ExpectedKey ... moreKeys) {
return LayoutBase.key(label, moreKeys); return AbstractLayoutBase.key(label, moreKeys);
} }
// Helper method to create {@link ExpectedKey} object that has the label and the output text. // Helper method to create {@link ExpectedKey} object that has the label and the output text.
static ExpectedKey key(final String label, final String outputText, static ExpectedKey key(final String label, final String outputText,
final ExpectedKey ... moreKeys) { final ExpectedKey ... moreKeys) {
return LayoutBase.key(label, outputText, moreKeys); return AbstractLayoutBase.key(label, outputText, moreKeys);
} }
// Helper method to create {@link ExpectedKey} object that has new "more keys". // Helper method to create {@link ExpectedKey} object that has new "more keys".
static ExpectedKey key(final ExpectedKey key, final ExpectedKey ... moreKeys) { static ExpectedKey key(final ExpectedKey key, final ExpectedKey ... moreKeys) {
return LayoutBase.key(key, moreKeys); return AbstractLayoutBase.key(key, moreKeys);
} }
// Helper method to create {@link ExpectedKey} object for "more key" that has the label. // Helper method to create {@link ExpectedKey} object for "more key" that has the label.
static ExpectedKey moreKey(final String label) { static ExpectedKey moreKey(final String label) {
return LayoutBase.moreKey(label); return AbstractLayoutBase.moreKey(label);
} }
// Helper method to create {@link ExpectedKey} object for "more key" that has the label and the // Helper method to create {@link ExpectedKey} object for "more key" that has the label and the
// output text. // output text.
static ExpectedKey moreKey(final String label, final String outputText) { static ExpectedKey moreKey(final String label, final String outputText) {
return LayoutBase.moreKey(label, outputText); return AbstractLayoutBase.moreKey(label, outputText);
} }
// Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey},
// {@link ExpectedKey} array, and {@link String}. // {@link ExpectedKey} array, and {@link String}.
static ExpectedKey[] join(final Object ... keys) { static ExpectedKey[] joinKeys(final Object ... keys) {
return LayoutBase.join(keys); return AbstractLayoutBase.joinKeys(keys);
} }
// Locale for testing subtype. // Keyboard layout for testing subtype.
abstract Locale getTestLocale(); abstract LayoutBase getLayout();
// Keyboard layout name for testing subtype. ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
abstract String getTestKeyboardLayout(); return builder;
// Alphabet keyboard for testing subtype.
abstract ExpectedKey[][] getAlphabetLayout(final boolean isPhone);
// Alphabet automatic shifted keyboard for testing subtype.
ExpectedKey[][] getAlphabetAutomaticShiftedLayout(final boolean isPhone) {
return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
}
// Alphabet manual shifted keyboard for testing subtype.
ExpectedKey[][] getAlphabetManualShiftedLayout(final boolean isPhone) {
return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
}
// Alphabet shift locked keyboard for testing subtype.
ExpectedKey[][] getAlphabetShiftLockedLayout(final boolean isPhone) {
return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
}
// Alphabet shift lock shifted keyboard for testing subtype.
ExpectedKey[][] getAlphabetShiftLockShiftedLayout(final boolean isPhone) {
return AlphabetShifted.getDefaultLayout(getAlphabetLayout(isPhone), getTestLocale());
}
// Symbols keyboard for testing subtype.
ExpectedKey[][] getSymbolsLayout(final boolean isPhone) {
return Symbols.getDefaultLayout(isPhone);
}
// Symbols shifted keyboard for testing subtype.
ExpectedKey[][] getSymbolsShiftedLayout(final boolean isPhone) {
return SymbolsShifted.getDefaultLayout(isPhone);
} }
// TODO: Add phone, phone symbols, number, number password layout tests. // TODO: Add phone, phone symbols, number, number password layout tests.
public final void testAlphabet() { public final void testAlphabet() {
final int elementId = KeyboardId.ELEMENT_ALPHABET; doKeyboardTests(KeyboardId.ELEMENT_ALPHABET);
doKeyboardTests(elementId, getAlphabetLayout(isPhone()));
} }
public final void testAlphabetAutomaticShifted() { public final void testAlphabetAutomaticShifted() {
final int elementId = KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED; doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED);
doKeyboardTests(elementId, getAlphabetAutomaticShiftedLayout(isPhone()));
} }
public final void testAlphabetManualShifted() { public final void testAlphabetManualShifted() {
final int elementId = KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED; doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED);
doKeyboardTests(elementId, getAlphabetManualShiftedLayout(isPhone()));
} }
public final void testAlphabetShiftLocked() { public final void testAlphabetShiftLocked() {
final int elementId = KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED; doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED);
doKeyboardTests(elementId, getAlphabetShiftLockedLayout(isPhone()));
} }
public final void testAlphabetShiftLockShifted() { public final void testAlphabetShiftLockShifted() {
final int elementId = KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED; doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED);
doKeyboardTests(elementId, getAlphabetShiftLockShiftedLayout(isPhone()));
} }
public final void testSymbols() { public final void testSymbols() {
final int elementId = KeyboardId.ELEMENT_SYMBOLS; doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS);
doKeyboardTests(elementId, getSymbolsLayout(isPhone()));
} }
public final void testSymbolsShifted() { public final void testSymbolsShifted() {
final int elementId = KeyboardId.ELEMENT_SYMBOLS_SHIFTED; doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS_SHIFTED);
doKeyboardTests(elementId, getSymbolsShiftedLayout(isPhone()));
} }
// Comparing expected keyboard and actual keyboard. // Comparing expected keyboard and actual keyboard.
private void doKeyboardTests(final int elementId, final ExpectedKey[][] expectedKeyboard) { private void doKeyboardTests(final int elementId) {
final ExpectedKey[][] expectedKeyboard = mLayout.getLayout(isPhone(), elementId);
// Skip test if no keyboard is defined. // Skip test if no keyboard is defined.
if (expectedKeyboard == null) { if (expectedKeyboard == null) {
return; return;

View file

@ -18,8 +18,9 @@ package com.android.inputmethod.keyboard.layout.tests;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.keyboard.layout.LayoutBase;
import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer;
import com.android.inputmethod.keyboard.layout.Qwerty; import com.android.inputmethod.keyboard.layout.Qwerty;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import java.util.Locale; import java.util.Locale;
@ -28,71 +29,64 @@ import java.util.Locale;
* en_US: English (United States)/qwerty * en_US: English (United States)/qwerty
*/ */
@SmallTest @SmallTest
public final class TestsEnglishUS extends LayoutTestsBase { public class TestsEnglishUS extends LayoutTestsBase {
@Override private static final Locale LOCALE = new Locale("en", "US");
Locale getTestLocale() { private static final LayoutBase LAYOUT = new Qwerty(new EnglishCustomizer(LOCALE));
return new Locale("en", "US");
}
@Override @Override
String getTestKeyboardLayout() { LayoutBase getLayout() { return LAYOUT; }
return Qwerty.LAYOUT_NAME;
}
@Override static class EnglishCustomizer extends LayoutCustomizer {
ExpectedKey[][] getAlphabetLayout(final boolean isPhone) { public EnglishCustomizer(final Locale locale) { super(locale); }
final ExpectedKey[][] keyboard = Qwerty.getLayout(isPhone);
final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(keyboard);
setAccentedLetters(builder);
return builder.build();
}
static ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { @Override
return builder public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE return builder
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
// U+0113: "ē" LATIN SMALL LETTER E WITH MACRON // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
.setMoreKeysOf("e", "3", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0113") // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX .setMoreKeysOf("e", "3", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0113")
// U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
// U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
.setMoreKeysOf("u", "7", "\u00FB", "\u00FC", "\u00F9", "\u00FA", "\u016B") // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
// U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX .setMoreKeysOf("u", "7", "\u00FB", "\u00FC", "\u00F9", "\u00FA", "\u016B")
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
// U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
// U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
.setMoreKeysOf("i", "8", "\u00EE", "\u00EF", "\u00ED", "\u012B", "\u00EC") // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
// U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX .setMoreKeysOf("i", "8", "\u00EE", "\u00EF", "\u00ED", "\u012B", "\u00EC")
// U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
// U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
// U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
// U+0153: "œ" LATIN SMALL LIGATURE OE // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
// U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE // U+0153: "œ" LATIN SMALL LIGATURE OE
// U+014D: "ō" LATIN SMALL LETTER O WITH MACRON // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
// U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
.setMoreKeysOf("o", // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
"9", "\u00F4", "\u00F6", "\u00F2", "\u00F3", "\u0153", "\u00F8", "\u014D", .setMoreKeysOf("o",
"\u00F5") "9", "\u00F4", "\u00F6", "\u00F2", "\u00F3", "\u0153", "\u00F8",
// U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE "\u014D", "\u00F5")
// U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
// U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
// U+00E6: "æ" LATIN SMALL LETTER AE // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
// U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE // U+00E6: "æ" LATIN SMALL LETTER AE
// U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
// U+0101: "ā" LATIN SMALL LETTER A WITH MACRON // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
.setMoreKeysOf("a", // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
"\u00E0", "\u00E1", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5", .setMoreKeysOf("a",
"\u0101") "\u00E0", "\u00E1", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5",
// U+00DF: "ß" LATIN SMALL LETTER SHARP S "\u0101")
.setMoreKeysOf("s", "\u00DF") // U+00DF: "ß" LATIN SMALL LETTER SHARP S
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA .setMoreKeysOf("s", "\u00DF")
.setMoreKeysOf("c", "\u00E7") // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE .setMoreKeysOf("c", "\u00E7")
.setMoreKeysOf("n", "\u00F1"); // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
.setMoreKeysOf("n", "\u00F1");
}
} }
} }