1use super::{
2 FocusManager, IAccessKeyHandler, IMainMenu, InputElement, Key, KeyEventArgs, KeyModifiers, PointerPressedEventArgs,
3};
4use crate::interactivity::{RoutedEvent, RoutedEventArgs, RoutingStrategies};
5use crate::reactive::IDisposable;
6use crate::{
7 ferro_property, ferro_routed_event, ferro_routed_event_args, AttachedProperty, FerroProperty, Ref,
8 StyledPropertyOptions, Visual, WeakRef,
9};
10use std::cell::{Cell, RefCell};
11use std::collections::VecDeque;
12use std::rc::{Rc, Weak};
13
14type Element = Ref<InputElement>;
15
16#[derive(Clone)]
19pub struct AccessKeyPressedEventArgs {
20 base: RoutedEventArgs,
21 target: Rc<RefCell<Option<Element>>>,
22 key: String,
23}
24
25ferro_routed_event_args!(AccessKeyPressedEventArgs: RoutedEventArgs);
26
27impl AccessKeyPressedEventArgs {
28 pub fn new(key: &str) -> Self {
30 Self {
31 base: RoutedEventArgs::with_event(AccessKeyHandler::access_key_pressed_event()),
32 target: Rc::new(RefCell::new(None)),
33 key: key.to_string(),
34 }
35 }
36
37 pub fn target(&self) -> Option<Element> {
39 self.target.borrow().clone()
40 }
41
42 pub fn set_target(&self, value: Option<Element>) {
44 let old = self.target.replace(value);
45 drop(old);
46 }
47
48 pub fn key(&self) -> &str {
50 &self.key
51 }
52}
53
54#[derive(Clone)]
57pub struct AccessKeyEventArgs {
58 base: RoutedEventArgs,
59 key: String,
60 is_multiple: bool,
61}
62
63ferro_routed_event_args!(AccessKeyEventArgs: RoutedEventArgs);
64
65impl AccessKeyEventArgs {
66 pub fn new(key: &str, is_multiple: bool) -> Self {
69 Self {
70 base: RoutedEventArgs::with_event(AccessKeyHandler::access_key_event()),
71 key: key.to_string(),
72 is_multiple,
73 }
74 }
75
76 pub fn key(&self) -> &str {
78 &self.key
79 }
80
81 pub fn is_multiple(&self) -> bool {
83 self.is_multiple
84 }
85}
86
87pub struct AccessKeyRegistration {
89 target: WeakRef<InputElement>,
90 key: String,
91}
92
93impl AccessKeyRegistration {
94 pub fn new(key: String, target: WeakRef<InputElement>) -> Self {
96 Self { target, key }
97 }
98
99 pub fn key(&self) -> &str {
101 &self.key
102 }
103
104 pub fn get_input_element(&self) -> Option<Element> {
106 self.target.upgrade()
107 }
108}
109
110#[derive(Clone, Copy, PartialEq, Eq)]
111enum ProcessKeyResult {
112 NoMatch,
113 MoreMatches,
114 LastMatch,
115}
116
117pub struct AccessKeyHandler {
119 this: Weak<AccessKeyHandler>,
120 registrations: RefCell<Vec<AccessKeyRegistration>>,
122 owner: RefCell<Option<WeakRef<InputElement>>>,
124 showing_access_keys: Cell<bool>,
126 ignore_alt_up: Cell<bool>,
128 alt_is_down: Cell<bool>,
130 restore_focus_element: RefCell<Option<WeakRef<InputElement>>>,
132 main_menu: RefCell<Option<Rc<dyn IMainMenu>>>,
134 main_menu_closed: RefCell<Option<Rc<dyn IDisposable>>>,
135}
136
137crate::ferro_static_type!(AccessKeyHandler);
138
139impl AccessKeyHandler {
140 ferro_routed_event!(
141 pub fn access_key_event() -> RoutedEvent<AccessKeyEventArgs> {
144 RoutedEvent::register::<AccessKeyHandler, _>("AccessKey", RoutingStrategies::BUBBLE)
145 }
146 );
147
148 ferro_routed_event!(
149 pub fn access_key_pressed_event() -> RoutedEvent<AccessKeyPressedEventArgs> {
152 RoutedEvent::register::<AccessKeyHandler, _>("AccessKeyPressed", RoutingStrategies::BUBBLE)
153 }
154 );
155
156}
157
158crate::ferro_properties! { impl AccessKeyHandler {
159 ferro_property!(
160 pub fn show_access_key_property() -> AttachedProperty<bool> {
163 FerroProperty::register_attached_with::<AccessKeyHandler, Visual, _>(
164 "ShowAccessKey",
165 StyledPropertyOptions::new(false).inherits(true),
166 )
167 }
168 );
169} }
170
171impl AccessKeyHandler {
172 pub fn new() -> Rc<AccessKeyHandler> {
174 Rc::new_cyclic(|this| AccessKeyHandler {
175 this: this.clone(),
176 registrations: RefCell::new(Vec::new()),
177 owner: RefCell::new(None),
178 showing_access_keys: Cell::new(false),
179 ignore_alt_up: Cell::new(false),
180 alt_is_down: Cell::new(false),
181 restore_focus_element: RefCell::new(None),
182 main_menu: RefCell::new(None),
183 main_menu_closed: RefCell::new(None),
184 })
185 }
186
187 pub fn registration_count(&self) -> usize {
190 self.registrations.borrow().len()
191 }
192
193 fn owner(&self) -> Option<Element> {
194 self.owner.borrow().as_ref().and_then(WeakRef::upgrade)
195 }
196
197 pub fn registrations(&self) -> Vec<(String, Element)> {
200 self.registrations
201 .borrow()
202 .iter()
203 .filter_map(|registration| {
204 registration.get_input_element().map(|element| (registration.key().to_owned(), element))
205 })
206 .collect()
207 }
208
209 fn set_owner_without_handlers(&self, owner: &Element) {
214 if self.owner.borrow().is_some() {
215 panic!("AccessKeyHandler owner has already been set.");
216 }
217
218 *self.owner.borrow_mut() = Some(owner.downgrade());
219 }
220
221 pub fn set_owner_with(&self, owner: &Element, on_set_owner: impl FnOnce(&Element)) {
228 IAccessKeyHandler::set_owner(self, owner);
229
230 on_set_owner(owner);
231 }
232
233 fn set_show_access_keys(target: &Visual, value: bool) {
234 target.set_value(Self::show_access_key_property(), value)
235 }
236
237 fn source_of(e: &RoutedEventArgs) -> Option<Element> {
238 e.source().and_then(|source| source.downcast::<InputElement>().ok())
239 }
240
241 pub fn on_preview_key_down(&self, e: &KeyEventArgs) {
244 let Some(owner) = self.owner() else { return };
245 let source = Self::source_of(e);
246
247 let is_focus_within_owner = Self::is_focus_within_owner(&owner, source.as_ref());
250 if !is_focus_within_owner {
251 return;
252 }
253
254 if e.key == Key::LeftAlt || e.key == Key::RightAlt {
255 self.alt_is_down.set(true);
256
257 let main_menu = self.main_menu();
258 if !main_menu.as_ref().is_some_and(|menu| menu.is_open()) {
259 let focus_manager = source.as_ref().and_then(|source| FocusManager::get_focus_manager(source));
260
261 if let Some(focused_element) = focus_manager.and_then(|manager| manager.get_focused_element()) {
263 *self.restore_focus_element.borrow_mut() = Some(focused_element.downgrade());
264 }
265
266 self.showing_access_keys.set(is_focus_within_owner);
270 Self::set_show_access_keys(&owner, is_focus_within_owner);
271 } else {
272 self.close_menu(&owner);
275 self.ignore_alt_up.set(true);
276
277 let restore_element = self.restore_focus_element.borrow_mut().take().and_then(|weak| weak.upgrade());
278 if let Some(restore_element) = restore_element {
279 restore_element.focus();
280 }
281 }
282 } else if self.alt_is_down.get() {
283 self.ignore_alt_up.set(true);
284 }
285 }
286
287 pub fn on_key_down(&self, e: &KeyEventArgs) {
289 let Some(owner) = self.owner() else { return };
290 let source = Self::source_of(e);
291
292 if !Self::is_focus_within_owner(&owner, source.as_ref()) {
295 return;
296 }
297
298 if (!e.key_modifiers.contains(KeyModifiers::ALT) || e.key_modifiers.contains(KeyModifiers::CONTROL))
299 && !self.main_menu().is_some_and(|menu| menu.is_open())
300 {
301 return;
302 }
303
304 e.set_handled(self.process_key(e.key_symbol.as_deref(), source.as_ref()));
305 }
306
307 pub fn on_preview_key_up(&self, e: &KeyEventArgs) {
309 if e.key == Key::LeftAlt || e.key == Key::RightAlt {
310 self.alt_is_down.set(false);
311
312 if self.ignore_alt_up.get() {
313 self.ignore_alt_up.set(false);
314 } else if self.showing_access_keys.get() {
315 if let Some(main_menu) = self.main_menu() {
316 main_menu.open();
317 }
318 }
319 }
320 }
321
322 pub fn on_preview_pointer_pressed(&self, _e: &PointerPressedEventArgs) {
324 if self.showing_access_keys.get() {
325 if let Some(owner) = self.owner() {
326 Self::set_show_access_keys(&owner, false);
327 }
328 }
329 }
330
331 fn close_menu(&self, owner: &Element) {
333 if let Some(main_menu) = self.main_menu() {
334 main_menu.close();
335 }
336 self.showing_access_keys.set(false);
337 Self::set_show_access_keys(owner, false);
338 }
339
340 fn main_menu_closed(&self) {
341 if let Some(owner) = self.owner() {
342 Self::set_show_access_keys(&owner, false);
343 }
344 }
345
346 pub fn process_key(&self, key: Option<&str>, element: Option<&Element>) -> bool {
349 let Some(key) = key.filter(|key| !key.is_empty()) else { return false };
350 let key = Self::normalize_key(key);
351 let sender_target = Self::get_target_for_element(element, &key);
352
353 let targets = Self::sort_by_hierarchy(self.get_targets_for_key(&key, element, sender_target));
355 Self::process_key_for_targets(&key, &targets) != ProcessKeyResult::NoMatch
356 }
357
358 fn normalize_key(key: &str) -> String {
359 key.to_uppercase()
360 }
361
362 fn process_key_for_targets(key: &str, targets: &[Element]) -> ProcessKeyResult {
363 if targets.is_empty() {
364 return ProcessKeyResult::NoMatch;
365 }
366
367 let mut is_single_target = true;
368 let mut last_was_focused = false;
369 let mut effective_target: Option<&Element> = None;
370 let mut chosen_index = 0;
371
372 for (i, target) in targets.iter().enumerate() {
373 if !Self::is_targetable(target) {
374 continue;
375 }
376
377 if effective_target.is_none() {
378 effective_target = Some(target);
379 chosen_index = i;
380 } else {
381 if last_was_focused {
382 effective_target = Some(target);
383 chosen_index = i;
384 }
385
386 is_single_target = false;
387 }
388
389 last_was_focused = target.is_focused();
390 }
391
392 let Some(effective_target) = effective_target else { return ProcessKeyResult::NoMatch };
393
394 let args = AccessKeyEventArgs::new(key, !is_single_target);
395 effective_target.raise_event(&args);
396
397 if chosen_index == targets.len() - 1 {
398 ProcessKeyResult::LastMatch
399 } else {
400 ProcessKeyResult::MoreMatches
401 }
402 }
403
404 fn get_targets_for_key(&self, key: &str, sender: Option<&Element>, sender_target: Option<Element>) -> Vec<Element> {
408 let possible_elements = self.copy_matching_and_purge_dead(key);
409 let mut final_targets = Vec::with_capacity(1);
410
411 for element in &possible_elements {
414 if Some(element) != sender {
415 if !Self::is_targetable(element) {
416 continue;
417 }
418
419 if let Some(target) = Self::get_target_for_element(Some(element), key) {
420 final_targets.push(target);
421 }
422 } else if let Some(target) = &sender_target {
423 final_targets.push(target.clone());
426 }
427 }
428
429 final_targets
430 }
431
432 fn is_targetable(element: &InputElement) -> bool {
433 element.is_effectively_enabled() && element.is_effectively_visible()
434 }
435
436 fn copy_matching_and_purge_dead(&self, key: &str) -> Vec<Element> {
437 let mut registrations = self.registrations.borrow_mut();
438 let mut matches = Vec::with_capacity(registrations.len());
439
440 registrations.retain(|registration| match registration.get_input_element() {
442 Some(input_element) => {
443 if registration.key == key {
444 matches.push(input_element);
445 }
446 true
447 }
448 None => false,
449 });
450
451 matches
452 }
453
454 fn get_target_for_element(element: Option<&Element>, key: &str) -> Option<Element> {
457 let element = element?;
458
459 let args = AccessKeyPressedEventArgs::new(key);
460 element.raise_event(&args);
461 args.target()
462 }
463
464 fn is_focus_within_owner(owner: &Element, source: Option<&Element>) -> bool {
466 match source {
467 Some(source) => source == owner || owner.is_visual_ancestor_of(source),
468 None => false,
469 }
470 }
471
472 fn sort_by_hierarchy(targets: Vec<Element>) -> Vec<Element> {
476 if targets.len() <= 1 {
478 return targets;
479 }
480
481 let mut sorted: Vec<Element> = Vec::with_capacity(targets.len());
482 let mut queue: VecDeque<Element> = targets.into();
483
484 while let Some(element) = queue.pop_front() {
485 if sorted.contains(&element) {
487 continue;
488 }
489
490 sorted.push(element.clone());
492
493 sorted.extend(queue.iter().filter(|child| element.is_logical_ancestor_of(Some(child))).cloned());
495 }
496
497 sorted
498 }
499}
500
501impl IAccessKeyHandler for AccessKeyHandler {
502 fn main_menu(&self) -> Option<Rc<dyn IMainMenu>> {
503 self.main_menu.borrow().clone()
504 }
505
506 fn set_main_menu(&self, value: Option<Rc<dyn IMainMenu>>) {
507 let subscription = self.main_menu_closed.borrow_mut().take();
508 if let Some(subscription) = subscription {
509 subscription.dispose();
510 }
511
512 let old = self.main_menu.replace(value.clone());
513 drop(old);
514
515 if let Some(main_menu) = value {
516 let this = self.this.clone();
517 let subscription = main_menu.closed(Rc::new(move |_| {
518 if let Some(this) = this.upgrade() {
519 this.main_menu_closed();
520 }
521 }));
522 *self.main_menu_closed.borrow_mut() = Some(subscription);
523 }
524 }
525
526 fn set_owner(&self, owner: &Element) {
527 self.set_owner_without_handlers(owner);
528
529 let handler = |f: fn(&AccessKeyHandler, &KeyEventArgs)| {
530 let this = self.this.clone();
531 move |_: &crate::interactivity::Interactive, e: &KeyEventArgs| {
532 if let Some(this) = this.upgrade() {
533 f(&this, e);
534 }
535 }
536 };
537
538 owner.add_handler_with(
539 InputElement::key_down_event(),
540 handler(Self::on_preview_key_down),
541 RoutingStrategies::TUNNEL,
542 false,
543 );
544 owner.add_handler_with(
545 InputElement::key_down_event(),
546 handler(Self::on_key_down),
547 RoutingStrategies::BUBBLE,
548 false,
549 );
550 owner.add_handler_with(
551 InputElement::key_up_event(),
552 handler(Self::on_preview_key_up),
553 RoutingStrategies::TUNNEL,
554 false,
555 );
556
557 let this = self.this.clone();
558 owner.add_handler_with(
559 InputElement::pointer_pressed_event(),
560 move |_, e| {
561 if let Some(this) = this.upgrade() {
562 this.on_preview_pointer_pressed(e);
563 }
564 },
565 RoutingStrategies::TUNNEL,
566 false,
567 );
568 }
569
570 fn register(&self, access_key: &str, element: &Element) {
571 assert!(!access_key.is_empty(), "The access key cannot be empty.");
572
573 let key = Self::normalize_key(access_key);
574 let mut registrations = self.registrations.borrow_mut();
575
576 registrations.retain(|registration| !(registration.key == key && registration.get_input_element().is_none()));
578
579 registrations.push(AccessKeyRegistration::new(key, element.downgrade()));
580 }
581
582 fn unregister(&self, element: &InputElement) {
583 self.registrations.borrow_mut().retain(|registration| match registration.get_input_element() {
585 Some(input_element) => !std::ptr::eq::<InputElement>(&*input_element, element),
586 None => false,
587 });
588 }
589}