diff --git a/examples/ime.rs b/examples/ime.rs index 76231766f8..5f38447a85 100644 --- a/examples/ime.rs +++ b/examples/ime.rs @@ -13,8 +13,8 @@ fn main() { .init() .unwrap(); - println!("Ime position will system default"); - println!("Click to set ime position to cursor's"); + println!("IME position will system default"); + println!("Click to set IME position to cursor's"); println!("Press F2 to toggle IME. See the documentation of `set_ime_allowed` for more info"); let event_loop = EventLoop::new(); diff --git a/src/event.rs b/src/event.rs index 709eb030d2..65e556a2f7 100644 --- a/src/event.rs +++ b/src/event.rs @@ -36,6 +36,8 @@ use instant::Instant; use std::path::PathBuf; +#[cfg(doc)] +use crate::window::Window; use crate::{ dpi::{PhysicalPosition, PhysicalSize}, platform_impl, @@ -93,8 +95,7 @@ pub enum Event<'a, T: 'static> { /// This gets triggered in two scenarios: /// - The OS has performed an operation that's invalidated the window's contents (such as /// resizing the window). - /// - The application has explicitly requested a redraw via - /// [`Window::request_redraw`](crate::window::Window::request_redraw). + /// - The application has explicitly requested a redraw via [`Window::request_redraw`]. /// /// During each iteration of the event loop, Winit will aggregate duplicate redraw requests /// into a single event, to help avoid duplicating rendering work. @@ -206,7 +207,7 @@ pub enum StartCause { Init, } -/// Describes an event from a `Window`. +/// Describes an event from a [`Window`]. #[derive(Debug, PartialEq)] pub enum WindowEvent<'a> { /// The size of the window has changed. Contains the client area's new dimensions. @@ -240,6 +241,8 @@ pub enum WindowEvent<'a> { HoveredFileCancelled, /// The window received a unicode character. + /// + /// See also the [`Ime`](Self::Ime) event for more complex character sequences. ReceivedCharacter(char), /// The window gained or lost focus. @@ -272,6 +275,8 @@ pub enum WindowEvent<'a> { /// An event from input method. /// + /// **Note :** You have to explicitly enable this event using [`Window::set_ime_allowed`]. + /// /// Platform-specific behavior: /// - **iOS / Android / Web :** Unsupported. Ime(Ime), @@ -634,11 +639,49 @@ pub struct KeyboardInput { pub modifiers: ModifiersState, } -/// Describes an event from input method. +/// Describes [input method](https://en.wikipedia.org/wiki/Input_method) events. +/// +/// This is also called a "composition event". +/// +/// Most keypresses using a latin-like keyboard layout simply generate a [`WindowEvent::ReceivedCharacter`]. +/// However, one couldn't possibly have a key for every single unicode character that the user might want to type +/// - so the solution operating systems employ is to allow the user to type these using _a sequence of keypresses_ instead. +/// +/// A prominent example of this is accents - many keyboard layouts allow you to first click the "accent key", and then +/// the character you want to apply the accent to. This will generate the following event sequence: +/// ```ignore +/// // Press "`" key +/// Ime::Preedit("`", Some(0), Some(0)) +/// // Press "E" key +/// Ime::Commit("é") +/// ``` +/// +/// Additionally, certain input devices are configured to display a candidate box that allow the user to select the +/// desired character interactively. (To properly position this box, you must use [`Window::set_ime_position`].) +/// +/// An example of a keyboard layout which uses candidate boxes is pinyin. On a latin keybaord the following event +/// sequence could be obtained: +/// ```ignore +/// // Press "A" key +/// Ime::Preedit("a", Some(1), Some(1)) +/// // Press "B" key +/// Ime::Preedit("a b", Some(3), Some(3)) +/// // Press left arrow key +/// Ime::Preedit("a b", Some(1), Some(1)) +/// // Press space key +/// Ime::Preedit("啊b", Some(3), Some(3)) +/// // Press space key +/// Ime::Commit("啊不") +/// ``` +/// #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Ime { /// Notifies when the IME was enabled. + /// + /// After getting this event you could receive [`Preedit`](Self::Preedit) and + /// [`Commit`](Self::Commit) events. You should also start performing IME related requests + /// like [`Window::set_ime_position`]. Enabled, /// Notifies when a new composing text should be set at the cursor position. @@ -650,9 +693,16 @@ pub enum Ime { Preedit(String, Option<(usize, usize)>), /// Notifies when text should be inserted into the editor widget. + /// + /// Any pending [`Preedit`](Self::Preedit) must be cleared. Commit(String), /// Notifies when the IME was disabled. + /// + /// After receiving this event you won't get any more [`Preedit`](Self::Preedit) or + /// [`Commit`](Self::Commit) events until the next [`Enabled`](Self::Enabled) event. You can + /// also stop issuing IME related requests like [`Window::set_ime_position`] and clear pending + /// preedit text. Disabled, } diff --git a/src/window.rs b/src/window.rs index b07ca7b184..96189872f8 100644 --- a/src/window.rs +++ b/src/window.rs @@ -814,6 +814,13 @@ impl Window { /// Sets location of IME candidate box in client area coordinates relative to the top left. /// + /// This is the window / popup / overlay that allows you to select the desired characters. + /// The look of this box may differ between input devices, even on the same platform. + /// + /// (Apple's official term is "candidate window", see their [chinese] and [japanese] guides). + /// + /// ## Example + /// /// ```no_run /// # use winit::dpi::{LogicalPosition, PhysicalPosition}; /// # use winit::event_loop::EventLoop; @@ -830,6 +837,9 @@ impl Window { /// ## Platform-specific /// /// - **iOS / Android / Web:** Unsupported. + /// + /// [chinese]: https://support.apple.com/guide/chinese-input-method/use-the-candidate-window-cim12992/104/mac/12.0 + /// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0 #[inline] pub fn set_ime_position>(&self, position: P) { self.window.set_ime_position(position.into())