0

I try to create a keyboard application from Android Studio (not an in-app keyboard). How to replace the text "e1" to "E"; And replacing text "e19" will replace "M"? Below are some of my file's contents.

MersonKeyboardd.java file:

public class MersonKeyboardd extends InputMethodService implements KeyboardView.OnKeyboardActionListener {

private KeyboardView kv;
private Keyboard keyboard;

private boolean isCaps = false;

@Override
public View onCreateInputView() {
    kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboardd,null);
    keyboard = new Keyboard(this,R.xml.qwerty); // Add my keypad
    kv.setKeyboard(keyboard);
    kv.setOnKeyboardActionListener(this);
    return kv;
}


@Override
public void onKey(int i, int[] ints) {
    InputConnection ic = getCurrentInputConnection();
    switch (i) {

        case Keyboard.KEYCODE_DELETE:
            ic.deleteSurroundingText(1,0);
        break;

        case Keyboard.KEYCODE_SHIFT:
            isCaps = !isCaps;
            keyboard.setShifted(isCaps);
            kv.invalidateAllKeys();
            break;

         case Keyboard.KEYCODE_DONE:
             ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_ENTER));
             break;
             default:
                 char code = (char)i;
                 if (Character.isLetter(code) && isCaps)
                     code = Character.toUpperCase(code);
                 ic.commitText(String.valueOf(code),1);

                 // this is I trying replace "e1" to "E"
                 if (String.valueOf(code) == "e1") {
                     ic.commitText("E", 1);
                 }

                 // this is I trying replace "E9" to "M"
                 if (String.valueOf(code) == "E9") {
                     ic.commitText("M", 1);
                 }

                 // this is I trying replace "e19" to "M"
                 if (String.valueOf(code) == "e19") {
                     ic.commitText("M", 1);
                 }


    }

}
}

R.xml.qwerty is the XML file that contains my settings with the <Keyboard> <Row> <Key> tags.

I do not have the <editText> tag in my XML file. The code in the above java file that I declare it as R.xml.qwerty, and this is the content of my qwerty.xml file looks like:

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="10%p"
    android:horizontalGap="5px"
    android:verticalGap="5px"
    android:keyHeight="40dp"
    >

    <Row>
        <Key android:keyLabel="1" android:keyEdgeFlags="left" android:codes="49" />
        <Key android:keyLabel="2" android:codes="50" />
        <Key android:keyLabel="3" android:codes="51" />
        <Key android:keyLabel="4" android:codes="52" />
        <Key android:keyLabel="5" android:codes="53" />
        <Key android:keyLabel="6" android:codes="54" />
        <Key android:keyLabel="7" android:codes="55" />
        <Key android:keyLabel="8" android:codes="56" />
        <Key android:keyLabel="9" android:codes="57" />
        <Key android:keyLabel="0" android:keyEdgeFlags="right" android:codes="48" />
    </Row>

    <Row>
        <Key android:keyLabel="q" android:keyEdgeFlags="left" android:codes="113" />
        <Key android:keyLabel="w" android:codes="119" />
        <Key android:keyLabel="e" android:codes="101" />
        <Key android:keyLabel="r" android:codes="114" />
        <Key android:keyLabel="t" android:codes="116" />
        <Key android:keyLabel="y" android:codes="121" />
        <Key android:keyLabel="u" android:codes="117" />
        <Key android:keyLabel="i" android:codes="105" />
        <Key android:keyLabel="o" android:codes="111" />
        <Key android:keyLabel="p" android:keyEdgeFlags="right" android:codes="112" />

    </Row>

    <Row>
        <Key android:keyLabel="a" android:keyEdgeFlags="left" android:codes="97" />
        <Key android:keyLabel="s" android:codes="115" />
        <Key android:keyLabel="d" android:codes="100" />
        <Key android:keyLabel="f" android:codes="102" />
        <Key android:keyLabel="g" android:codes="103" />
        <Key android:keyLabel="h" android:codes="104" />
        <Key android:keyLabel="j" android:codes="106" />
        <Key android:keyLabel="k" android:codes="107" />
        <Key android:keyLabel="l" android:codes="108" />
        <Key android:keyLabel="\#\@" android:keyEdgeFlags="right" android:codes="35,64" />

    </Row>

    <Row>
        <Key android:keyLabel="CAPS" android:keyEdgeFlags="left" android:codes="-1" />
        <Key android:keyLabel="z" android:codes="122" />
        <Key android:keyLabel="x" android:codes="120" />
        <Key android:keyLabel="c" android:codes="99" />
        <Key android:keyLabel="v" android:codes="118" />
        <Key android:keyLabel="b" android:codes="98" />
        <Key android:keyLabel="n" android:codes="110" />
        <Key android:keyLabel="m" android:codes="109" />
        <Key android:keyLabel="." android:codes="46" />
        <Key android:keyLabel="\?!" android:keyEdgeFlags="right" android:codes="53,33" />
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key android:keyLabel="," android:keyWidth="10%p" android:keyEdgeFlags="left" android:codes="44" />
        <Key android:keyLabel="/" android:keyWidth="10%p" android:codes="47" />
        <Key android:keyLabel="SPACE" android:keyWidth="40%p" android:isRepeatable="true" android:codes="32" />
        <Key android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true" android:codes="-5" />

        <Key android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right" android:codes="-4" />

    </Row>
