Proper use of compositionstart and compositionupdate events for Android IMEs

Nearly all Android on-screen keyboards use the Android IME APIs for
entering text:
https://developer.android.com/reference/android/view/
inputmethod/InputConnection.html

For example, with Gboard, when you start typing a word, it will open a
composition, update the composition for each letter typed, and then end the
composition when you hit the space bar to end the word. If you tap on
another word, Gboard will set that word as the active composition, even
before you start actually typing. This uses the
InputConnection#setComposingRegion()
method to move the composition range to an existing piece of text:

*https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingRegion(int,%20int)
<https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingRegion(int,%20int)>*


In Chrome 64 and earlier, we never fired compositionstart or
compositionupdate events in response to setComposingRegion(). However, we
_would_ actually move or create the composition region, and fire
compositionend when that region was closed out. I landed a change for
Chrome 65 that will fix this, so setComposingRegion() now fires
compositionstart if no composition range is open, and compositionupdate
regardless of whether or not one is already open.

The UI Events spec says that for compositionstart:

https://www.w3.org/TR/uievents/#event-type-compositionstart
> Some implementations MAY populate the data attribute of the
compositionstart event with the text currently selected in the document
(for editing and replacement). Otherwise, the value of the data attribute
MUST be the empty string.

On Android, selection and composition are usually two different ranges.
Tapping on a new word will cause Gboard to change the composition range to
contain that word, but the selection will just be a caret selection
wherever you tapped. So my Chrome change always sends the empty string for
this event. However, I wanted web developers to actually know what text is
in the composition at this point, so I'm also firing a compositionupdate
immediately afterward.

Some developers from Basecamp (which develops at least two rich text editor
web apps: Trix and Draft.js) were testing a beta of Chrome 65 and
discovered that this change breaks their apps:
https://bugs.chromium.org/p/chromium/issues/detail?id=812674

They feel that it's now difficult to tell when a composition is actually
inserting or replacing text versus when a keyboard is just moving the
composition. It seems that they were previously making use of the fact that
Chrome was not sending the compositionstart event for the latter case. I
think there's some operation they want to do with the new text after a
composition is closed. I feel like there should be a better way to do this
(e.g. using the beforeinput or input events in conjunction with
compositionend?). So I think the change we're making brings Chrome into
better alignment with the spec, but I'm interested in getting feedback,
especially from developers of rich text editing applications, as to whether
the spec could be changed somehow to make it more useful. E.g., should we
be able to send the initial composition text in the data field of the
compositionstart event, even if it's not selected?


I also have a question about when fake key events with the 229 key code
should be sent for composition updates. The spec says:

https://www.w3.org/TR/uievents/#events-composition-key-events
> During the composition session, keydown and keyup events MUST still be
sent, and these events MUST have the isComposing attribute set to true.

The language here is unclear to me and other Chrome developers about what
should be done if the composition was changed in response to something
other than a virtual or physical key press event.

An example in a prior section shows a handwriting recognition IME
apparently not sending keydown/keyup events (or are they just omitted from
the example?):
https://www.w3.org/TR/uievents/#events-composition-handwriting


Right now, my code isn't sending key press events when a user taps on a
word and Gboard moves the composition to a new word. This seems like the
correct behavior (since there's no actual key being pressed and no text is
actually being changed). However, I think the spec is generally unclear as
to handle this case. Another issue in my opinion is that the spec for
compositionupdate says:

https://www.w3.org/TR/uievents/#event-type-compositionupdate
> A user agent SHOULD dispatch this event during a composition session when
a text composition system updates its active text passage with a new
character, which is reflected in the string in data.

However, it doesn't really say what to do if an IME is moving the
composition to a new piece of text, or updating the composition by more
than one character (both of these cases are extremely common).


In summary:

- Are the existing APIs sufficient for web developers to interpret when
Gboard is editing text vs. just moving the composition range?

-  Does the behavior required by the spec as the Chrome editing engineers
make sense for this case?

- Whatever we decide, I think the spec should be made more clear about what
should happen in these cases.


Thanks,
Ryan Landay

Received on Tuesday, 20 February 2018 21:58:36 UTC