I am designing a custom keyboard for Amharic language in Android, but the following is applicable to many other non-English languages.
我正在Android中为Amharic语言设计一个自定义键盘,但以下适用于其他许多非英语语言。
Two or more combination of keys translate to one character. So, if the user types 'S', the keyboard will output 'ሰ'... and if they follow it with the letter 'A', the 'ሰ' is replaced with 'ሳ'.
两个或多个键的组合转换为一个字符。因此,如果用户输入“年代”,键盘输出“ሰ”……如果他们遵循它的字母“A”,“ሰ”是“ሳ”所取代。
I managed to get a solution, as below, working by looking at the character before the cursor and checking it against a Map. However, I was wondering whether there is a simpler and cleaner solution possible.
我设法得到了一个解决方案,如下所示,通过查看光标前的字符并对照映射检查它。然而,我想知道是否可能有一种更简单、更干净的解决方案。
public void onKey(int primaryCode, int[] keyCodes) {
InputConnection ic = getCurrentInputConnection();
HashMap<String, Integer> en_to_am = new HashMap<String, Integer>();
CharSequence pChar = ic.getTextBeforeCursor(1, 0);
int outKey = 0;
//build a hashmap of 'existing character' + 'new key code' = 'output key code'
en_to_am.put("83", 4656);
en_to_am.put("ሰ65", 4659);
try {
//see if config exists in hashmap for 'existing character' + 'new key code'
if (en_to_am.get(pChar.toString() + primaryCode) != null) {
outKey = en_to_am.get(pChar.toString() + primaryCode);
ic.deleteSurroundingText(1, 0);
} else {
//else just translate latin to amharic (ASCII 83 = ሰ)
if (en_to_am.get("" + primaryCode) != null) {
outKey = en_to_am.get("" + primaryCode);
} else {
//if no translation exists, just output the latin code
outKey = primaryCode;
}
}
} catch (Exception e) {
outKey = primaryCode;
}
char code = (char) outKey;
ic.commitText(String.valueOf(code), 1);
}
2 个解决方案
#1
3
Here are some changes I would suggest to make it more efficient
这里有一些我建议的改变,让它更有效率。
- Use your own variable to track the editing status. In the code below, I used mComposing, clear it onStartInput, and update it when new input is made.
- 使用您自己的变量来跟踪编辑状态。在下面的代码中,我使用mcomposition,清除onStartInput,并在进行新的输入时更新它。
- Reduce use of String. I have replaced Strings using a custom class and restructured your conversion map.
- 减少使用的字符串。我已经使用自定义类替换了字符串,并重新构造了您的转换映射。
- Use composing text to give better hint to user on what you are doing.
- 使用组合文本给用户更好的提示你正在做什么。
Here is the modified code
这是修改后的代码
private StringBuilder mComposing = new StringBuilder();
private static HashMap<Integer, CodeInfo> mCodeMap = new HashMap<Integer, CodeInfo>();
private static class CodeInfo {
final Character mCode;
final Map<Character, Character> mCombinedCharMap;
CodeInfo(Character code, Map<Character, Character> combinedCharMap) {
mCode = code;
mCombinedCharMap = combinedCharMap;
}
}
static {
//reminder, do not input combinedCharMap as null
mCodeMap.put(83, new CodeInfo(Character.valueOf((char)4656), new HashMap<Character, Character>());
HashMap<Character, Character> combinedCharMap = new HashMap<Character, Character>();
combinedCharMap.put(Character.valueOf('ሰ'), Character.valueOf((char)4659))
mCodeMap.put(65, new CodeInfo(null, combinedCharMap);
}
@Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
super.onStartInput(attribute, restarting);
mComposing.setLength(0);
//other codes you already have
}
public void onKey(int primaryCode, int[] keyCodes) {
InputConnection ic = getCurrentInputConnection();
CodeInfo codeInfo = mCodeMap.get(primaryCode);
Character output = null;
if (codeInfo != null) {
if (mComposing.length() > 0) {
Character combinedOutput = codeInfo.mCombinedCharMap.get(mComposing.charAt(0));
if (combinedOutput != null) {
//the length is mComposing is expected to be 1 here
mComposing.setCharAt(0, combinedOutput);
ic.finishComposingText();
ic.setComposingText(mComposing, 1);
return;
}
}
output = codeInfo.mCode;
}
if (mComposing.length() > 0) {
mComposing.setLength(0);
ic.finishComposingText();
}
mComposing.append(output==null?(char)primaryCode:(char)output);
ic.setComposingText(mComposing, 1);
}
#2
1
Initialize en_to_am in static code
在静态代码中初始化en_to_am
static private Map<String, Integer> en_to_am = new HashMap<String,Integer>;
static {
//build a hashmap of 'existing character' + 'new key code' = 'output key code'
en_to_am.put("83", 4656);
en_to_am.put("ሰ65", 4659);
}
Skip the try.
跳过试一试。
public void onKey(int primaryCode) {
InputConnection ic = getCurrentInputConnection();
CharSequence pChar = ic.getTextBeforeCursor(1, 0);
Integer pairInt = en_to_am.get(pChar.toString() + primaryCode);
Integer singleInt = en_to_am.get(primaryCode.toString());
int outKey = primaryCode;
if (pairInt != null) {
try {
ic.deleteSurroundingText(1, 0);
outkey = pairInt;
}
}
else if (singleInt != null) {
outkey = singleInt;
}
ic.commitText((char) outkey).toString()), 1);
}
#1
3
Here are some changes I would suggest to make it more efficient
这里有一些我建议的改变,让它更有效率。
- Use your own variable to track the editing status. In the code below, I used mComposing, clear it onStartInput, and update it when new input is made.
- 使用您自己的变量来跟踪编辑状态。在下面的代码中,我使用mcomposition,清除onStartInput,并在进行新的输入时更新它。
- Reduce use of String. I have replaced Strings using a custom class and restructured your conversion map.
- 减少使用的字符串。我已经使用自定义类替换了字符串,并重新构造了您的转换映射。
- Use composing text to give better hint to user on what you are doing.
- 使用组合文本给用户更好的提示你正在做什么。
Here is the modified code
这是修改后的代码
private StringBuilder mComposing = new StringBuilder();
private static HashMap<Integer, CodeInfo> mCodeMap = new HashMap<Integer, CodeInfo>();
private static class CodeInfo {
final Character mCode;
final Map<Character, Character> mCombinedCharMap;
CodeInfo(Character code, Map<Character, Character> combinedCharMap) {
mCode = code;
mCombinedCharMap = combinedCharMap;
}
}
static {
//reminder, do not input combinedCharMap as null
mCodeMap.put(83, new CodeInfo(Character.valueOf((char)4656), new HashMap<Character, Character>());
HashMap<Character, Character> combinedCharMap = new HashMap<Character, Character>();
combinedCharMap.put(Character.valueOf('ሰ'), Character.valueOf((char)4659))
mCodeMap.put(65, new CodeInfo(null, combinedCharMap);
}
@Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
super.onStartInput(attribute, restarting);
mComposing.setLength(0);
//other codes you already have
}
public void onKey(int primaryCode, int[] keyCodes) {
InputConnection ic = getCurrentInputConnection();
CodeInfo codeInfo = mCodeMap.get(primaryCode);
Character output = null;
if (codeInfo != null) {
if (mComposing.length() > 0) {
Character combinedOutput = codeInfo.mCombinedCharMap.get(mComposing.charAt(0));
if (combinedOutput != null) {
//the length is mComposing is expected to be 1 here
mComposing.setCharAt(0, combinedOutput);
ic.finishComposingText();
ic.setComposingText(mComposing, 1);
return;
}
}
output = codeInfo.mCode;
}
if (mComposing.length() > 0) {
mComposing.setLength(0);
ic.finishComposingText();
}
mComposing.append(output==null?(char)primaryCode:(char)output);
ic.setComposingText(mComposing, 1);
}
#2
1
Initialize en_to_am in static code
在静态代码中初始化en_to_am
static private Map<String, Integer> en_to_am = new HashMap<String,Integer>;
static {
//build a hashmap of 'existing character' + 'new key code' = 'output key code'
en_to_am.put("83", 4656);
en_to_am.put("ሰ65", 4659);
}
Skip the try.
跳过试一试。
public void onKey(int primaryCode) {
InputConnection ic = getCurrentInputConnection();
CharSequence pChar = ic.getTextBeforeCursor(1, 0);
Integer pairInt = en_to_am.get(pChar.toString() + primaryCode);
Integer singleInt = en_to_am.get(primaryCode.toString());
int outKey = primaryCode;
if (pairInt != null) {
try {
ic.deleteSurroundingText(1, 0);
outkey = pairInt;
}
}
else if (singleInt != null) {
outkey = singleInt;
}
ic.commitText((char) outkey).toString()), 1);
}