2025-01-10 07:12:31 +09:00
|
|
|
//! Listen to input method events.
|
2025-05-01 13:03:54 +00:00
|
|
|
use crate::{Pixels, Rectangle};
|
2025-02-02 20:45:29 +01:00
|
|
|
|
2025-02-02 17:55:16 +01:00
|
|
|
use std::ops::Range;
|
2025-01-10 07:12:31 +09:00
|
|
|
|
2025-02-02 20:45:29 +01:00
|
|
|
/// The input method strategy of a widget.
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum InputMethod<T = String> {
|
2025-02-12 08:46:35 +01:00
|
|
|
/// Input method is disabled.
|
2025-02-02 20:45:29 +01:00
|
|
|
Disabled,
|
2025-02-12 08:46:35 +01:00
|
|
|
/// Input method is enabled.
|
|
|
|
|
Enabled {
|
2025-05-01 13:03:54 +00:00
|
|
|
/// The area of the cursor of the input method.
|
|
|
|
|
///
|
|
|
|
|
/// This area should not be covered.
|
|
|
|
|
cursor: Rectangle,
|
2025-02-02 20:45:29 +01:00
|
|
|
/// The [`Purpose`] of the input method.
|
|
|
|
|
purpose: Purpose,
|
|
|
|
|
/// The preedit to overlay on top of the input method dialog, if needed.
|
|
|
|
|
///
|
|
|
|
|
/// Ideally, your widget will show pre-edits on-the-spot; but, since that can
|
|
|
|
|
/// be tricky, you can instead provide the current pre-edit here and the
|
|
|
|
|
/// runtime will display it as an overlay (i.e. "Over-the-spot IME").
|
2025-02-03 02:33:40 +01:00
|
|
|
preedit: Option<Preedit<T>>,
|
2025-02-02 20:45:29 +01:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-03 02:33:40 +01:00
|
|
|
/// The pre-edit of an [`InputMethod`].
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default)]
|
|
|
|
|
pub struct Preedit<T = String> {
|
|
|
|
|
/// The current content.
|
|
|
|
|
pub content: T,
|
|
|
|
|
/// The selected range of the content.
|
|
|
|
|
pub selection: Option<Range<usize>>,
|
2025-02-06 01:50:25 +09:00
|
|
|
/// The text size of the content.
|
|
|
|
|
pub text_size: Option<Pixels>,
|
2025-02-03 02:33:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> Preedit<T> {
|
|
|
|
|
/// Creates a new empty [`Preedit`].
|
2025-02-06 09:57:01 +09:00
|
|
|
pub fn new() -> Self
|
2025-02-03 02:33:40 +01:00
|
|
|
where
|
|
|
|
|
T: Default,
|
|
|
|
|
{
|
2025-02-06 09:57:01 +09:00
|
|
|
Self::default()
|
2025-02-03 02:33:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Turns a [`Preedit`] into its owned version.
|
|
|
|
|
pub fn to_owned(&self) -> Preedit
|
|
|
|
|
where
|
|
|
|
|
T: AsRef<str>,
|
|
|
|
|
{
|
|
|
|
|
Preedit {
|
|
|
|
|
content: self.content.as_ref().to_owned(),
|
|
|
|
|
selection: self.selection.clone(),
|
2025-02-06 01:50:25 +09:00
|
|
|
text_size: self.text_size,
|
2025-02-03 02:33:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Preedit {
|
|
|
|
|
/// Borrows the contents of a [`Preedit`].
|
|
|
|
|
pub fn as_ref(&self) -> Preedit<&str> {
|
|
|
|
|
Preedit {
|
|
|
|
|
content: &self.content,
|
|
|
|
|
selection: self.selection.clone(),
|
2025-02-06 01:50:25 +09:00
|
|
|
text_size: self.text_size,
|
2025-02-03 02:33:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-02 20:45:29 +01:00
|
|
|
/// The purpose of an [`InputMethod`].
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
|
|
|
|
pub enum Purpose {
|
|
|
|
|
/// No special hints for the IME (default).
|
|
|
|
|
#[default]
|
|
|
|
|
Normal,
|
|
|
|
|
/// The IME is used for secure input (e.g. passwords).
|
|
|
|
|
Secure,
|
|
|
|
|
/// The IME is used to input into a terminal.
|
|
|
|
|
///
|
|
|
|
|
/// For example, that could alter OSK on Wayland to show extra buttons.
|
|
|
|
|
Terminal,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl InputMethod {
|
2025-02-03 17:12:08 +01:00
|
|
|
/// Merges two [`InputMethod`] strategies, prioritizing the first one when both open:
|
2025-02-02 20:45:29 +01:00
|
|
|
/// ```
|
2025-02-03 17:12:08 +01:00
|
|
|
/// # use iced_core::input_method::{InputMethod, Purpose, Preedit};
|
2025-11-25 22:37:44 +01:00
|
|
|
/// # use iced_core::{Point, Rectangle, Size};
|
2025-02-02 20:45:29 +01:00
|
|
|
///
|
2025-02-12 08:46:35 +01:00
|
|
|
/// let open = InputMethod::Enabled {
|
2025-11-25 22:37:44 +01:00
|
|
|
/// cursor: Rectangle::new(Point::ORIGIN, Size::UNIT),
|
2025-02-02 20:45:29 +01:00
|
|
|
/// purpose: Purpose::Normal,
|
2025-02-06 01:50:25 +09:00
|
|
|
/// preedit: Some(Preedit { content: "1".to_owned(), selection: None, text_size: None }),
|
2025-02-02 20:45:29 +01:00
|
|
|
/// };
|
|
|
|
|
///
|
2025-02-12 08:46:35 +01:00
|
|
|
/// let open_2 = InputMethod::Enabled {
|
2025-11-25 22:37:44 +01:00
|
|
|
/// cursor: Rectangle::new(Point::ORIGIN, Size::UNIT),
|
2025-02-02 20:45:29 +01:00
|
|
|
/// purpose: Purpose::Secure,
|
2025-02-06 01:50:25 +09:00
|
|
|
/// preedit: Some(Preedit { content: "2".to_owned(), selection: None, text_size: None }),
|
2025-02-02 20:45:29 +01:00
|
|
|
/// };
|
|
|
|
|
///
|
|
|
|
|
/// let mut ime = InputMethod::Disabled;
|
|
|
|
|
///
|
|
|
|
|
/// ime.merge(&open);
|
|
|
|
|
/// assert_eq!(ime, open);
|
|
|
|
|
///
|
|
|
|
|
/// ime.merge(&open_2);
|
2025-02-03 17:12:08 +01:00
|
|
|
/// assert_eq!(ime, open);
|
2025-02-02 20:45:29 +01:00
|
|
|
/// ```
|
|
|
|
|
pub fn merge<T: AsRef<str>>(&mut self, other: &InputMethod<T>) {
|
2025-02-12 08:46:35 +01:00
|
|
|
if let InputMethod::Enabled { .. } = self {
|
|
|
|
|
return;
|
2025-02-03 17:12:08 +01:00
|
|
|
}
|
2025-02-12 08:46:35 +01:00
|
|
|
|
|
|
|
|
*self = other.to_owned();
|
2025-02-03 17:12:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns true if the [`InputMethod`] is open.
|
2025-02-12 08:46:35 +01:00
|
|
|
pub fn is_enabled(&self) -> bool {
|
|
|
|
|
matches!(self, Self::Enabled { .. })
|
2025-02-03 17:12:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> InputMethod<T> {
|
|
|
|
|
/// Turns an [`InputMethod`] into its owned version.
|
|
|
|
|
pub fn to_owned(&self) -> InputMethod
|
|
|
|
|
where
|
|
|
|
|
T: AsRef<str>,
|
|
|
|
|
{
|
|
|
|
|
match self {
|
|
|
|
|
Self::Disabled => InputMethod::Disabled,
|
2025-02-12 08:46:35 +01:00
|
|
|
Self::Enabled {
|
2025-05-01 13:03:54 +00:00
|
|
|
cursor,
|
2025-02-02 20:45:29 +01:00
|
|
|
purpose,
|
|
|
|
|
preedit,
|
2025-02-12 08:46:35 +01:00
|
|
|
} => InputMethod::Enabled {
|
2025-05-01 13:03:54 +00:00
|
|
|
cursor: *cursor,
|
2025-02-03 17:12:08 +01:00
|
|
|
purpose: *purpose,
|
|
|
|
|
preedit: preedit.as_ref().map(Preedit::to_owned),
|
|
|
|
|
},
|
2025-02-02 20:45:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-02 17:55:16 +01:00
|
|
|
/// Describes [input method](https://en.wikipedia.org/wiki/Input_method) events.
|
2025-01-10 07:12:31 +09:00
|
|
|
///
|
2025-02-02 17:55:16 +01:00
|
|
|
/// This is also called a "composition event".
|
2025-01-10 07:12:31 +09:00
|
|
|
///
|
2025-02-02 17:55:16 +01:00
|
|
|
/// Most keypresses using a latin-like keyboard layout simply generate a
|
2025-02-02 20:45:29 +01:00
|
|
|
/// [`keyboard::Event::KeyPressed`](crate::keyboard::Event::KeyPressed).
|
|
|
|
|
/// However, one couldn't possibly have a key for every single
|
|
|
|
|
/// unicode character that the user might want to type. The solution operating systems employ is
|
|
|
|
|
/// to allow the user to type these using _a sequence of keypresses_ instead.
|
2025-02-02 17:55:16 +01:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
2025-01-10 07:12:31 +09:00
|
|
|
pub enum Event {
|
2025-02-02 20:45:29 +01:00
|
|
|
/// Notifies when the IME was opened.
|
2025-02-02 17:55:16 +01:00
|
|
|
///
|
|
|
|
|
/// After getting this event you could receive [`Preedit`][Self::Preedit] and
|
|
|
|
|
/// [`Commit`][Self::Commit] events. You should also start performing IME related requests
|
2025-02-02 20:45:29 +01:00
|
|
|
/// like [`Shell::request_input_method`].
|
|
|
|
|
///
|
|
|
|
|
/// [`Shell::request_input_method`]: crate::Shell::request_input_method
|
|
|
|
|
Opened,
|
2025-01-10 07:12:31 +09:00
|
|
|
|
2025-02-02 17:55:16 +01:00
|
|
|
/// Notifies when a new composing text should be set at the cursor position.
|
|
|
|
|
///
|
|
|
|
|
/// The value represents a pair of the preedit string and the cursor begin position and end
|
|
|
|
|
/// position. When it's `None`, the cursor should be hidden. When `String` is an empty string
|
|
|
|
|
/// this indicates that preedit was cleared.
|
|
|
|
|
///
|
|
|
|
|
/// The cursor range is byte-wise indexed.
|
|
|
|
|
Preedit(String, Option<Range<usize>>),
|
2025-01-10 07:12:31 +09:00
|
|
|
|
2025-02-02 17:55:16 +01:00
|
|
|
/// Notifies when text should be inserted into the editor widget.
|
|
|
|
|
///
|
2025-02-02 20:45:29 +01:00
|
|
|
/// Right before this event, an empty [`Self::Preedit`] event will be issued.
|
2025-01-10 07:12:31 +09:00
|
|
|
Commit(String),
|
|
|
|
|
|
2025-02-02 17:55:16 +01:00
|
|
|
/// Notifies when the IME was disabled.
|
|
|
|
|
///
|
|
|
|
|
/// After receiving this event you won't get any more [`Preedit`][Self::Preedit] or
|
2025-02-02 20:45:29 +01:00
|
|
|
/// [`Commit`][Self::Commit] events until the next [`Opened`][Self::Opened] event. You should
|
|
|
|
|
/// also stop issuing IME related requests like [`Shell::request_input_method`] and clear
|
2025-02-02 17:55:16 +01:00
|
|
|
/// pending preedit text.
|
2025-02-02 20:45:29 +01:00
|
|
|
///
|
|
|
|
|
/// [`Shell::request_input_method`]: crate::Shell::request_input_method
|
|
|
|
|
Closed,
|
2025-01-10 07:12:31 +09:00
|
|
|
}
|