From e634cc609fe2dd6087515e3014f6979343d5042d Mon Sep 17 00:00:00 2001 From: Mitoma Ryo Date: Tue, 29 Apr 2025 21:11:54 +0900 Subject: [PATCH] windows: fix incorrect cursor_range calculation in Ime::Preedit The `text` is retrieved as UTF-8 while `attributes` are based on UTF-16, thus the offset was getting out of sync on some unicode payloads like surrogate pairs. Fixes #3967. --- src/changelog/unreleased.md | 1 + src/platform_impl/windows/ime.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index a50817b5..bc4107bb 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -257,3 +257,4 @@ changelog entry. - On macOS, fixed `VideoMode::refresh_rate_millihertz` for fractional refresh rates. - On macOS, store monitor handle to avoid panics after going in/out of sleep. - On macOS, allow certain invalid monitor handles and return `None` instead of panicking. +- On Windows, fixed `Ime::Preedit` cursor offset calculation. diff --git a/src/platform_impl/windows/ime.rs b/src/platform_impl/windows/ime.rs index c68a9cd0..4a274904 100644 --- a/src/platform_impl/windows/ime.rs +++ b/src/platform_impl/windows/ime.rs @@ -34,8 +34,13 @@ impl ImeContext { let mut first = None; let mut last = None; let mut boundary_before_char = 0; + let mut attr_idx = 0; + + for chr in text.chars() { + let Some(attr) = attrs.get(attr_idx).copied() else { + break; + }; - for (attr, chr) in attrs.into_iter().zip(text.chars()) { let char_is_targeted = attr as u32 == ATTR_TARGET_CONVERTED || attr as u32 == ATTR_TARGET_NOTCONVERTED; @@ -46,6 +51,7 @@ impl ImeContext { } boundary_before_char += chr.len_utf8(); + attr_idx += chr.len_utf16(); } if first.is_some() && last.is_none() {