iced_core/input_method.rs
1//! Listen to input method events.
2use crate::{Pixels, Point};
3
4use std::ops::Range;
5
6/// The input method strategy of a widget.
7#[derive(Debug, Clone, PartialEq)]
8pub enum InputMethod<T = String> {
9 /// Input method is disabled.
10 Disabled,
11 /// Input method is enabled.
12 Enabled {
13 /// The position at which the input method dialog should be placed.
14 position: Point,
15 /// The [`Purpose`] of the input method.
16 purpose: Purpose,
17 /// The preedit to overlay on top of the input method dialog, if needed.
18 ///
19 /// Ideally, your widget will show pre-edits on-the-spot; but, since that can
20 /// be tricky, you can instead provide the current pre-edit here and the
21 /// runtime will display it as an overlay (i.e. "Over-the-spot IME").
22 preedit: Option<Preedit<T>>,
23 },
24}
25
26/// The pre-edit of an [`InputMethod`].
27#[derive(Debug, Clone, PartialEq, Default)]
28pub struct Preedit<T = String> {
29 /// The current content.
30 pub content: T,
31 /// The selected range of the content.
32 pub selection: Option<Range<usize>>,
33 /// The text size of the content.
34 pub text_size: Option<Pixels>,
35}
36
37impl<T> Preedit<T> {
38 /// Creates a new empty [`Preedit`].
39 pub fn new() -> Self
40 where
41 T: Default,
42 {
43 Self::default()
44 }
45
46 /// Turns a [`Preedit`] into its owned version.
47 pub fn to_owned(&self) -> Preedit
48 where
49 T: AsRef<str>,
50 {
51 Preedit {
52 content: self.content.as_ref().to_owned(),
53 selection: self.selection.clone(),
54 text_size: self.text_size,
55 }
56 }
57}
58
59impl Preedit {
60 /// Borrows the contents of a [`Preedit`].
61 pub fn as_ref(&self) -> Preedit<&str> {
62 Preedit {
63 content: &self.content,
64 selection: self.selection.clone(),
65 text_size: self.text_size,
66 }
67 }
68}
69
70/// The purpose of an [`InputMethod`].
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
72pub enum Purpose {
73 /// No special hints for the IME (default).
74 #[default]
75 Normal,
76 /// The IME is used for secure input (e.g. passwords).
77 Secure,
78 /// The IME is used to input into a terminal.
79 ///
80 /// For example, that could alter OSK on Wayland to show extra buttons.
81 Terminal,
82}
83
84impl InputMethod {
85 /// Merges two [`InputMethod`] strategies, prioritizing the first one when both open:
86 /// ```
87 /// # use iced_core::input_method::{InputMethod, Purpose, Preedit};
88 /// # use iced_core::Point;
89 ///
90 /// let open = InputMethod::Enabled {
91 /// position: Point::ORIGIN,
92 /// purpose: Purpose::Normal,
93 /// preedit: Some(Preedit { content: "1".to_owned(), selection: None, text_size: None }),
94 /// };
95 ///
96 /// let open_2 = InputMethod::Enabled {
97 /// position: Point::ORIGIN,
98 /// purpose: Purpose::Secure,
99 /// preedit: Some(Preedit { content: "2".to_owned(), selection: None, text_size: None }),
100 /// };
101 ///
102 /// let mut ime = InputMethod::Disabled;
103 ///
104 /// ime.merge(&open);
105 /// assert_eq!(ime, open);
106 ///
107 /// ime.merge(&open_2);
108 /// assert_eq!(ime, open);
109 /// ```
110 pub fn merge<T: AsRef<str>>(&mut self, other: &InputMethod<T>) {
111 if let InputMethod::Enabled { .. } = self {
112 return;
113 }
114
115 *self = other.to_owned();
116 }
117
118 /// Returns true if the [`InputMethod`] is open.
119 pub fn is_enabled(&self) -> bool {
120 matches!(self, Self::Enabled { .. })
121 }
122}
123
124impl<T> InputMethod<T> {
125 /// Turns an [`InputMethod`] into its owned version.
126 pub fn to_owned(&self) -> InputMethod
127 where
128 T: AsRef<str>,
129 {
130 match self {
131 Self::Disabled => InputMethod::Disabled,
132 Self::Enabled {
133 position,
134 purpose,
135 preedit,
136 } => InputMethod::Enabled {
137 position: *position,
138 purpose: *purpose,
139 preedit: preedit.as_ref().map(Preedit::to_owned),
140 },
141 }
142 }
143}
144
145/// Describes [input method](https://en.wikipedia.org/wiki/Input_method) events.
146///
147/// This is also called a "composition event".
148///
149/// Most keypresses using a latin-like keyboard layout simply generate a
150/// [`keyboard::Event::KeyPressed`](crate::keyboard::Event::KeyPressed).
151/// However, one couldn't possibly have a key for every single
152/// unicode character that the user might want to type. The solution operating systems employ is
153/// to allow the user to type these using _a sequence of keypresses_ instead.
154#[derive(Debug, Clone, PartialEq, Eq, Hash)]
155pub enum Event {
156 /// Notifies when the IME was opened.
157 ///
158 /// After getting this event you could receive [`Preedit`][Self::Preedit] and
159 /// [`Commit`][Self::Commit] events. You should also start performing IME related requests
160 /// like [`Shell::request_input_method`].
161 ///
162 /// [`Shell::request_input_method`]: crate::Shell::request_input_method
163 Opened,
164
165 /// Notifies when a new composing text should be set at the cursor position.
166 ///
167 /// The value represents a pair of the preedit string and the cursor begin position and end
168 /// position. When it's `None`, the cursor should be hidden. When `String` is an empty string
169 /// this indicates that preedit was cleared.
170 ///
171 /// The cursor range is byte-wise indexed.
172 Preedit(String, Option<Range<usize>>),
173
174 /// Notifies when text should be inserted into the editor widget.
175 ///
176 /// Right before this event, an empty [`Self::Preedit`] event will be issued.
177 Commit(String),
178
179 /// Notifies when the IME was disabled.
180 ///
181 /// After receiving this event you won't get any more [`Preedit`][Self::Preedit] or
182 /// [`Commit`][Self::Commit] events until the next [`Opened`][Self::Opened] event. You should
183 /// also stop issuing IME related requests like [`Shell::request_input_method`] and clear
184 /// pending preedit text.
185 ///
186 /// [`Shell::request_input_method`]: crate::Shell::request_input_method
187 Closed,
188}