Set composing text on an EditText from a custom keyboard in Android

2.2k Views Asked by At

Explanation of what I am trying to do

I'm making a custom in-app keyboard that works on the same principle of this example. However, in my keyboard I'm using popup windows to display extra letter forms. In traditional Mongolian letters have different forms depending on if they are located at the beginning, middle, or end of a word. Usually these can be determined from the context, but sometimes a user needs to choose an alternate form explicitly from the popup key candidates.

Lets say that a user starts typing a word (where - represent letters):

--- 

Then they chose a from the popup (I'm only using a to represent the concept of choosing a special Mongolian glyph form). The Unicode for this letter will be rendered as follows if they continue typing:

---a--

However, the Unicode is rendered as

---A

at the end of words. (a and A have the same code in Unicode.) So the user is confused why they chose a from the popup key but it gets rendered as A in the editor. If they would just keep typing, though, it will be fine since it gets rendered as a in middle of words.

What I want to do it set some sort of temporary span on the a of ---a so that it doesn't get rendered as ---A before they type the next letter. But if they add a space or move the cursor to a different location, then it will revert back to the default ---A form for final letters. (That is, the temporary span will be cancelled.)

Real example

If the abstract a and A are too confusing, here is a real example. The user wants to type a Mongolian UE form (Unicode \u1826\u180c) in this word

enter image description here

But since \u1826\u180c gets rendered like this at the end of words

enter image description here

the user is confused until they continue typing. I want the span to make it look like this

enter image description here

which can be temporarily rendered with \u1826\u180c\u200d.

Documentation

The documentation says

If your IME does text prediction or requires multiple steps to compose a glyph or word, you can show the progress in the text field until the user commits the word, and then you can replace the partial composition with the completed text.

And it gives this example and image:

InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
ic.setComposingText("Composin", 1);
ic.commitText("Composing ", 1);

enter image description here

Problem

I was going to describe why it wasn't working in this section, but in the process of setting up my question here, I discovered that it actually works. So I will add my answer below as an example for other people are who doing something similar.

1

There are 1 best solutions below

0
On BEST ANSWER

The following code sets a temporary composing span when the string in question is returned by the popup window

if (selectedItem.equals("a")) {
    inputConnection.setComposingText("a", 1);
}

where selectedItem is the string chosen by the user from the key popup window candidates.

enter image description here

Note that the a has an underline indicating that it is a composing span. (This is a contrived example from the question where a would be rendered as A if the text were committed immediately.)

This also works for the real example in the question

if (selectedItem.equals("\u1826\u180c")) {
    inputConnection.setComposingText("\u1826\u180c\u200d", 1);
}

enter image description here

Committing the composing span

When it is confirmed that the user wants to keep the composing span (ie, they keep typing more letters in the word), it can be committed with

inputConnection.commitText("\u1826\u180c", 1);

Abandoning the composing span

If the user clicks somewhere else, the composing span is not cancelled. But this is a different question.

Your keyboard can override onUpdateSelection to listen for cursor changes there. Then call

inputConnection.finishComposingText();

to keep whatever text was in the composing region. Or

ic.commitText("", 1);

to get rid of it. See this answer for more.