Permalink
Browse files

keyboard: multipress for alternate characters

Change-Id: I50534225c21594c34d2e8340d1e372d5d383187d
  • Loading branch information...
nadlabak committed Nov 8, 2011
1 parent d394cde commit 06e8f2e21ad9f2252cd3d96017c8160bb824d31d
Showing with 307 additions and 11 deletions.
  1. +307 −11 core/java/android/text/method/QwertyKeyListener.java
@@ -16,19 +16,33 @@
package android.text.method;
import android.os.SystemProperties;
import android.text.*;
import android.text.method.TextKeyListener.Capitalize;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import java.lang.Character;
import java.lang.System;
import java.util.Locale;
/**
* This is the standard key listener for alphabetic input on qwerty
* keyboards. You should generally not need to instantiate this yourself;
* TextKeyListener will do it for you.
*/
public class QwertyKeyListener extends BaseKeyListener {
private static int mLastKey = -1;
private static int mCharToReplace = -1;
private static int mRepeatCount = 0;
private static boolean mAlreadyReplaced = false;
private static long mLastPressTime = 0;
private static long multiPressTimeout = 500;
private static String mLang;
private static QwertyKeyListener[] sInstance =
new QwertyKeyListener[Capitalize.values().length * 2];
@@ -49,8 +63,222 @@ public static QwertyKeyListener getInstance(boolean autotext,
sInstance[off] = new QwertyKeyListener(cap, autotext);
}
mLang = Locale.getDefault().getLanguage();
updateMPSets();
return sInstance[off];
}
private static SparseArray<String> MP_SETS = new SparseArray<String>();
private static void updateMPSets() {
MP_SETS.clear();
// for Russian charset
MP_SETS.put('\u0439', "\u0446");
MP_SETS.put('\u0419', "\u0426");
MP_SETS.put('\u0444', "\u044b");
MP_SETS.put('\u0424', "\u042b");
MP_SETS.put('\u044f', "\u0447");
MP_SETS.put('\u042f', "\u0427");
MP_SETS.put('\u0445', "\u044a");
MP_SETS.put('\u0425', "\u042a");
MP_SETS.put('\u0437', "\u003f");
MP_SETS.put('\u0417', "\u003f");
MP_SETS.put('\u044e', "\u002c");
MP_SETS.put('\u042e', "\u002c");
if (mLang.equals("cs")) {
MP_SETS.put('A', "\u00C1");
MP_SETS.put('C', "\u010C");
MP_SETS.put('D', "\u010E");
MP_SETS.put('E', "\u00C9\u011A");
MP_SETS.put('I', "\u00CD");
MP_SETS.put('N', "\u0147");
MP_SETS.put('O', "\u00D3");
MP_SETS.put('R', "\u0158");
MP_SETS.put('S', "\u0160");
MP_SETS.put('T', "\u0164");
MP_SETS.put('U', "\u016E\u00DA");
MP_SETS.put('Y', "\u00DD");
MP_SETS.put('Z', "\u017D");
MP_SETS.put('a', "\u00E1");
MP_SETS.put('c', "\u010D");
MP_SETS.put('d', "\u010F");
MP_SETS.put('e', "\u00E9\u011B");
MP_SETS.put('i', "\u00ED");
MP_SETS.put('n', "\u0148");
MP_SETS.put('o', "\u00F3");
MP_SETS.put('r', "\u0159");
MP_SETS.put('s', "\u0161");
MP_SETS.put('t', "\u0165");
MP_SETS.put('u', "\u016F\u00FA");
MP_SETS.put('y', "\u00FD");
MP_SETS.put('z', "\u017E");
} else if (mLang.equals("da")) {
MP_SETS.put('A', "\u00C5\u00C6");
MP_SETS.put('E', "\u00C9");
MP_SETS.put('O', "\u00D8");
MP_SETS.put('a', "\u00E5\u00E6");
MP_SETS.put('e', "\u00E9");
MP_SETS.put('o', "\u00F8");
} else if (mLang.equals("de")) {
MP_SETS.put('A', "\u00C4");
MP_SETS.put('O', "\u00D6");
MP_SETS.put('U', "\u00DC");
MP_SETS.put('a', "\u00E4");
MP_SETS.put('o', "\u00F6");
MP_SETS.put('s', "\u00DF");
MP_SETS.put('u', "\u00FC");
} else if (mLang.equals("es")) {
MP_SETS.put('A', "\u00C1");
MP_SETS.put('E', "\u00C9");
MP_SETS.put('I', "\u00CD");
MP_SETS.put('N', "\u00D1");
MP_SETS.put('O', "\u00D3");
MP_SETS.put('U', "\u00DA\u00DC");
MP_SETS.put('a', "\u00E1");
MP_SETS.put('e', "\u00E9");
MP_SETS.put('i', "\u00ED");
MP_SETS.put('n', "\u00F1");
MP_SETS.put('o', "\u00F3");
MP_SETS.put('u', "\u00FA\u00FC");
MP_SETS.put('?', "\u00bf");
MP_SETS.put('!', "\u00a1");
} else if (mLang.equals("fi")) {
MP_SETS.put('A', "\u00C4\u00C5");
MP_SETS.put('O', "\u00D6");
MP_SETS.put('a', "\u00E4\u00E5");
MP_SETS.put('o', "\u00F6");
} else if (mLang.equals("fr")) {
MP_SETS.put('A', "\u00C0\u00C2\u00C6");
MP_SETS.put('C', "\u00C7");
MP_SETS.put('E', "\u00C9\u00C8\u00CA\u00CB");
MP_SETS.put('I', "\u00CF\u00CE");
MP_SETS.put('O', "\u00D4\u0152");
MP_SETS.put('U', "\u00D9\u00DB");
MP_SETS.put('Y', "\u0178");
MP_SETS.put('a', "\u00E0\u00E2\u00E6");
MP_SETS.put('c', "\u00E7");
MP_SETS.put('e', "\u00E9\u00E8\u00EA\u00EB");
MP_SETS.put('i', "\u00EF\u00EE");
MP_SETS.put('o', "\u00F4\u0153");
MP_SETS.put('u', "\u00F9\u00FB");
MP_SETS.put('y', "\u00FF");
} else if (mLang.equals("hu")) {
MP_SETS.put('A', "\u00C1");
MP_SETS.put('E', "\u00C9");
MP_SETS.put('I', "\u00CD");
MP_SETS.put('O', "\u00D6\u00D3\u0150");
MP_SETS.put('U', "\u00DC\u00DA\u0170");
MP_SETS.put('a', "\u00E1");
MP_SETS.put('e', "\u00E9");
MP_SETS.put('i', "\u00ED");
MP_SETS.put('o', "\u00F6\u00F3\u0151");
MP_SETS.put('u', "\u00FC\u00FA\u0171");
} else if (mLang.equals("it")) {
MP_SETS.put('A', "\u00C0");
MP_SETS.put('E', "\u00C8\u00C9");
MP_SETS.put('I', "\u00CC");
MP_SETS.put('O', "\u00D2\u00D3");
MP_SETS.put('U', "\u00D9");
MP_SETS.put('a', "\u00E0");
MP_SETS.put('e', "\u00E8\u00E9");
MP_SETS.put('i', "\u00EC");
MP_SETS.put('o', "\u00F2\u00F3");
MP_SETS.put('u', "\u00F9");
} else if (mLang.equals("nl")) {
MP_SETS.put('E', "\u00C9\u00CB");
MP_SETS.put('I', "\u00CF");
MP_SETS.put('O', "\u00D3\u00D6");
MP_SETS.put('U', "\u00DC");
MP_SETS.put('e', "\u00E9\u00EB");
MP_SETS.put('i', "\u00EF");
MP_SETS.put('o', "\u00F3\u00F6");
MP_SETS.put('u', "\u00FC");
} else if (mLang.equals("no")) {
MP_SETS.put('A', "\u00C5\u00C6\u00C2");
MP_SETS.put('E', "\u00C9\u00C8\u00CA");
MP_SETS.put('O', "\u00D8\u00D3\u00D2\u00D4");
MP_SETS.put('a', "\u00E5\u00E6\u00E2");
MP_SETS.put('e', "\u00E9\u00E8\u00EA\u00EB");
MP_SETS.put('o', "\u00F8\u00F3\u00F2\u00F4");
} else if (mLang.equals("pl")) {
MP_SETS.put('A', "\u0104");
MP_SETS.put('C', "\u0106");
MP_SETS.put('E', "\u0118");
MP_SETS.put('L', "\u0141");
MP_SETS.put('N', "\u0143");
MP_SETS.put('O', "\u00D3");
MP_SETS.put('S', "\u015A");
MP_SETS.put('Z', "\u0179\u017B");
MP_SETS.put('a', "\u0105");
MP_SETS.put('c', "\u0107");
MP_SETS.put('e', "\u0119");
MP_SETS.put('l', "\u0142");
MP_SETS.put('n', "\u0144");
MP_SETS.put('o', "\u00F3");
MP_SETS.put('s', "\u015B");
MP_SETS.put('z', "\u017A\u017C");
} else if (mLang.equals("pt")) {
MP_SETS.put('A', "\u00C3\u00C1\u00C2\u00C0");
MP_SETS.put('C', "\u00C7");
MP_SETS.put('E', "\u00C9\u00CA");
MP_SETS.put('I', "\u00CD");
MP_SETS.put('O', "\u00D5\u00D3\u00D4");
MP_SETS.put('U', "\u00DA\u00DC");
MP_SETS.put('a', "\u00E3\u00E1\u00E2\u00E0");
MP_SETS.put('c', "\u00E7");
MP_SETS.put('e', "\u00E9\u00EA");
MP_SETS.put('i', "\u00ED");
MP_SETS.put('o', "\u00F5\u00F3\u00F4");
MP_SETS.put('u', "\u00FA\u00FC");
} else if (mLang.equals("ro")) {
MP_SETS.put('A', "\u0102\u00C2");
MP_SETS.put('I', "\u00CE");
MP_SETS.put('S', "\u0218");
MP_SETS.put('T', "\u0162");
MP_SETS.put('a', "\u0103\u00E2");
MP_SETS.put('i', "\u00EE");
MP_SETS.put('s', "\u0219");
MP_SETS.put('t', "\u0163");
} else if (mLang.equals("sk")) {
MP_SETS.put('A', "\u00C1\u00C4");
MP_SETS.put('C', "\u010C");
MP_SETS.put('D', "\u010E");
MP_SETS.put('E', "\u00C9");
MP_SETS.put('I', "\u00CD");
MP_SETS.put('L', "\u013D\u0139");
MP_SETS.put('N', "\u0147");
MP_SETS.put('O', "\u00D3");
MP_SETS.put('R', "\u0154");
MP_SETS.put('S', "\u0160");
MP_SETS.put('T', "\u0164");
MP_SETS.put('U', "\u00DA");
MP_SETS.put('Y', "\u00DD");
MP_SETS.put('Z', "\u017D");
MP_SETS.put('a', "\u00E1\u00E4");
MP_SETS.put('c', "\u010D");
MP_SETS.put('d', "\u010F");
MP_SETS.put('e', "\u00E9");
MP_SETS.put('i', "\u00ED");
MP_SETS.put('l', "\u013E\u013A");
MP_SETS.put('n', "\u0148");
MP_SETS.put('o', "\u00F3");
MP_SETS.put('r', "\u0155");
MP_SETS.put('s', "\u0161");
MP_SETS.put('t', "\u0165");
MP_SETS.put('u', "\u00FA");
MP_SETS.put('y', "\u00FD");
MP_SETS.put('z', "\u017E");
} else if (mLang.equals("sv")) {
MP_SETS.put('A', "\u00C4\u00C5");
MP_SETS.put('E', "\u00C9");
MP_SETS.put('O', "\u00D6");
MP_SETS.put('a', "\u00E4\u00E5");
MP_SETS.put('e', "\u00E9");
MP_SETS.put('o', "\u00F6");
}
}
public int getInputType() {
return makeTextContentType(mAutoCap, mAutoText);
@@ -84,14 +312,57 @@ public boolean onKeyDown(View view, Editable content,
// QWERTY keyboard normal case
int i = event.getUnicodeChar(getMetaState(content));
int k = event.getKeyCode();
multiPressTimeout = SystemProperties.getInt("persist.sys.keypad_multipress_t", 500);
String lang = Locale.getDefault().getLanguage();
if (!lang.equals(mLang)) {
mLang = lang;
updateMPSets();
}
int count = event.getRepeatCount();
if (count == 0 && i != 0 && !KeyEvent.isModifierKey(k)) {
long currTime = System.currentTimeMillis();
if (k == mLastKey && multiPressTimeout >= currTime - mLastPressTime && selStart > 0) {
mRepeatCount++;
if (!mAlreadyReplaced) {
mCharToReplace = content.charAt(selStart - 1);
}
String set = MP_SETS.get(mCharToReplace);
if (set != null) {
if (mRepeatCount > set.length()) {
mRepeatCount = 0;
content.replace(selEnd - 1, selEnd,
new String(Character.toChars(mCharToReplace)));
} else {
content.replace(selEnd - 1, selEnd, String.valueOf(set.charAt(mRepeatCount-1)));
}
mLastPressTime = currTime;
mLastKey = k;
mAlreadyReplaced = true;
adjustMetaAfterKeypress(content);
return true;
}
} else {
mRepeatCount = 0;
}
mLastPressTime = currTime;
mLastKey = k;
mAlreadyReplaced = false;
mCharToReplace = i;
}
if (count > 0 && selStart == selEnd && selStart > 0) {
char c = content.charAt(selStart - 1);
if (c == i || c == Character.toUpperCase(i) && view != null) {
String set = PICKER_SETS.get(i);
if (count > 1 && set != null &&
(c == set.charAt(0) || c == Character.toUpperCase(set.charAt(0)))) {
adjustMetaAfterKeypress(content);
return true;
} else if (view != null && (c == i || c == Character.toUpperCase(i))) {
if (showCharacterPicker(view, content, c, false, count)) {
resetMetaState(content);
adjustMetaAfterKeypress(content);
return true;
}
}
@@ -412,13 +683,13 @@ public static void markAsReplaced(Spannable content, int start, int end,
PICKER_SETS.put('D', "\u010E");
PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB\u0118\u011A\u0112");
PICKER_SETS.put('G', "\u011E");
PICKER_SETS.put('L', "\u0141");
PICKER_SETS.put('L', "\u0141\u013d\u0139");
PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A\u0130");
PICKER_SETS.put('N', "\u00D1\u0143\u0147");
PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6\u014C");
PICKER_SETS.put('R', "\u0158");
PICKER_SETS.put('S', "\u015A\u0160\u015E");
PICKER_SETS.put('T', "\u0164");
PICKER_SETS.put('S', "\u015A\u0160\u015E\u0218");
PICKER_SETS.put('T', "\u0164\u0162");
PICKER_SETS.put('U', "\u00D9\u00DA\u00DB\u00DC\u016E\u016A");
PICKER_SETS.put('Y', "\u00DD\u0178");
PICKER_SETS.put('Z', "\u0179\u017B\u017D");
@@ -428,12 +699,12 @@ public static void markAsReplaced(Spannable content, int start, int end,
PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB\u0119\u011B\u0113");
PICKER_SETS.put('g', "\u011F");
PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B\u0131");
PICKER_SETS.put('l', "\u0142");
PICKER_SETS.put('l', "\u0142\u013E\u013A");
PICKER_SETS.put('n', "\u00F1\u0144\u0148");
PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6\u014D");
PICKER_SETS.put('r', "\u0159");
PICKER_SETS.put('s', "\u00A7\u00DF\u015B\u0161\u015F");
PICKER_SETS.put('t', "\u0165");
PICKER_SETS.put('r', "\u0159\u0155");
PICKER_SETS.put('s', "\u00A7\u00DF\u015B\u0161\u015F\u0219");
PICKER_SETS.put('t', "\u0165\u0163");
PICKER_SETS.put('u', "\u00F9\u00FA\u00FB\u00FC\u016F\u016B");
PICKER_SETS.put('y', "\u00FD\u00FF");
PICKER_SETS.put('z', "\u017A\u017C\u017E");
@@ -467,6 +738,22 @@ public static void markAsReplaced(Spannable content, int start, int end,
PICKER_SETS.put('=', "\u2260\u2248\u221e");
PICKER_SETS.put('<', "\u2264\u00ab\u2039");
PICKER_SETS.put('>', "\u2265\u00bb\u203a");
// Russian
PICKER_SETS.put('\u0439', "\u0446");
PICKER_SETS.put('\u0419', "\u0426");
PICKER_SETS.put('\u0444', "\u044b");
PICKER_SETS.put('\u0424', "\u042b");
PICKER_SETS.put('\u044f', "\u0447");
PICKER_SETS.put('\u042f', "\u0427");
PICKER_SETS.put('\u0445', "\u044a");
PICKER_SETS.put('\u0425', "\u042a");
PICKER_SETS.put('\u0437', "\u003f");
PICKER_SETS.put('\u0417', "\u003f");
PICKER_SETS.put('\u044e', "\u002c");
PICKER_SETS.put('\u042e', "\u002c");
};
private boolean showCharacterPicker(View view, Editable content, char c,
@@ -477,8 +764,17 @@ private boolean showCharacterPicker(View view, Editable content, char c,
}
if (count == 1) {
new CharacterPickerDialog(view.getContext(),
if (set.length() == 1) {
int selEnd = Selection.getSelectionEnd(content);
if (insert || selEnd == 0) {
content.insert(selEnd, set);
} else {
content.replace(selEnd - 1, selEnd, set);
}
} else {
new CharacterPickerDialog(view.getContext(),
view, content, set, insert).show();
}
}
return true;

0 comments on commit 06e8f2e

Please sign in to comment.