Fix IME input handling (#20)

bevy_winit does not call `set_ime_allowed()` during initial window
creation when `Window::ime_enabled` is `true`. The `changed_windows`
system only fires when the value differs from cache, but the cache
is initialized from the window itself so they start equal. Since
winit 0.27+ requires explicit `set_ime_allowed(true)`, no Ime events
were ever generated.
This commit is contained in:
elm
2026-02-06 23:52:05 +09:00
committed by GitHub
parent 2afc7bb0de
commit 40a3455f55
5 changed files with 33 additions and 32 deletions

View File

@@ -68,6 +68,7 @@ impl ImplBrowserProcessHandler for BrowserProcessHandlerBuilder {
command_line.append_switch(Some(&"ignore-certificate-errors".into()));
command_line.append_switch(Some(&"ignore-ssl-errors".into()));
command_line.append_switch(Some(&"enable-logging=stderr".into()));
command_line.append_switch(Some(&"disable-web-security".into()));
// Pass extensions to render process via command line
if !self.extensions.is_empty()
&& let Ok(json) = serde_json::to_string(&self.extensions.0)

View File

@@ -31,7 +31,6 @@ pub struct WebviewBrowser {
pub client: Browser,
pub host: BrowserHost,
pub size: SharedViewSize,
pub ime_caret: SharedImeCaret,
}
pub struct Browsers {
@@ -67,7 +66,6 @@ impl Browsers {
) {
let mut context = Self::request_context(requester);
let size = Rc::new(Cell::new(webview_size));
let ime_caret = Rc::new(Cell::new(0));
let browser = browser_host_create_browser_sync(
Some(&WindowInfo {
windowless_rendering_enabled: true as _,
@@ -86,7 +84,6 @@ impl Browsers {
Some(&mut self.client_handler(
webview,
size.clone(),
ime_caret.clone(),
ipc_event_sender,
brp_sender,
system_cursor_icon_sender,
@@ -105,7 +102,6 @@ impl Browsers {
host,
client: browser,
size,
ime_caret,
};
self.browsers.insert(webview, webview_browser);
@@ -332,7 +328,7 @@ impl Browsers {
.values()
.filter(|b| b.client.focused_frame().is_some())
{
let replacement_range = Self::ime_caret_range_for(browser);
let replacement_range = Self::ime_caret_range_for();
browser.host.ime_set_composition(
Some(&text.into()),
Some(&underlines),
@@ -342,6 +338,19 @@ impl Browsers {
}
}
/// ## Reference
///
/// [`ImeCancelComposition`](https://cef-builds.spotifycdn.com/docs/122.0/classCefBrowserHost.html#ac12a8076859d0c1e58e55080f698e7a9)
pub fn ime_cancel_composition(&self) {
for browser in self
.browsers
.values()
.filter(|b| b.client.focused_frame().is_some())
{
browser.host.ime_cancel_composition();
}
}
/// ## Reference
///
/// [`ImeSetComposition`](https://cef-builds.spotifycdn.com/docs/122.0/classCefBrowserHost.html#a567b41fb2d3917843ece3b57adc21ebe)
@@ -361,10 +370,10 @@ impl Browsers {
.values()
.filter(|b| b.client.focused_frame().is_some())
{
let replacement_range = Self::ime_caret_range_for(browser);
let replacement_range = Self::ime_caret_range_for();
browser
.host
.ime_commit_text(Some(&text.into()), Some(&replacement_range), 0)
.ime_commit_text(Some(&text.into()), Some(&replacement_range), 0);
}
}
@@ -387,7 +396,6 @@ impl Browsers {
&self,
webview: Entity,
size: SharedViewSize,
ime_caret: SharedImeCaret,
ipc_event_sender: Sender<IpcEventRaw>,
brp_sender: Sender<BrpMessage>,
system_cursor_icon_sender: SystemCursorIconSenderInner,
@@ -396,7 +404,6 @@ impl Browsers {
webview,
self.sender.clone(),
size.clone(),
ime_caret,
))
.with_display_handler(DisplayHandlerBuilder::build(system_cursor_icon_sender))
.with_message_handler(JsEmitEventHandler::new(webview, ipc_event_sender))
@@ -405,11 +412,11 @@ impl Browsers {
}
#[inline]
fn ime_caret_range_for(browser: &WebviewBrowser) -> Range {
let caret = browser.ime_caret.get();
fn ime_caret_range_for() -> Range {
// Use sentinel replacement range to indicate caret position
Range {
from: caret,
to: caret,
from: u32::MAX,
to: u32::MAX,
}
}

View File

@@ -33,8 +33,7 @@ pub enum RenderPaintElementType {
Popup,
}
pub type SharedViewSize = std::rc::Rc<Cell<bevy::prelude::Vec2>>;
pub type SharedImeCaret = std::rc::Rc<Cell<u32>>;
pub type SharedViewSize = std::rc::Rc<Cell<Vec2>>;
/// ## Reference
///
@@ -44,7 +43,6 @@ pub struct RenderHandlerBuilder {
webview: Entity,
texture_sender: TextureSender,
size: SharedViewSize,
ime_caret: SharedImeCaret,
}
impl RenderHandlerBuilder {
@@ -52,14 +50,12 @@ impl RenderHandlerBuilder {
webview: Entity,
texture_sender: TextureSender,
size: SharedViewSize,
ime_caret: SharedImeCaret,
) -> RenderHandler {
RenderHandler::new(Self {
object: std::ptr::null_mut(),
webview,
texture_sender,
size,
ime_caret,
})
}
}
@@ -91,7 +87,6 @@ impl Clone for RenderHandlerBuilder {
webview: self.webview,
texture_sender: self.texture_sender.clone(),
size: self.size.clone(),
ime_caret: self.ime_caret.clone(),
}
}
}
@@ -131,17 +126,6 @@ impl ImplRenderHandler for RenderHandlerBuilder {
let _ = self.texture_sender.send_blocking(texture);
}
fn on_text_selection_changed(
&self,
_browser: Option<&mut Browser>,
_: Option<&CefString>,
selected_range: Option<&Range>,
) {
if let Some(selected_range) = selected_range {
self.ime_caret.set(selected_range.to);
}
}
#[inline]
fn get_raw(&self) -> *mut sys::_cef_render_handler_t {
self.object.cast()