</Keyboard>

Its path: AndroidStudioProjects/MersonKeyboard/app/src/main/res/xml/qwerty.xml

Thank You very much!

Christopher Rucinski
  • 4,737
  • 2
  • 27
  • 58
Merson Su
  • 115
  • 9
  • 1
    Looks like an assignment, as substituting **e1** is provisionary as **9** could follow. – Joop Eggen Dec 08 '18 at 11:55
  • @JoopEggen Yes, you were right. – Merson Su Dec 08 '18 at 14:36
  • @ChristopherRucinski Nothing. I tried trying to add it to the **public void onKey(int i, int[] ints) { ... }** inside, but could not, Android Studio log the error. – Merson Su Dec 08 '18 at 14:45
  • 1
    It appears to me that the key to this is using the `InputConnection` variable. Do you have the whole project on GitHub or somewhere I can quickly try some solutions? – Christopher Rucinski Dec 08 '18 at 16:02
  • 1
    This should help you otherwise: https://stackoverflow.com/questions/45204305/set-composing-text-on-an-edittext-from-a-custom-keyboard-in-android – Christopher Rucinski Dec 08 '18 at 16:26
  • @ChristopherRucinski Thanks to Christopher Rucinski! – Merson Su Dec 08 '18 at 17:42
  • @ChristopherRucinski You can download my project at: https://drive.google.com/file/d/1AApQbVwT4YBC3uWoWvlXWSVaVKhdKYyV – Merson Su Dec 08 '18 at 18:44
  • @ChristopherRucinski I really appreciate your help! – Merson Su Dec 08 '18 at 18:49
  • @ChristopherRucinski I've added some code that I tried that Android Studio does not write errors, but this code does not work. – Merson Su Dec 09 '18 at 01:50
  • @MersonSu What I am going to is the following: **(1) Rollback the question to its previous edit because its good etiquette here to not change the question** and your previous question was answered correctly by me. *Extra important information is great and should be added!!* **(2) Ask that you re-accept my answer** because it did answer your question. Again, this is not good etiquette here. **(3) Ask that you post a link to the new question here so that I can help solve this new issue.** Please note, most users will not be THIS helpful to you next time. I want you to be a good SO user! Cheers!! – Christopher Rucinski Dec 13 '18 at 20:36
  • Yes. Thank you. – Merson Su Dec 14 '18 at 01:23
  • @ChristopherRucinski My new question at here: https://stackoverflow.com/questions/53836722/how-to-replace-e1-to-a-e9-to-b-ie-a9-to-b-b1-to-a – Merson Su Dec 18 '18 at 16:09
  • 1
    @MersonSu There are 4 votes to close your new question. The reasons are because your question is unclear. One more vote and your question is closed! I edited your question to try to be more clear. Please learn what I did and all future questions should be as clear as possible! – Christopher Rucinski Dec 18 '18 at 19:17

