Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve IME documentation #2258

Merged
merged 4 commits into from
May 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/ime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
58 changes: 54 additions & 4 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
use instant::Instant;
use std::path::PathBuf;

#[cfg(doc)]
use crate::window::Window;
use crate::{
dpi::{PhysicalPosition, PhysicalSize},
platform_impl,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should note: This part is technically not true, currently our macOS implementation gives Ime::Preedit("a b", Some(3), Some(3)). But it should give Ime::Preedit("a b", Some(1), Some(1)).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can ensure you that it'll work like that on Wayland at least, and that's how it should be on macOS as well? If it doesn't work like that it's likely a macOS bug, though, not really a blocking one...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's a bug, should be possible to fix just has to do some UTF-16 to UTF-8 encoding that I didn't really see how to do easily.

/// // 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.
Expand All @@ -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,
}

Expand Down
10 changes: 10 additions & 0 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<P: Into<Position>>(&self, position: P) {
self.window.set_ime_position(position.into())
Expand Down