Output one character per two keys in Android Keyboard

扶醉桌前 提交于 2019-12-10 12:42:14

问题


I am designing a custom keyboard for Amharic language in Android, but the following is applicable to many other non-English languages.

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 'ሳ'.

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);
}

回答1:


Here are some changes I would suggest to make it more efficient

  1. 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.
  2. Reduce use of String. I have replaced Strings using a custom class and restructured your conversion map.
  3. 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:


Initialize en_to_am in static code

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);
}


来源:https://stackoverflow.com/questions/32330858/output-one-character-per-two-keys-in-android-keyboard

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!