Skip to content

Much improved IME#7967

Merged
emilk merged 18 commits intoemilk:mainfrom
umajho:fix-undesired-keyboard-input-events-during-ime-composition
Mar 24, 2026
Merged

Much improved IME#7967
emilk merged 18 commits intoemilk:mainfrom
umajho:fix-undesired-keyboard-input-events-during-ime-composition

Conversation

@umajho
Copy link
Copy Markdown
Contributor

@umajho umajho commented Mar 11, 2026

This approach is better than #7898 (#7914) because it correctly handles all three major IME types (Chinese, Japanese, and Korean) without requiring a predefined “IME mode”.

Environments I haved tested this PR in

macOS 15.7.3 (AArch64, Host of other virtual machines)

Run command: cargo run -p egui_demo_app --release

Tested IMEs:

  • builtin Chinese IME (Shuangpin - Simplified)
  • builtin Japanese IME (Romaji)
  • builtin Korean IME (2-Set)
Windows 11 25H2 (AArch64, Virtual Machine)

Build command: cargo build --release -p egui_demo_app --target=x86_64-pc-windows-gnu --features=glow --no-default-features

(I cannot use wgpu due to this bug, which prevents debugging inside the VM. Anyways, the rendering backend should be irrelevant here.)

Tested IMEs:

  • builtin Chinese IME (Shuangpin)
  • Sogou IME (Chinese Shuangpin)
  • WeType IME (Chinese Shuangpin)
  • builtin Japanese IME (Hiragana)
  • builtin Korean IME (2 Beolsik)
Linux [Wayland + IBus] (AArch64, Virtual Machine)

Fedora KDE Plasma Desktop 43 [Wayland + IBus 1.5.33-rc2]