2 Answers2

2

Results

When typing e1 e12 e13 e14 e15 e16 e17 e18 e19 e9, you get E E2 E3 E4 E5 E6 E7 E8 M E

Important APIs

As stated in the comments, the key to this issue is with InputConnection and its API. It's a little difficult to wrap your head around the documentation, but luckily the API is simple.

InputConnection basically links the IME with your application. It provides the feature you want which is called composing.

The methods of importance are:

  • InputConnection.commitText(CharSequence, int) - sends non-composable (non-editable) text to your application.
  • InputConnection.setComposingText(CharSequence, int) - sends composable text to your application.

    Note: with several passes of OnKeyboardActionListener.onKey(int, int[]), you can search for patterns and commitText(...) or continue to setComposingText(...)
  • InputConnection.finishComposingText() - takes all composed text, and sends it to your application as non-composable.

Code

Feel free to change names of variables and methods. I didn't spend time thinking of great names.

I added two class fields that holds Strings.

private String composing = "";
private String stillComposible = "";
  • composing - holds text that can possibly be composed into other text.
  • stillComposible - holds text that has been composed into other text but still can be composed more.

onKey(...)

Most of the changes are in the default case. I commented most of the major code paths.

@Override
public void onKey(int i, int[] ints) {

    InputConnection ic = getCurrentInputConnection();
    char code = (char) i;
    playClick(i);

    switch (i) {

        // Added special case for deleting composed text
        case Keyboard.KEYCODE_DELETE:
            if (composing.length() == 0) {
                ic.deleteSurroundingText(1, 0);
            } else {
                composing = "";
                ic.commitText("", 0);
            }

            break;

        case Keyboard.KEYCODE_SHIFT:
            isCaps = !isCaps;
            keyboard.setShifted(isCaps);
            kv.invalidateAllKeys();
            break;

        case Keyboard.KEYCODE_DONE:
            ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
            break;

        default:
            if (Character.isLetter(code) && isCaps)
                code = Character.toUpperCase(code);

            // If code point is "e" or "E" start a new composition
            if (String.valueOf(code).toLowerCase().equals("e")) {
                if (composing.length() > 0) {   // Pass through previous text if needed
                    ic.commitText(composing, composing.length());
                }
                composing = String.valueOf(code);
                ic.setComposingText(composing, composing.length());

                // Continue composing longer text if
            } else if (composing.length() > 0) {
                composing += code;


                // Check for replacement of composition
                if (!compositionReplaced(ic)) {

                    // Replacement followed by no replacement - special case
                    if (stillComposible.length() > 0) {
                        String text = stillComposible + code;
                        ic.commitText(text, text.length());

                        // No replacement case
                    } else {
                        ic.setComposingText(composing, composing.length());
                    }
                }

                // Otherwise pass the code point through
            } else {
                composing = "";
                ic.commitText(String.valueOf(code), 1);
            }

            // No pattern matches are larger than 3 characters.
            // If nothing matched, pass the code points through.
            if (composing.length() >= 3) {
                ic.finishComposingText();
                composing = "";
            }
    }
 }

Helper Method

This is where the composed text can be changed.

Feel free to put this code in the correct location in the default case if desired.

private boolean compositionReplaced(InputConnection ic) {

    boolean isReplaced = true;

    switch (composing.toLowerCase()) {

        case "e19":
            ic.commitText("M", 1);
            composing = "";
            break;

            // Can be composed more
        case "e1":
            ic.setComposingText("E", 1);
            stillComposible = "E";
            break;

        case "e9":
            ic.commitText("E", 1);
            composing = "";
            break;

        // No replacement occur
        default:
            isReplaced = false;
            break;
    }
    return isReplaced;
}

