Вывод одного символа на два ключа в Android-клавиатуре

Я разрабатываю пользовательскую клавиатуру для амхарского языка в Android, но следующее применимо ко многим другим неанглийским языкам.

Две или более комбинации клавиш переводят на один символ. Итак, если пользователь набирает "S", клавиатура выведет "ሰ"... и если они последуют за ней буквой "A", "ሰ" заменяется на "ሳ".

Мне удалось найти решение, как показано ниже, работая, просматривая символ перед курсором и проверяя его на карте. Тем не менее, мне было интересно, возможно ли более простое и чистое решение.

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

Вот некоторые изменения, которые я бы предложил сделать более эффективными

  • Используйте собственную переменную для отслеживания статуса редактирования. В приведенном ниже коде я использовал mComposing, очистил его onStartInput и обновил его при вводе нового ввода.
  • Уменьшить использование String. Я заменил строки с использованием пользовательского класса и изменил карту преобразования.
  • Используйте композиционный текст, чтобы дать вам лучший намек на то, что вы делаете.

Вот модифицированный код

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

Инициализировать 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);
}

Пропустите попытку.

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