API design proposal: CJK input method support

Hello.

I am a Japanese software developer. I am interested in text input in the CJK language in iced.

As some of you may know, the CJK language requires a mechanism that called “Input Method” for text input (or IME, also known as the abbreviation of Input Method Editor.) In other words, I hope CJK Input method will be supported in iced.

Several Pull requests have been submitted in the past, but since the API Design has not been sufficiently discussed, it seems that the situation of not being merged continues. So, I would like to propose an API Design and start the discussion.

I appreciate for feedbacks to progress discussion!

Supporting input method with winit

Iced relies on winit for the abstraction of the native platform. Therefore, as a premise for discussion, I will explain what is needed for input method support for the winit app.

Following diagram shows basic interaction between input method and winit apps

The word “Preedit” in this figure may be an unfamiliar concept, it shows the intermediate state of the user entering complex words such as “漢字”(kanji) in the Input Method. Depending on the platform, it is also called “Composing Text”, “Composing String”, etc., but I call that “Preedit” here to clarify that it is a concept specific to the Input Method.

There are some display style of the preedit, implementation complexity depends on which style apps/widgets will support.
The following are the well-known types of Preedit display styles.

Off-the-spot Over-the-spot On-the-spot(Inline composing)
Preedit placed unrelated position Preedit placed over original text Preedit temporalily inserted into original text

*“Off-the-spot” image refers to XIM による日本語入力

Type Caret position
required?
Need to tell
allow state?
Who draws preedit?
Off-the-spot NO NO Toolkit*
Over-the-spot YES YES Toolkit or app, it doesn’t affect to app’s text layout
On-the-spot YES YES App embeds composing text in document for Ime::Preedit events

Basic strategy

On-the-spot (Inline) preedit is highest UX quality for CJK users, but it requires (custom) text input widgets to integrate tightly with the input method state. This is not easy for non-CJK developers to support (especially on testing).

So I suggest we have the “Over-the-spot” preedit support on iced first, while we should open the room some custom text input widgets can implement “On-the-spot” preedit style later if they want. We can discuss another mechanisms help to implement those with no hassle, but it is out of scope of this proposal.

How will it work?

How it enables the input method? And how it inputs text to the app?

  • Focused text widget can report its “caret information” containig whether it accepts input with input method currently or not.
  • Native layer (iced_winit) controls the input method state of a winit window from the current caret information.
    • By this, winit starts sending input method events to iced.
  • Text widget handles Commit input method event to insert the text sent from the input method.
    • We can basically reuse the clipboard pasting logic of the widget (some refactoring may be desirable, though)

Then, how it shows the “preedit string”?

  • Native layer (iced_winit) handles the Preedit input method event from winit.
  • It receives the preedit string and place it as layer over the UserInterface with app’s Renderer.

The caret information should looks like this:

pub struct CaretInfo {
    pub position: Point,
    pub input_method_allowed: bool,
    pub shows_preedit_myself: bool,
}

How custom text widgets or apps can implement on-the-spot (inline) style preedit display in future?

  • They can opt-out the over-the-spot preedit layer on reporting its focused caret information.
  • Then, they can implement freely preedit with existing mechanisms.
    • Handles Preedit input method events themselves.
    • Update in-widget or in-app state and build view tree for it.

About reporting the caret information

I propose to let focused text input widget to set its caret information to the Shell on Widget::update().

Because it is better avoiding API change of Widget trait itself, as there are very limited set of widget types involved.

Controlling input method allowed or enabled state affects how shell (and underlying winit) notifies events for user key input. So there is some relevance.

Widgets decide its caret state on update() method, so determining also input method related state there is natural and has enough flexibility.

I submitted my PoC PR draft of this design.

Please refer that too, if you (reader) are interested in.