(Not working at the moment because of another issue that will be fixed by #7983. It is a complicated story. )

[!NOTE]

IBus is partially broken in this system. The Input Method Selector refuses to select IBus. As a workaround, I have to open System Settings -> Virtual Keyboard and select “IBus Wayland” to start an IBus instance that works in egui.

The funny thing is: the Chinese Intelligent Pinyin IME is broken in native Apps like System Settings and KWrite, but works correctly in egui!

Screencast: What

2026-03-13 3 10 11 AM

Build command: cross build --release -p egui_demo_app --target=aarch64-unknown-linux-gnu --features=wayland,wgpu --no-default-features

(The Linux toolchain on my mac is somehow broken, so I used cross instead.)

Tested IMEs:

  • Chinese Intelligent Pinyin IME (Shuangpin)
  • Japanese Anthy IME (Hiragana)
  • Korean Hangul IME
Linux [X11 + Fcitx5] (AArch64, Virtual Machine)

Debian 13 [Cinnamon 6.4.10 + X11 + Fcitx5 5.1.2]

Build command: cross build --release -p egui_demo_app --target=aarch64-unknown-linux-gnu --features=x11,wgpu --no-default-features

Tested IMEs:

  • Chinese Shuangpin IME
  • Chinese Rime IME with luna-pinyin
  • Japanese Mozc IME (Hiragana)
  • Korean Hangul IME

Unlike macOS and Linux + Wayland, key-release events for keys processed by the IME are still forwarded to egui. These appear to be harmless in practice.
Unlike on Windows, however, they cannot be filtered reliably because there are no corresponding key-press events marked as “processed by IME”.


There are too many possible combinations to test (Operating Systems × Desktop Environments × Windowing Systems × IMFs × IMEs × …), and I only have access to a limited subset. For example, Google Japanese Input refused to install on my Windows VM, and some paid Japanese IMEs are not accessible to me. Therefore, I would appreciate feedback from people other than me using all kinds of environments.

Details

There are two possible approaches to removing keyboard events that have already been processed by an IME:

  • Approach 1: Filter out events inside egui that appear to have been received during IME composition.
  • Approach 2: Filter out such events in the platform backend (terminology borrowed from imgui, e.g. the egui-winit crate or the code under web/ in the eframe crate.).

Both approaches already exist in egui:

  • Handle the IME event first in TextEdit to fix some bugs #4794 uses the first approach, filtering these events in the TextEdit-related code.
  • eframe uses the second approach in its web integration. See:
    if event.is_composing() || event.key_code() == 229 {
    // https://web.archive.org/web/20200526195704/https://www.fxsitecompat.dev/en-CA/docs/2018/keydown-and-keyup-events-are-now-fired-during-ime-composition/
    return;
    }

Compared to the first approach, the second has a clear advantage: when events are passed from the platform backends into egui, they are simplified and lose information. In contrast, events in the platform backends are the original events, which allows them to be handled more flexibly. This is also why #7898 (#7914), which attempts to address the issue from within the egui crate, struggles to make all IMEs work correctly at the same time and requires manually selecting an “IME mode”: the events received by egui have already been reduced and therefore lack necessary information.

A more appropriate solution is to consistently follow the second approach, explicitly requiring platform backends not to forward events that have already been processed by the IME to egui. This is the method used in this PR. Specifically, this PR works within the egui-winit crate, where the original KeyboardInput events can be accessed. At least for key press events, these can be used directly to determine whether the event has already been processed by the IME on Windows (by checking whether logical_key equals winit::keyboard::NamedKey::Process). This makes it straightforward to ensure that all IMEs work correctly at the same time.

This PR also reverts #4794, which took the first approach. It filters out some events that merely look like they were received during IME composition but actually are not. It also messes up the order of those events along the way.
As a result, it caused several IME-related issues. One of the sections in the Demonstrations below will illustrate these problems.

Demonstrations

Changes not included in this PR for displaying Unicode characters in demonstrations

Download unifont-17.0.03.otf from https://unifoundry.com/pub/unifont/unifont-17.0.03/font-builds/, and place it at crates/egui_demo_app/src/unifont-17.0.03.otf.

In crates/egui_demo_app/src/wrap_app.rs, add these lines at the beginning of impl WrapApp's pub fn new:

        {
            const MAIN_FONT: &'static [u8] = include_bytes!("./unifont-17.0.03.otf");

            let mut fonts = egui::FontDefinitions::default();

            fonts.font_data.insert(
                "main-font".to_owned(),
                std::sync::Arc::new(egui::FontData::from_static(MAIN_FONT)),
            );

            let proportional = fonts
                .families
                .entry(egui::FontFamily::Proportional)
                .or_default();
            proportional.insert(0, "main-font".to_owned());

            cc.egui_ctx.set_fonts(fonts);
        }

(I took this from somewhere, but I forgot where it is. Sorry…)

GNU Unifont is licensed under OFL-1.1.

This PR Fixes: Focus on a single-line TextEdit is lost after completing candidate selection with Japanese IME on Windows (#7809)

Screencast: ✅ Japanese IME now behaves correctly while Korean IME behaves as before

7809

This PR Fixes: Committing Japanese IME text with Enter inserts an unintended newline in multiline TextEdit on Windows (#7876)

Screencast: ✅ Japanese IME now behaves correctly while Korean IME behaves as before

7876

This PR Fixes: Backspacing deletes characters during composition in certain Chinese IMEs (e.g., Sogou) on Windows (#7908)

Screencast: ✅ Sogou IME now behaves correctly

7908

This PR Obsoletes #4794, because egui receives only IME events during composition from now on

On Windows, “incompatible” events are filtered in egui-winit, aligning the behavior with other systems.

Screencasts

Some Chinese IMEs on Windows:
2026-03-13 12 25 37 AM

The default Japanese IMEs on Windows:
2026-03-13 12 28 33 AM

The 2-set Korean IMEs handle arrow keys differently. It will be discussed in the next section.

This PR Reverts #4794, because it introduced several bugs

Some of its bugs have already been worked around in the past, but those workarounds might also be problematic. For example, #4912 is a workaround for a bug (#4908) introduced by #4794, and that workaround is in fact the root cause of the macOS backspacing bug I have worked around with #7810. (The reversion of #4912 is out of the scope of this PR, I will do that in #7983.)

It Caused: Arrow keys are incorrectly blocked during typical Korean IME composition

When composing Korean text using 2-Set IMEs, users should still be able to move the cursor with arrow keys regardless if the composition is committed.

Correct behavior
Screencasts

macOS TextEdit:
2026-03-12 8 04 15 PM

Windows Notepad:
2026-03-12 8 05 08 PM

With #4794 reverted, egui also behaves correctly (tested on Linux + Wayland, macOS, and Windows):
2026-03-12 8 03 51 PM

Incorrect behavior caused by #4794

remove_ime_incompatible_events removed arrow-key events in such cases. As a result, the first arrow key press only commits the composition, and users need to press the arrow key again to move the cursor:

Screencast

2026-03-12 8 06 40 PM

This is essentially the same issue described here: #7877 (comment)

It Caused: Backspacing leaves the last character in Korean IME pre-edit text not removed on macOS

Screencasts

Before this PR:
2026-03-17 10 48 12 PM

After this PR:
2026-03-17 10 47 23 PM

Korean IMEs also use Enter to confirm Hanja selections, and will not work properly in the Korean “IME mode” proposed by #7898 (#7914)

Screencast: Korean IME using Enter and Space for confirmation (IBus Korean Hangul IME)

The screencast below demonstrates that some Korean IMEs handle Hanja selection in a way similar to Japanese IMEs: the Up/Down arrow keys are used to navigate candidates, and Enter confirms the selected candidate.

2026-03-13 6 39 17 AM

Screencasts: Another example

Using the built-in Korean IME on Windows, I type two lines: the first line in Hangul, and the second line as the same word converted to Hanja.

Correct behavior in Notepad (reference):
7914-ref

Behavior after applying this PR, which matches the Notepad behavior:
7914-7967

Behavior after applying #7914 with the “IME mode” set to Korean (which is also the behavior before this PR being applied):
7914-7914
On the second line, each time a Hanja character is confirmed, an unintended newline is inserted. This mirrors the Japanese IME issues that are supposed to be fixed by setting the “IME mode” to Japanese.
(These Japanese IME issues are fixed in this PR as mentioned before.)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 11, 2026

Preview available at https://egui-pr-preview.github.io/pr/7967-fix-undesired-keyboard-input-events-during-ime-composition
Note that it might take a couple seconds for the update to show up after the preview_build workflow has completed.

View snapshot changes at kitdiff

@umajho
Copy link
Copy Markdown
Contributor Author

umajho commented Mar 11, 2026

Related winit issue: rust-windowing/winit#4508

@umajho umajho changed the title Fix: winit::event::KeyboardInput fiddling with IME composition on Windows Fix winit::event::KeyboardInput fiddling with IME composition on Windows properly Mar 12, 2026
@umajho umajho marked this pull request as ready for review March 13, 2026 22:24
@umajho
Copy link
Copy Markdown
Contributor Author

umajho commented Mar 13, 2026

Hello.
Since you were involved in the issues/PRs related to this PR, I'd appreciate it if you could take a look at this PR.
Sorry if the pinging annoyed you.

@choyunjin (Issue #7809)
@ClozedJP (Issue #7876)
@cats2333 (Issue #7908)
@sevenc-nanashi (PR #7877)
@rustbasic (PR #7898, PR #7914, and PR #4794)

@sevenc-nanashi
Copy link
Copy Markdown

sevenc-nanashi commented Mar 17, 2026

Tested on Windows 11 with Google Japanese IME, it's working very well, like other applications that supports IME. Nice work!

Speaking of implementation, as the behavior which winit sends keyboard events that is consumed by IME is confirmed as a bug, it would be nice to have a comment that says the implementation is workaround and will be fixed by winit.

@umajho umajho changed the title Fix winit::event::KeyboardInput fiddling with IME composition on Windows properly Workaround winit::event::KeyboardInput fiddling with IME composition on Windows properly Mar 17, 2026
@umajho umajho changed the title Workaround winit::event::KeyboardInput fiddling with IME composition on Windows properly Work around winit::event::KeyboardInput fiddling with IME composition on Windows properly Mar 19, 2026
@lucasmerlin lucasmerlin added bug Something is broken IME egui-winit porblems related to winit labels Mar 19, 2026
Copy link
Copy Markdown
Collaborator

@lucasmerlin lucasmerlin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Thanks for the thorough testing as well!

@umajho
Copy link
Copy Markdown
Contributor Author

umajho commented Mar 19, 2026

I noticed that @rustbasic reacted with an 👀 to the comment where I pinged people, so they may still be reviewing this PR. I think we should wait for their feedback before considering merging it.

@rustbasic
Copy link
Copy Markdown
Contributor

Great job, @umajho.
This Pull Request #7967 is a solid replacement for #4794.
It is useful for handling special key inputs during IME composition.

On a side note, I believe #7914 should still be pursued for separate reasons.
It(#7914) specifically addresses and resolves issues related to the 'Cheonjiin' Korean keyboard layout.
Furthermore, the start and end indices provided by Preedit are still necessary in certain contexts, so that PR remains relevant.

While not directly related to this (#7914 and #7967), there are still some unresolved issues regarding IME handling.
For instance, if the focus is moved to another TextEdit via a mouse click or the TAB key
while an IME composition is active, the character currently being typed is incorrectly transferred to the newly selected TextEdit.
( Currently, this is being partially prevented by checking the cursor_range. Related #4137 )

@umajho
Copy link
Copy Markdown
Contributor Author

umajho commented Mar 20, 2026

@rustbasic thanks for the feedback!

Could you elaborate more on the Cheonjiin issue Specifically:

  • how to reproduce it,
  • what is the expected behavior,
  • what is the actual behavior,
  • and by any chance, this PR inadvertently fixed it?

Regarding #4137

The ime_cursor_range it introduced led to #7485. Rather than adding more complexity by working around ime_cursor_range, I proposed in #7983 to replace #4137 with a simpler approach using mem.had_focus_last_frame.

I have tested #7983 on Windows and confirmed that the partial fix for the focus-related bug still works there. (And on macOS, the behavior remains incorrect as before.)

I guess the ultimate solution may involve explicitly disabling and re-enabling the IME when a TextEdit gains focus, though this is just a speculation.

@umajho
Copy link
Copy Markdown
Contributor Author

umajho commented Mar 20, 2026

Regarding the Preedit cursor range:

I'm also planning to introduce this in a follow-up PR that implements visuals for “real IME cursors & cursor ranges.” My intention is to work on it after this PR and #7983 are resolved.

By “real IME cursors & cursor ranges,” I mean something like the following:
Screenshot 2026-03-20 at 9 54 00 PM
Screenshot 2026-03-20 at 9 54 56 PM


Since this discussion is already outside the scope of this PR, I suggest we continue it in #7983 and merge this PR first.

(Since I've gathered feedback from both a Japanese IME user and a Korean IME user that this PR works, and I'm confident it also works for Chinese IMEs (at least for those Pinyin-like), I believe this PR is ready to be merged.)

@umajho umajho requested a review from lucasmerlin March 20, 2026 13:51
@rustbasic
Copy link
Copy Markdown
Contributor

rustbasic commented Mar 20, 2026

@rustbasic thanks for the feedback!

Could you elaborate more on the Cheonjiin issue Specifically:

  • how to reproduce it,
  • what is the expected behavior,
  • what is the actual behavior,
  • and by any chance, this PR inadvertently fixed it?

Regarding #4137

The ime_cursor_range it introduced led to #7485. Rather than adding more complexity by working around ime_cursor_range, I proposed in #7983 to replace #4137 with a simpler approach using mem.had_focus_last_frame.

I have tested #7983 on Windows and confirmed that the partial fix for the focus-related bug still works there. (And on macOS, the behavior remains incorrect as before.)

I guess the ultimate solution may involve explicitly disabling and re-enabling the IME when a TextEdit gains focus, though this is just a speculation.

Regarding the Cheonjiin Korean Keyboard issue:
The Cheonjiin layout issue was not resolved in #7967 and is not directly related to it.
For certain Korean characters with double final consonants (batchim), such as "않", the IME occasionally needs to revert and delete characters even after a Commit has been sent.
This is why the start and end indices from Preedit are essential.

Example sequence:
"안" -> 안"ㅎ" -> "않" -> 않"ㅇ" -> 않"아"
"안" -> 안"ㅎ" -> 안"해"

Regarding #7983:
While #7983 is effective when moving focus between different TextEdit elements on Windows, it also shows some effectiveness on WASM as well.
I believe #4137 should be maintained. If #4137 is removed, clicking a different position within the same TextEdit during composition causes the character to be incorrectly copied to that new position. Essentially, #4137 and #7983 address different problems: one handles issues within the same TextEdit, while the other handles transitions between different TextEdit elements.

Regarding disabling and re-enabling IME on focus:
The main challenge here is the non-deterministic timing of the Commit signal.
Disabling it for just a single frame might not be sufficient; it might require a delay of about 0.1 seconds. It could be a viable temporary workaround, though.

@rustbasic
Copy link
Copy Markdown
Contributor

rustbasic commented Mar 20, 2026

@umajho
In my opinion, it might be better not to modify #4137 in #7983. Instead, could you try setting wants_ime_events to had_focus_last_frame and resubmitting the PR? I’ll do some further testing in the meantime.

Update from further testing:
I have confirmed that the character copying issue is resolved on both Windows and WASM by combining #4137 and #7983.

@umajho
Copy link
Copy Markdown
Contributor Author

umajho commented Mar 20, 2026

Note

I moved the original content of this comment to #7983 (comment)

I think we should continue our discussion in #7983, since we are now talking about what comes after this PR, which is what I originally planned for #7983.

@cats2333
Copy link
Copy Markdown

Finally, a smooth typing experience in egui on Windows! Thank you for the extensive testing across different environments. You've solved a long-standing pain point for us : )

@emilk emilk added the eframe Relates to epi and eframe label Mar 24, 2026
@emilk emilk changed the title Work around winit::event::KeyboardInput fiddling with IME composition on Windows properly Much improved IME Mar 24, 2026
@emilk emilk merged commit b4f9cd7 into emilk:main Mar 24, 2026
26 checks passed
@emilk
Copy link
Copy Markdown
Owner

emilk commented Mar 24, 2026

Thank you!

Masterchef365 pushed a commit to Masterchef365/egui that referenced this pull request Apr 3, 2026
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* Closes emilk#7809
* Closes emilk#7876
* Closes emilk#7908
* Supersedes emilk#7877
* Supersedes emilk#7898
* The author of the PR above replaced it with emilk#7914, which additionally
fixes another IME issue. I believe that fix deserves a separate PR.
* Reverts emilk#4794  
* [x] I have followed the instructions in the PR template

This approach is better than emilk#7898 (emilk#7914) because it correctly handles
all three major IME types (Chinese, Japanese, and Korean) without
requiring a predefined “IME mode”.

## Environments I haved tested this PR in

<details><summary>macOS 15.7.3 (AArch64, Host of other virtual
machines)</summary>

Run command: `cargo run -p egui_demo_app --release`

Tested IMEs:

- builtin Chinese IME (Shuangpin - Simplified)
- builtin Japanese IME (Romaji)
- builtin Korean IME (2-Set)
</details>

<details><summary>Windows 11 25H2 (AArch64, Virtual Machine)</summary>

Build command: `cargo build --release -p egui_demo_app
--target=x86_64-pc-windows-gnu --features=glow --no-default-features`

(I cannot use `wgpu` due to [this
bug](emilk#4381), which prevents
debugging inside the VM. Anyways, the rendering backend should be
irrelevant here.)

Tested IMEs:

- builtin Chinese IME (Shuangpin)
- Sogou IME (Chinese Shuangpin)
- WeType IME (Chinese Shuangpin)
- builtin Japanese IME (Hiragana)
- builtin Korean IME (2 Beolsik)
</details>

<details><summary>Linux [Wayland + IBus] (AArch64, Virtual
Machine)</summary>

Fedora KDE Plasma Desktop 43 [Wayland + IBus 1.5.33-rc2]

(Not working at the moment because of [another
issue](emilk#7485) that will be fixed by
emilk#7983. It is [a complicated
story](emilk#7973 (comment)).
)

> [!NOTE]
>
> IBus is partially broken in this system. The Input Method Selector
refuses to select IBus. As a workaround, I have to open System Settings
-> Virtual Keyboard and select “IBus Wayland” to start an IBus instance
that works in egui.
>
> The funny thing is: the Chinese Intelligent Pinyin IME is broken in
native Apps like System Settings and KWrite, but works correctly in
egui!
>
> <details><summary>Screencast: What</summary>
>
> ![2026-03-13 3 10
11 AM](https://github.com/user-attachments/assets/4001cf12-8089-46f5-9cf4-e41d8f77ee24)
> </details>

Build command: `cross build --release -p egui_demo_app
--target=aarch64-unknown-linux-gnu --features=wayland,wgpu
--no-default-features`

(The Linux toolchain on my mac is somehow broken, so I used `cross`
instead.)

Tested IMEs:

- Chinese Intelligent Pinyin IME (Shuangpin)
- Japanese Anthy IME (Hiragana)
- Korean Hangul IME
</details>

<details><summary>Linux [X11 + Fcitx5] (AArch64, Virtual
Machine)</summary>

Debian 13 [Cinnamon 6.4.10 + X11 + Fcitx5 5.1.2]

Build command: `cross build --release -p egui_demo_app
--target=aarch64-unknown-linux-gnu --features=x11,wgpu
--no-default-features`

Tested IMEs:

- Chinese Shuangpin IME
- Chinese Rime IME with `luna-pinyin`
- Japanese Mozc IME (Hiragana)
- Korean Hangul IME

Unlike macOS and Linux + Wayland, key-release events for keys processed
by the IME are still forwarded to `egui`. These appear to be harmless in
practice.
Unlike on Windows, however, they cannot be filtered reliably because
there are no corresponding key-press events marked as “processed by
IME”.

</details>

---

There are too many possible combinations to test (Operating Systems ×
[Desktop
Environment](https://en.wikipedia.org/wiki/Desktop_environment)s ×
[Windowing System](https://en.wikipedia.org/wiki/Windowing_system)s ×
[IMF](https://wiki.archlinux.org/title/Input_method#Input_method_framework)s
× [IME](https://en.wikipedia.org/wiki/Input_method)s × …), and I only
have access to a limited subset. For example, Google Japanese Input
refused to install on my Windows VM, and some paid Japanese IMEs are not
accessible to me. Therefore, I would appreciate feedback from people
other than me using all kinds of environments.

## Details

There are two possible approaches to removing keyboard events that have
already been processed by an IME:

* Approach 1: Filter out events inside `egui` that appear to have been
received during IME composition.
* Approach 2: Filter out such events in the platform backend
(terminology [borrowed from
imgui](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md#using-standard-backends),
e.g. the `egui-winit` crate or the code under `web/` in the `eframe`
crate.).

Both approaches already exist in `egui`:

* emilk#4794 uses the first approach, filtering these events in the
`TextEdit`-related code.
* `eframe` uses the second approach in its web integration. See:
<https://github.com/emilk/egui/blob/14afefa2521d1baaf4fd02105eec2d3727a7ac36/crates/eframe/src/web/events.rs#L173-L176>

Compared to the first approach, the second has a clear advantage: when
events are passed from the platform backends into `egui`, they are
simplified and lose information. In contrast, events in the platform
backends are the original events, which allows them to be handled more
flexibly. This is also why emilk#7898 (emilk#7914), which attempts to address the
issue from within the `egui` crate, struggles to make all IMEs work
correctly at the same time and requires manually selecting an “IME
mode”: the events received by `egui` have already been reduced and
therefore lack necessary information.

A more appropriate solution is to consistently follow the second
approach, explicitly requiring platform backends not to forward events
that have already been processed by the IME to `egui`. This is the
method used in this PR. Specifically, this PR works within the
`egui-winit` crate, where the original `KeyboardInput` events can be
accessed. At least for key press events, these can be used directly to
determine whether the event has already been processed by the IME on
Windows (by checking whether `logical_key` equals
`winit::keyboard::NamedKey::Process`). This makes it straightforward to
ensure that all IMEs work correctly at the same time.

This PR also reverts emilk#4794, which took the first approach. It filters
out some events that merely look like they were received during IME
composition but actually are not. It also messes up the order of those
events along the way.
As a result, it caused several IME-related issues. One of the sections
in the Demonstrations below will illustrate these problems.

## Demonstrations

<details><summary>Changes not included in this PR for displaying Unicode
characters in demonstrations</summary>

Download `unifont-17.0.03.otf` from
<https://unifoundry.com/pub/unifont/unifont-17.0.03/font-builds/>, and
place it at `crates/egui_demo_app/src/unifont-17.0.03.otf`.

In `crates/egui_demo_app/src/wrap_app.rs`, add these lines at the
beginning of `impl WrapApp`'s `pub fn new`:
```rust
        {
            const MAIN_FONT: &'static [u8] = include_bytes!("./unifont-17.0.03.otf");

            let mut fonts = egui::FontDefinitions::default();

            fonts.font_data.insert(
                "main-font".to_owned(),
                std::sync::Arc::new(egui::FontData::from_static(MAIN_FONT)),
            );

            let proportional = fonts
                .families
                .entry(egui::FontFamily::Proportional)
                .or_default();
            proportional.insert(0, "main-font".to_owned());

            cc.egui_ctx.set_fonts(fonts);
        }
```

(I took this from somewhere, but I forgot where it is. Sorry…)
</details>

[GNU Unifont](https://unifoundry.com/unifont/index.html) is licensed
under [OFL-1.1](https://unifoundry.com/OFL-1.1.txt).

### This PR Fixes: Focus on a single-line `TextEdit` is lost after
completing candidate selection with Japanese IME on Windows (emilk#7809)

<details><summary>Screencast: ✅ Japanese IME now behaves correctly while
Korean IME behaves as before</summary>


![7809](https://github.com/user-attachments/assets/6e92f6e6-fed4-46f4-96e1-e0e12dadc360)
</details>

### This PR Fixes: Committing Japanese IME text with <kbd>Enter</kbd>
inserts an unintended newline in multiline `TextEdit` on Windows (emilk#7876)

<details><summary>Screencast: ✅ Japanese IME now behaves correctly while
Korean IME behaves as before</summary>


![7876](https://github.com/user-attachments/assets/03d2cb22-fd0c-45fe-9132-e59fa39bfcf3)
</details>

### This PR Fixes: Backspacing deletes characters during composition in
certain Chinese IMEs (e.g., Sogou) on Windows (emilk#7908)

<details><summary>Screencast: ✅ Sogou IME now behaves
correctly</summary>


![7908](https://github.com/user-attachments/assets/2c63de28-26f0-4387-9c50-dceabfdbe99d)
</details>

### This PR Obsoletes emilk#4794, because `egui` receives only IME events
during composition from now on

On Windows, “incompatible” events are filtered in `egui-winit`, aligning
the behavior with other systems.

<details><summary>Screencasts</summary>

Some Chinese IMEs on Windows:
![2026-03-13 12 25
37 AM](https://github.com/user-attachments/assets/064fd1c7-244b-4053-bd24-c65d768cd943)

The default Japanese IMEs on Windows:
![2026-03-13 12 28
33 AM](https://github.com/user-attachments/assets/f799b0b5-350b-4b05-a769-bcef16255bdb)
</details>

The 2-set Korean IMEs handle arrow keys differently. It will be
discussed in the next section.

### This PR Reverts emilk#4794, because it introduced several bugs

Some of its bugs have already been worked around in the past, but those
workarounds might also be problematic. For example, emilk#4912 is a
workaround for a bug (emilk#4908) introduced by emilk#4794, and that workaround is
in fact the root cause of the macOS backspacing bug I have worked around
with emilk#7810. (The reversion of emilk#4912 is out of the scope of this PR, I
will do that in emilk#7983.)

#### It Caused: Arrow keys are incorrectly blocked during typical Korean
IME composition

When composing Korean text using 2-Set IMEs, users should still be able
to move the cursor with arrow keys regardless if the composition is
committed.

##### Correct behavior

<details><summary>Screencasts</summary>

macOS TextEdit:
![2026-03-12 8 04
15 PM](https://github.com/user-attachments/assets/24383568-f51c-4a74-9251-adfd942cad8f)

Windows Notepad:
![2026-03-12 8 05
08 PM](https://github.com/user-attachments/assets/5a29a5b5-69b8-407b-b1a4-84fdb8f8847d)

With emilk#4794 reverted, `egui` also behaves correctly (tested on Linux +
Wayland, macOS, and Windows):
![2026-03-12 8 03
51 PM](https://github.com/user-attachments/assets/fcb7f25c-1329-4eb1-82f2-1cea33dcca73)
</details>

##### Incorrect behavior caused by emilk#4794

`remove_ime_incompatible_events` removed arrow-key events in such cases.
As a result, the first arrow key press only commits the composition, and
users need to press the arrow key again to move the cursor:

<details><summary>Screencast</summary>

![2026-03-12 8 06
40 PM](https://github.com/user-attachments/assets/6760c6bd-b6ce-44ea-b192-6bd165191c01)
</details>

This is essentially the same issue described here:
emilk#7877 (comment)

#### It Caused: Backspacing leaves the last character in Korean IME
pre-edit text not removed on macOS

<details><summary>Screencasts</summary>

Before this PR:
![2026-03-17 10 48
12 PM](https://github.com/user-attachments/assets/88021e7e-caf6-4aa9-8f73-ecffc63cda06)

After this PR:
![2026-03-17 10 47
23 PM](https://github.com/user-attachments/assets/379cd0db-24e0-4c0e-a5b4-edb37d3e1df7)
</details>

### Korean IMEs also use <kbd>Enter</kbd> to confirm Hanja selections,
and will not work properly in the Korean “IME mode” proposed by emilk#7898
(emilk#7914)

<details><summary>Screencast: Korean IME using <kbd>Enter</kbd> and
<kbd>Space</kbd> for confirmation (IBus Korean Hangul IME)</summary>

The screencast below demonstrates that some Korean IMEs handle Hanja
selection in a way similar to Japanese IMEs: the
<kbd>Up</kbd>/<kbd>Down</kbd> arrow keys are used to navigate
candidates, and <kbd>Enter</kbd> confirms the selected candidate.

![2026-03-13 6 39
17 AM](https://github.com/user-attachments/assets/0b054cc6-2251-4689-95a4-d69a9be36371)
</details>

<details><summary>Screencasts: Another example</summary>

Using the built-in Korean IME on Windows, I type two lines: the first
line in Hangul, and the second line as the same word converted to Hanja.

Correct behavior in Notepad (reference):

![7914-ref](https://github.com/user-attachments/assets/1e9f9315-eb71-497a-b6e2-2b11eb6bbf7f)

Behavior after applying this PR, which matches the Notepad behavior:

![7914-7967](https://github.com/user-attachments/assets/26f12b9f-9354-45b8-b2a8-ede28c34c5b1)

Behavior after applying emilk#7914 with the “IME mode” set to Korean (which
is also the behavior before this PR being applied):

![7914-7914](https://github.com/user-attachments/assets/0f82a019-c491-4b64-a92a-d88d62dfbd84)
On the second line, each time a Hanja character is confirmed, an
unintended newline is inserted. This mirrors the Japanese IME issues
that are supposed to be fixed by setting the “IME mode” to Japanese.
(These Japanese IME issues are fixed in this PR as mentioned before.)

</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something is broken eframe Relates to epi and eframe egui-winit porblems related to winit IME

Projects

None yet

6 participants