@@ -93,6 +93,7 @@ pub(crate) fn handle_msg(
WM_IME_COMPOSITION => handle_ime_composition(handle, lparam, state_ptr),
WM_SETCURSOR => handle_set_cursor(lparam, state_ptr),
WM_SETTINGCHANGE => handle_system_settings_changed(handle, lparam, state_ptr),
+ WM_INPUTLANGCHANGE => handle_input_language_changed(lparam, state_ptr),
WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
_ => None,
};
@@ -1279,6 +1280,18 @@ fn handle_system_theme_changed(
Some(0)
}
+fn handle_input_language_changed(
+ lparam: LPARAM,
+ state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+ let thread = state_ptr.main_thread_id_win32;
+ let validation = state_ptr.validation_number;
+ unsafe {
+ PostThreadMessageW(thread, WM_INPUTLANGCHANGE, WPARAM(validation), lparam).log_err();
+ }
+ Some(0)
+}
+
fn parse_syskeydown_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
let modifiers = current_modifiers();
let vk_code = wparam.loword();
@@ -33,8 +33,8 @@ use crate::{platform::blade::BladeContext, *};
pub(crate) struct WindowsPlatform {
state: RefCell<WindowsPlatformState>,
raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
- gpu_context: BladeContext,
// The below members will never change throughout the entire lifecycle of the app.
+ gpu_context: BladeContext,
icon: HICON,
main_receiver: flume::Receiver<Runnable>,
background_executor: BackgroundExecutor,
@@ -62,6 +62,7 @@ struct PlatformCallbacks {
app_menu_action: Option<Box<dyn FnMut(&dyn Action)>>,
will_open_app_menu: Option<Box<dyn FnMut()>>,
validate_app_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
+ keyboard_layout_change: Option<Box<dyn FnMut()>>,
}
impl WindowsPlatformState {
@@ -201,6 +202,19 @@ impl WindowsPlatform {
}
}
+ fn handle_input_lang_change(&self) {
+ let mut lock = self.state.borrow_mut();
+ if let Some(mut callback) = lock.callbacks.keyboard_layout_change.take() {
+ drop(lock);
+ callback();
+ self.state
+ .borrow_mut()
+ .callbacks
+ .keyboard_layout_change
+ .get_or_insert(callback);
+ }
+ }
+
// Returns true if the app should quit.
fn handle_events(&self) -> bool {
let mut msg = MSG::default();
@@ -208,7 +222,8 @@ impl WindowsPlatform {
while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() {
match msg.message {
WM_QUIT => return true,
- WM_GPUI_CLOSE_ONE_WINDOW
+ WM_INPUTLANGCHANGE
+ | WM_GPUI_CLOSE_ONE_WINDOW
| WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD
| WM_GPUI_DOCK_MENU_ACTION => {
if self.handle_gpui_evnets(msg.message, msg.wParam, msg.lParam, &msg) {
@@ -247,6 +262,7 @@ impl WindowsPlatform {
}
WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD => self.run_foreground_task(),
WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _),
+ WM_INPUTLANGCHANGE => self.handle_input_lang_change(),
_ => unreachable!(),
}
false
@@ -305,8 +321,8 @@ impl Platform for WindowsPlatform {
)
}
- fn on_keyboard_layout_change(&self, _callback: Box<dyn FnMut()>) {
- // todo(windows)
+ fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) {
+ self.state.borrow_mut().callbacks.keyboard_layout_change = Some(callback);
}
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {