From 6123e473776720d2c13be4a7314fa346a0a4533d Mon Sep 17 00:00:00 2001 From: zhjie Date: Mon, 25 May 2026 01:10:28 +0800 Subject: [PATCH 1/2] macOS: fix IME punctuation dropped when hasMarkedText() is false MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macOS Chinese Simplified Pinyin IME (and likely other CJK input methods) converts punctuation keys by calling insertText: directly, without a prior setMarkedText: call. Because hasMarkedText() is false at that point, winit silently dropped the converted character and the raw ASCII key from NSEvent.characters reached the application instead. For example, pressing ',' in Chinese mode should produce the Chinese comma ',', but the application received ',' (ASCII) because ',' was never emitted as Ime::Commit. Fix: emit Ime::Commit whenever is_ime_enabled() is true and the string is not a control character, regardless of hasMarkedText(). When hasMarkedText() is true we still clear the preedit first, preserving the existing preedit-then-commit behaviour for composed characters. ImeState::Committed is always set, so keyDown: treats the key as handled (had_ime_input = true) and does not generate a duplicate KeyboardInput event with the raw ASCII character. Tested with: Apple Chinese Simplified Pinyin, punctuation (,。?! ;:「」), full-width ASCII, and standard pinyin composition (nihao → 你好). No regression observed on Japanese and Korean IMEs (confirmed by inspecting the existing test matrix in PR #4478). --- winit-appkit/src/view.rs | 21 ++++++++++++++++++--- winit/src/changelog/v0.31.md | 10 +++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) 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/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. From fbfd061d9d54d1046533e0ba53463c5c6df9990c Mon Sep 17 00:00:00 2001 From: zhjie Date: Mon, 25 May 2026 01:38:34 +0800 Subject: [PATCH 2/2] winit-x11: fix clippy::iter_kv_map on map values iteration --- winit-x11/src/event_processor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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,