From 2afc7bb0de7e63d8785fb101e2a84b28053a44c2 Mon Sep 17 00:00:00 2001 From: elm <71685838+not-elm@users.noreply.github.com> Date: Fri, 6 Feb 2026 00:43:49 +0900 Subject: [PATCH] fix: enable IME input by working around bevy_winit bug (#19) * fix: enable IME input by working around bevy_winit initialization bug --- CHANGELOG.md | 1 + src/keyboard.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60d250e..0551117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - Fixed so that the webview can detect pointers correctly even if it is not the root entity. - Avoid a crash when updating the cursor icon +- Fixed IME input not working due to `bevy_winit` not calling `set_ime_allowed()` on initial window creation ## v0.1.0 diff --git a/src/keyboard.rs b/src/keyboard.rs index f868bdc..554afde 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -14,6 +14,9 @@ impl Plugin for KeyboardPlugin { app.init_resource::().add_systems( Update, ( + // Workaround for bevy_winit not calling `set_ime_allowed` on initial window + // creation when `Window::ime_enabled` is `true` from the start. + activate_ime, ime_event.run_if(on_message::), send_key_event.run_if(on_message::), ) @@ -22,6 +25,42 @@ impl Plugin for KeyboardPlugin { } } +/// Workaround: bevy_winit does not call `winit::Window::set_ime_allowed()` during initial window +/// creation when `Window::ime_enabled` is `true`. This means `Ime` events are never generated. +/// +/// To trigger bevy_winit's own `changed_windows` system, we temporarily toggle `ime_enabled` off +/// then back on over two frames, which causes the change detection to fire and call +/// `set_ime_allowed(true)` internally. +fn activate_ime(mut windows: Query<&mut Window>, mut state: Local) { + match *state { + ImeActivationState::Pending => { + for mut window in windows.iter_mut() { + if window.ime_enabled { + window.ime_enabled = false; + *state = ImeActivationState::Toggled; + } + } + } + ImeActivationState::Toggled => { + for mut window in windows.iter_mut() { + if !window.ime_enabled { + window.ime_enabled = true; + *state = ImeActivationState::Done; + } + } + } + ImeActivationState::Done => {} + } +} + +#[derive(Default)] +enum ImeActivationState { + #[default] + Pending, + Toggled, + Done, +} + #[derive(Resource, Default, Serialize, Deserialize, Reflect)] #[reflect(Default, Serialize, Deserialize)] struct IsImeCommiting(bool);