diff --git a/CHANGELOG.md b/CHANGELOG.md index d6372d4c..57f574e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- On Windows, implement `Window::set_ime_position`. - **Breaking:** On Windows, Renamed `WindowBuilderExtWindows`'s `is_dark_mode` to `theme`. - On Windows, add `WindowBuilderExtWindows::with_theme` to set a preferred theme. - On Windows, fix bug causing message boxes to appear delayed. diff --git a/Cargo.toml b/Cargo.toml index f501f8c1..068b2bc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ features = [ "commctrl", "dwmapi", "errhandlingapi", + "imm", "hidusage", "libloaderapi", "objbase", diff --git a/examples/set_ime_position.rs b/examples/set_ime_position.rs new file mode 100644 index 00000000..1b2eecc3 --- /dev/null +++ b/examples/set_ime_position.rs @@ -0,0 +1,54 @@ +use simple_logger::SimpleLogger; +use winit::{ + dpi::PhysicalPosition, + event::{ElementState, Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; + +fn main() { + SimpleLogger::new().init().unwrap(); + let event_loop = EventLoop::new(); + + let window = WindowBuilder::new().build(&event_loop).unwrap(); + window.set_title("A fantastic window!"); + + println!("Ime position will system default"); + println!("Click to set ime position to cursor's"); + + let mut cursor_position = PhysicalPosition::new(0.0, 0.0); + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { + event: WindowEvent::CursorMoved { position, .. }, + .. + } => { + cursor_position = position; + } + Event::WindowEvent { + event: + WindowEvent::MouseInput { + state: ElementState::Released, + .. + }, + .. + } => { + println!( + "Setting ime position to {}, {}", + cursor_position.x, cursor_position.y + ); + window.set_ime_position(cursor_position); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + *control_flow = ControlFlow::Exit; + return; + } + _ => (), + } + }); +} diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 580fa958..c444863e 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -18,7 +18,9 @@ use winapi::{ windef::{HWND, POINT, RECT}, }, um::{ - combaseapi, dwmapi, libloaderapi, + combaseapi, dwmapi, + imm::{CFS_POINT, COMPOSITIONFORM}, + libloaderapi, objbase::COINIT_APARTMENTTHREADED, ole2, oleidl::LPDROPTARGET, @@ -616,9 +618,25 @@ impl Window { self.window_state.lock().taskbar_icon = taskbar_icon; } + pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) { + if unsafe { winuser::GetSystemMetrics(winuser::SM_IMMENABLED) } != 0 { + let mut composition_form = COMPOSITIONFORM { + dwStyle: CFS_POINT, + ptCurrentPos: POINT { x, y }, + rcArea: unsafe { mem::zeroed() }, + }; + unsafe { + let himc = winapi::um::imm::ImmGetContext(self.window.0); + winapi::um::imm::ImmSetCompositionWindow(himc, &mut composition_form); + winapi::um::imm::ImmReleaseContext(self.window.0, himc); + } + } + } + #[inline] - pub fn set_ime_position(&self, _position: Position) { - warn!("`Window::set_ime_position` is ignored on Windows") + pub fn set_ime_position(&self, spot: Position) { + let (x, y) = spot.to_physical::(self.scale_factor()).into(); + self.set_ime_position_physical(x, y); } #[inline] diff --git a/src/window.rs b/src/window.rs index 8cf6e066..9ed2de06 100644 --- a/src/window.rs +++ b/src/window.rs @@ -677,7 +677,7 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS / Android / Web / Windows:** Unsupported. + /// - **iOS / Android / Web:** Unsupported. #[inline] pub fn set_ime_position>(&self, position: P) { self.window.set_ime_position(position.into())