Notes

This only addresses your main question. There are still more issues that need to be fixed to be fully functional in a real app.

Christopher Rucinski
  • 4,737
  • 2
  • 27
  • 58
  • Hi, Christopher Rucinski. It works for me. This code worked well. This is the most complete and useful answer. Please leave your Paypal information, I would like to spend you some coins so that you have a cup of coffee instead of my gratitude! – Merson Su Dec 10 '18 at 05:37
  • I mean in my question is about the case that looks like this: `"e1" to "a", "e9" to "b"`, ie `"a9" to "b", "b1" to "a"`, and when you write 1 or 9 after them ( e, a, b) , they will be able to replace each other ( a will replace b, or b will replace a). Which code does that make? – Merson Su Dec 10 '18 at 18:29
  • I also feel my question post is untidy and unclear. I'm so sorry about that. Wish you a happy day! – Merson Su Dec 12 '18 at 22:19
  • 1
    @MersonSu sorry, it looks like **<[refer to original question](https://stackoverflow.com/revisions/53680694/7)>** is solved isn't it? As for **<[refer to "new" problem](https://stackoverflow.com/revisions/53680694/8)>**, that would be a **[different question](https://meta.stackexchange.com/questions/43478/exit-strategies-for-chameleon-questions "at Stack Exchange sites, “chameleon questions” are not quite welcome")**. Please post it separately by [clicking here](https://meta.stackoverflow.com/questions/ask). – Christopher Rucinski Dec 13 '18 at 20:19
  • 1
    @MersonSu What I am going to is the following: **(1) Rollback the question to its previous edit because its good etiquette here to not change the question** and your previous question was answered correctly by me. *Extra important information is great and should be added!!* **(2) Ask that you re-accept my answer** because it did answer your question. Again, this is not good etiquette here. **(3) Ask that you post a link to the new question here so that I can help solve this new issue.** Please note, most users will not be THIS helpful to you next time. I want you to be a good SO user! Cheers!! – Christopher Rucinski Dec 13 '18 at 20:34
  • A few days ago, I created a new question. When I was posting, there was a user named Mike who commented on my new question. I was about to paste the link of the new question here, but he said that there is no difference between the new question and the old question. He asked me the reason for creating a new question. I think he's talking about spam. At that time I thought I was not a spammer, so I deleted the new question and updated my old question. I think I did not think carefully. I will restore my old question and recreate the new question. – Merson Su Dec 14 '18 at 01:12
  • (^_^) I do not intend to make you sad. Will not you bother me? – Merson Su Dec 14 '18 at 01:13
  • 1
    @MersonSu That's unfortunately how things happen on this site sometimes. How about when you create a new question, make it different from your last edit, and only include the most important code. Link back to this question, and explain what changes you made to my code. This site wants **you to show us that you tried to fix the problem**. To get a quick answer, you will need to explain yourself more. – Christopher Rucinski Dec 14 '18 at 06:22
  • Yes. Thank you very much, Christopher. Maybe I need to take a tour of your tutorial, which is very useful for beginners like me. – Merson Su Dec 15 '18 at 09:51
  • Again, thank you for your efforts to help me, as well as the usefulness of your tutorial. Thanks! – Merson Su Dec 15 '18 at 09:52
0

I think what you want is to edit the editText field you have on the fly, for example.

EditText et;
//.......
et.addTextChangedListener(new TextWatcher() {
   //.....
   @Override
   public void afterTextChanged(Editable editable) {

    String text = editable.toString();                
    Pattern pattern = Pattern.compile("e19");
    Matcher matcher = pattern.matcher(text);
    String replaceAll = matcher.replaceAll("M");

    pattern = Pattern.compile("e1");
    matcher = pattern.matcher(replaceAll);
    replaceAll = matcher.replaceAll("E");
    et.setText(replaceAll);

   }
 )};