diff --git a/winit-appkit/src/view.rs b/winit-appkit/src/view.rs index 818e460277..e07c512070 100644 --- a/winit-appkit/src/view.rs +++ b/winit-appkit/src/view.rs @@ -371,9 +371,24 @@ define_class!( let is_control = string.chars().next().is_some_and(|c| c.is_control()); - // Commit only if we have marked text. - if self.hasMarkedText() && self.is_ime_enabled() && !is_control { - self.queue_event(WindowEvent::Ime(Ime::Preedit(String::new(), None))); + // Commit the text whenever the IME is enabled and the string is + // not a control character. The original guard `hasMarkedText()` + // was too strict: some input methods (e.g. macOS Chinese + // Simplified Pinyin) convert punctuation keys by calling + // `insertText:` *without* a prior `setMarkedText:`, so + // `hasMarkedText()` is `false` even though the text is the + // IME-converted result (e.g. `,` → `,`). + // + // Without this change winit silently drops the converted + // character and the raw ASCII key from `NSEvent.characters` + // reaches the application instead. + // + // When `hasMarkedText()` is `true` we still clear the preedit + // first, preserving the existing preedit-then-commit sequence. + if self.is_ime_enabled() && !is_control { + if self.hasMarkedText() { + self.queue_event(WindowEvent::Ime(Ime::Preedit(String::new(), None))); + } self.queue_event(WindowEvent::Ime(Ime::Commit(string))); self.ivars().ime_state.set(ImeState::Committed); } diff --git a/winit-x11/src/event_processor.rs b/winit-x11/src/event_processor.rs index 72c1c295f7..4127c01a68 100644 --- a/winit-x11/src/event_processor.rs +++ b/winit-x11/src/event_processor.rs @@ -1757,7 +1757,7 @@ impl EventProcessor { .find(|prev_monitor| prev_monitor.name == new_monitor.name) .map(|prev_monitor| prev_monitor.scale_factor); if Some(new_monitor.scale_factor) != maybe_prev_scale_factor { - for window in self.target.windows.borrow().iter().filter_map(|(_, w)| w.upgrade()) { + for window in self.target.windows.borrow().values().filter_map(|w| w.upgrade()) { window.refresh_dpi_for_monitor( &new_monitor, maybe_prev_scale_factor, diff --git a/winit/src/changelog/v0.31.md b/winit/src/changelog/v0.31.md index d64bdd6e58..ecda7fe6ca 100644 --- a/winit/src/changelog/v0.31.md +++ b/winit/src/changelog/v0.31.md @@ -1,6 +1,14 @@ ## 0.31.0-beta.2 -### Added +### Fixed + +- On macOS, `insertText:replacementRange:` now always emits `Ime::Commit` + when the IME is enabled, even when `hasMarkedText()` is `false`. This + fixes Chinese (and potentially other CJK) punctuation input: the macOS + Chinese Simplified Pinyin IME converts punctuation keys (e.g. `,` → + `,`) via a direct `insertText:` call without a prior `setMarkedText:`, + causing the converted character to be silently dropped and the raw ASCII + key to reach the application instead. - Add `EventLoopExtRegister::register_app` for being explicit about how the event loop runs on Web. - Add `EventLoopExtNeverReturn::run_app_never_return` for being explicit about how the event loop runs on iOS.