1pub use iced_core::keyboard::*;
3
4use crate::UserInterface;
5use crate::core;
6use crate::core::widget::operation::{self, Operation as _};
7
8fn run_operation<Message, Theme, Renderer>(
10 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
11 renderer: &Renderer,
12 mut op: Box<dyn operation::Operation>,
13) where
14 Renderer: core::Renderer,
15{
16 loop {
17 ui.operate(renderer, op.as_mut());
18
19 match op.finish() {
20 operation::Outcome::Chain(next) => {
21 op = next;
22 }
23 _ => break,
24 }
25 }
26}
27
28fn focus_and_scroll<Message, Theme, Renderer>(
30 shift: bool,
31 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
32 renderer: &Renderer,
33) where
34 Renderer: core::Renderer,
35{
36 let op: Box<dyn operation::Operation> = if shift {
37 Box::new(operation::focusable::focus_previous::<()>())
38 } else {
39 Box::new(operation::focusable::focus_next::<()>())
40 };
41
42 run_operation(ui, renderer, op);
43
44 run_operation(
45 ui,
46 renderer,
47 Box::new(operation::focusable::scroll_focused_into_view::<()>()),
48 );
49}
50
51fn focus_and_scroll_within<Message, Theme, Renderer>(
53 shift: bool,
54 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
55 renderer: &Renderer,
56 scope: core::widget::Id,
57) where
58 Renderer: core::Renderer,
59{
60 let op: Box<dyn operation::Operation> = if shift {
61 Box::new(operation::focusable::focus_previous_within::<()>(scope))
62 } else {
63 Box::new(operation::focusable::focus_next_within::<()>(scope))
64 };
65
66 run_operation(ui, renderer, op);
67
68 run_operation(
69 ui,
70 renderer,
71 Box::new(operation::focusable::scroll_focused_into_view::<()>()),
72 );
73}
74
75pub fn handle_ctrl_tab<Message, Theme, Renderer>(
82 event: &core::Event,
83 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
84 renderer: &Renderer,
85) -> bool
86where
87 Renderer: core::Renderer,
88{
89 if let core::Event::Keyboard(core::keyboard::Event::KeyPressed {
90 key: core::keyboard::Key::Named(core::keyboard::key::Named::Tab),
91 modifiers,
92 ..
93 }) = event
94 && modifiers.control()
95 {
96 focus_and_scroll(modifiers.shift(), ui, renderer);
97 return true;
98 }
99
100 false
101}
102
103pub fn handle_tab<Message, Theme, Renderer>(
110 event: &core::Event,
111 status: core::event::Status,
112 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
113 renderer: &Renderer,
114) -> bool
115where
116 Renderer: core::Renderer,
117{
118 if status != core::event::Status::Ignored {
119 return false;
120 }
121
122 if let core::Event::Keyboard(core::keyboard::Event::KeyPressed {
123 key: core::keyboard::Key::Named(core::keyboard::key::Named::Tab),
124 modifiers,
125 ..
126 }) = event
127 {
128 focus_and_scroll(modifiers.shift(), ui, renderer);
129 return true;
130 }
131
132 false
133}
134
135pub fn handle_ctrl_tab_within<Message, Theme, Renderer>(
142 event: &core::Event,
143 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
144 renderer: &Renderer,
145 scope: core::widget::Id,
146) -> bool
147where
148 Renderer: core::Renderer,
149{
150 if let core::Event::Keyboard(core::keyboard::Event::KeyPressed {
151 key: core::keyboard::Key::Named(core::keyboard::key::Named::Tab),
152 modifiers,
153 ..
154 }) = event
155 && modifiers.control()
156 {
157 focus_and_scroll_within(modifiers.shift(), ui, renderer, scope);
158 return true;
159 }
160
161 false
162}
163
164pub fn handle_tab_within<Message, Theme, Renderer>(
171 event: &core::Event,
172 status: core::event::Status,
173 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
174 renderer: &Renderer,
175 scope: core::widget::Id,
176) -> bool
177where
178 Renderer: core::Renderer,
179{
180 if status != core::event::Status::Ignored {
181 return false;
182 }
183
184 if let core::Event::Keyboard(core::keyboard::Event::KeyPressed {
185 key: core::keyboard::Key::Named(core::keyboard::key::Named::Tab),
186 modifiers,
187 ..
188 }) = event
189 {
190 focus_and_scroll_within(modifiers.shift(), ui, renderer, scope);
191 return true;
192 }
193
194 false
195}
196
197pub fn handle_mnemonic<Message, Theme, Renderer>(
209 event: &core::Event,
210 status: core::event::Status,
211 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
212 renderer: &Renderer,
213) -> Option<core::Rectangle>
214where
215 Renderer: core::Renderer,
216{
217 if status != core::event::Status::Ignored {
218 return None;
219 }
220
221 if let core::Event::Keyboard(core::keyboard::Event::KeyPressed {
222 key: core::keyboard::Key::Character(smol),
223 modifiers,
224 ..
225 }) = event
226 {
227 if !modifiers.alt() || modifiers.control() || modifiers.logo() {
228 return None;
229 }
230
231 let ch = smol.chars().next()?;
232
233 let mut op = operation::focusable::find_mnemonic(ch);
234 ui.operate(renderer, &mut operation::black_box::<_, ()>(&mut op));
235
236 if let operation::Outcome::Some(target) = op.finish() {
237 if let Some(id) = target.id {
238 run_operation(
239 ui,
240 renderer,
241 Box::new(operation::focusable::focus::<()>(id)),
242 );
243 }
244
245 return Some(target.bounds);
246 }
247 }
248
249 None
250}
251
252pub fn handle_scroll_keys<Message, Theme, Renderer>(
260 event: &core::Event,
261 status: core::event::Status,
262 ui: &mut UserInterface<'_, Message, Theme, Renderer>,
263 renderer: &Renderer,
264) -> bool
265where
266 Renderer: core::Renderer,
267{
268 if status != core::event::Status::Ignored {
269 return false;
270 }
271
272 if let core::Event::Keyboard(core::keyboard::Event::KeyPressed {
273 key: core::keyboard::Key::Named(named),
274 modifiers,
275 ..
276 }) = event
277 {
278 use operation::focusable::ScrollAction;
279
280 let action = match named {
281 core::keyboard::key::Named::PageDown if modifiers.shift() => {
282 Some(ScrollAction::PageRight)
283 }
284 core::keyboard::key::Named::PageDown => Some(ScrollAction::PageDown),
285 core::keyboard::key::Named::PageUp if modifiers.shift() => Some(ScrollAction::PageLeft),
286 core::keyboard::key::Named::PageUp => Some(ScrollAction::PageUp),
287 core::keyboard::key::Named::ArrowDown if modifiers.shift() => {
288 Some(ScrollAction::LineRight)
289 }
290 core::keyboard::key::Named::ArrowDown => Some(ScrollAction::LineDown),
291 core::keyboard::key::Named::ArrowUp if modifiers.shift() => {
292 Some(ScrollAction::LineLeft)
293 }
294 core::keyboard::key::Named::ArrowUp => Some(ScrollAction::LineUp),
295 core::keyboard::key::Named::ArrowRight => Some(ScrollAction::LineRight),
296 core::keyboard::key::Named::ArrowLeft => Some(ScrollAction::LineLeft),
297 core::keyboard::key::Named::Home if modifiers.shift() => Some(ScrollAction::ShiftHome),
298 core::keyboard::key::Named::Home => Some(ScrollAction::Home),
299 core::keyboard::key::Named::End if modifiers.shift() => Some(ScrollAction::ShiftEnd),
300 core::keyboard::key::Named::End => Some(ScrollAction::End),
301 _ => None,
302 };
303
304 if let Some(action) = action {
305 run_operation(
306 ui,
307 renderer,
308 Box::new(operation::focusable::scroll_focused_ancestor::<()>(action)),
309 );
310 return true;
311 }
312 }
313
314 false
315}