Skip to content

Commit c99e42a

Browse files
authored
windows: Properly handle surrogates (#34006)
Closes #33791 Surrogate pairs are now handled correctly, so input from tools like `WinCompose` is properly received. Release Notes: - N/A
1 parent 018dbfb commit c99e42a

File tree

2 files changed

+38
-6
lines changed

2 files changed

+38
-6
lines changed

crates/gpui/src/platform/windows/events.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -466,12 +466,7 @@ fn handle_keyup_msg(
466466
}
467467

468468
fn handle_char_msg(wparam: WPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
469-
let Some(input) = char::from_u32(wparam.0 as u32)
470-
.filter(|c| !c.is_control())
471-
.map(String::from)
472-
else {
473-
return Some(1);
474-
};
469+
let input = parse_char_message(wparam, &state_ptr)?;
475470
with_input_handler(&state_ptr, |input_handler| {
476471
input_handler.replace_text_in_range(None, &input);
477472
});
@@ -1228,6 +1223,36 @@ fn handle_input_language_changed(
12281223
Some(0)
12291224
}
12301225

1226+
#[inline]
1227+
fn parse_char_message(wparam: WPARAM, state_ptr: &Rc<WindowsWindowStatePtr>) -> Option<String> {
1228+
let code_point = wparam.loword();
1229+
let mut lock = state_ptr.state.borrow_mut();
1230+
// https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G2630
1231+
match code_point {
1232+
0xD800..=0xDBFF => {
1233+
// High surrogate, wait for low surrogate
1234+
lock.pending_surrogate = Some(code_point);
1235+
None
1236+
}
1237+
0xDC00..=0xDFFF => {
1238+
if let Some(high_surrogate) = lock.pending_surrogate.take() {
1239+
// Low surrogate, combine with pending high surrogate
1240+
String::from_utf16(&[high_surrogate, code_point]).ok()
1241+
} else {
1242+
// Invalid low surrogate without a preceding high surrogate
1243+
log::warn!(
1244+
"Received low surrogate without a preceding high surrogate: {code_point:x}"
1245+
);
1246+
None
1247+
}
1248+
}
1249+
_ => {
1250+
lock.pending_surrogate = None;
1251+
String::from_utf16(&[code_point]).ok()
1252+
}
1253+
}
1254+
}
1255+
12311256
#[inline]
12321257
fn translate_message(handle: HWND, wparam: WPARAM, lparam: LPARAM) {
12331258
let msg = MSG {
@@ -1270,6 +1295,10 @@ where
12701295
capslock: current_capslock(),
12711296
}))
12721297
}
1298+
VK_PACKET => {
1299+
translate_message(handle, wparam, lparam);
1300+
None
1301+
}
12731302
VK_CAPITAL => {
12741303
let capslock = current_capslock();
12751304
if state

crates/gpui/src/platform/windows/window.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub struct WindowsWindowState {
4343

4444
pub callbacks: Callbacks,
4545
pub input_handler: Option<PlatformInputHandler>,
46+
pub pending_surrogate: Option<u16>,
4647
pub last_reported_modifiers: Option<Modifiers>,
4748
pub last_reported_capslock: Option<Capslock>,
4849
pub system_key_handled: bool,
@@ -105,6 +106,7 @@ impl WindowsWindowState {
105106
let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?;
106107
let callbacks = Callbacks::default();
107108
let input_handler = None;
109+
let pending_surrogate = None;
108110
let last_reported_modifiers = None;
109111
let last_reported_capslock = None;
110112
let system_key_handled = false;
@@ -126,6 +128,7 @@ impl WindowsWindowState {
126128
min_size,
127129
callbacks,
128130
input_handler,
131+
pending_surrogate,
129132
last_reported_modifiers,
130133
last_reported_capslock,
131134
system_key_handled,

0 commit comments

Comments
 (0)