1use std::any::Any;
6use std::rc::Weak;
7
8use kurbo::Point;
9
10use super::{OverlayRoute, RenderRoot, advance_focus_epoch};
11use crate::event::{
12 ContactFrame, ContactPass, EventCtx, EventOutcome, EventResult, FileDropEvent, FileDropPhase,
13 ImeState, InputEvent, Key, KeyEvent, Modifiers, NamedKey, OverlayEvent, OverlayEventKind,
14 PointerButton, PointerId, PointerPhase, RequestPass,
15};
16use crate::overlay::{OutsideTap, OverlayHit, OverlayInput, OverlayKey, OverlayPod};
17use crate::shortcuts::{DeliveryProbe, KeyForwardPass};
18use crate::tree::WidgetPod;
19use crate::view::{ChangeFlags, View};
20use crate::widget::{ChildPod, FocusGrant};
21
22struct DispatchFrame {
24 pointer_id: PointerId,
25 secondary: bool,
27 live_focus_epoch: u64,
28 candidate_focus_epoch: u64,
29 focus_active_before: bool,
30 hover_pass: bool,
32 hover_ends: bool,
34 hover_epoch: u64,
35 hover_was_active: bool,
36 root_identity: u64,
37 cursor_pass: bool,
39 contacts_captor_is_root: bool,
41 grant: bool,
43 root_grant: bool,
44}
45
46struct RootDispatch {
48 handled: bool,
49 needs_redraw: bool,
50 captured: bool,
51 hover_claimed: bool,
52 focus_req: bool,
53 focus_req_from_live: bool,
55 focus_rel: bool,
56 ime: Option<ImeState>,
57 ime_published: bool,
58 root_opted_in: bool,
60}
61
62const ROOT_STOP: u64 = 0;
64
65struct FocusStop {
67 id: u64,
69 surface: Option<OverlayKey>,
71 current: bool,
73}
74
75struct FocusWalk<'a> {
77 floated: &'a [(OverlayPod, OverlayHit)],
78 stops: Vec<FocusStop>,
79}
80
81impl FocusWalk<'_> {
82 fn visit(&mut self, pod: &ChildPod, chain: bool, mut surface: Option<OverlayKey>) {
84 let floated = self
85 .floated
86 .iter()
87 .find(|(float, _)| std::ptr::eq(float.as_ptr(), pod));
88 if let Some((_, hit)) = floated {
89 if hit.input == OverlayInput::Transparent {
91 return;
92 }
93 surface = Some(hit.key);
94 }
95 let chain = chain && pod.holds_live_focus();
96 let widget = pod.widget();
97 if widget.is_focusable() {
98 let id = pod.inspect_id().0;
99 self.stops.push(FocusStop {
100 id,
101 surface,
102 current: chain,
103 });
104 }
105 widget.visit_focus_children(&mut |child| self.visit(child, chain, surface));
106 }
107}
108
109fn is_bare_escape(key: &KeyEvent) -> bool {
112 key.key == Key::Named(NamedKey::Escape) && key.modifiers == Modifiers::default()
113}
114
115fn traversal_direction(key: &KeyEvent) -> Option<bool> {
116 let mods = key.modifiers;
117 let bare = !(mods.ctrl || mods.alt || mods.meta);
118 (key.key == Key::Named(NamedKey::Tab) && bare).then_some(mods.shift)
119}
120
121fn is_pointer_down(event: &InputEvent) -> bool {
123 let pointer = match event {
124 InputEvent::Pointer(pointer) => pointer,
125 InputEvent::Overlay(OverlayEvent {
126 kind: OverlayEventKind::Pointer(pointer),
127 ..
128 }) => pointer,
129 _ => return false,
130 };
131 pointer.phase == PointerPhase::Down
132}
133
134fn unwrap_contact(event: &InputEvent) -> (Option<InputEvent>, PointerId) {
138 match event {
139 InputEvent::PointerContact {
140 pointer_id,
141 event: pointer,
142 } => (Some(InputEvent::Pointer(*pointer)), *pointer_id),
143 InputEvent::Pointer(_) => (None, PointerId::MOUSE),
144 _ => (None, crate::event::current_pointer_id()),
145 }
146}
147
148impl<State: 'static, V: View<State>> RenderRoot<State, V> {
149 pub fn event(&mut self, state: &mut State, event: &InputEvent) -> EventOutcome {
162 self.dispatch_pass(state, event, None).0
163 }
164
165 fn dispatch_pass(
168 &mut self,
169 state: &mut State,
170 event: &InputEvent,
171 grant: Option<bool>,
172 ) -> (EventOutcome, bool) {
173 let Some(root_id) = self.root_id else {
174 return (EventOutcome::default(), false);
175 };
176 self.trap_modal_focus();
177 let (unwrapped, pointer_id) = unwrap_contact(event);
178 let event = unwrapped.as_ref().unwrap_or(event);
179 if is_pointer_down(event) {
180 self.set_keyboard_focus(false);
181 }
182 let Some(secondary) = self.gate_contact(event, pointer_id) else {
183 return (EventOutcome::default(), false);
184 };
185 let contact_pass = ContactPass::enter(pointer_id, secondary);
188
189 let carried = match self.route_overlay(state, event) {
191 OverlayRoute::Consumed(outcome) => return (outcome, false),
192 OverlayRoute::Continue(outcome) => outcome,
193 };
194 let frame = self.open_frame(event, pointer_id, secondary, grant);
195 let Some(pod) = self.tree.pod_mut(root_id) else {
196 self.publish_focus_session();
198 return (carried, false);
199 };
200 let request_slot = RequestPass::enter();
203 let forward_slot = KeyForwardPass::enter();
204 let mut root = Self::dispatch_root(pod, &mut self.pending, &frame, state, event);
205 if frame.grant && root.focus_req {
207 self.release_focus_session();
208 }
209 root.ime_published = root.ime.is_some();
210 self.publish_ime(event, root.focus_req, root.ime.take());
211 let focus_claim_honoured = self.commit_event(event, &frame, &root, &contact_pass);
212 self.resolve_focus_session(&frame, focus_claim_honoured);
213 self.record_key_forward(forward_slot.take());
214 drop(forward_slot);
215 self.resolve_hover(&frame, root.hover_claimed);
216 self.resolve_requests(request_slot, frame.cursor_pass);
217 let carried = if root.handled {
218 carried
219 } else {
220 self.dispatch_declined_key(state, event, carried)
221 };
222 let mut outcome = self.build_outcome(&frame, &root, carried);
223 self.file_drop_follow_up(state, event, &mut outcome);
224 (outcome, focus_claim_honoured)
225 }
226
227 fn gate_contact(&self, event: &InputEvent, pointer_id: PointerId) -> Option<bool> {
230 if matches!(event, InputEvent::Pointer(_)) {
231 self.contact_route(pointer_id)
233 } else {
234 Some(false)
235 }
236 }
237
238 fn open_frame(
243 &self,
244 event: &InputEvent,
245 pointer_id: PointerId,
246 secondary: bool,
247 grant: Option<bool>,
248 ) -> DispatchFrame {
249 let live_focus_epoch = self.focus_epoch;
250 let mut candidate_focus_epoch = advance_focus_epoch(live_focus_epoch);
251 if grant.is_some() && (self.focus_active || self.ime_state.is_some()) {
252 candidate_focus_epoch = advance_focus_epoch(candidate_focus_epoch);
253 }
254 crate::widget::set_live_focus_session(
255 self.root_identity,
256 live_focus_epoch,
257 candidate_focus_epoch,
258 );
259 let is_move = matches!(event, InputEvent::Pointer(p) if p.phase == PointerPhase::Move);
261 let hover_ends = !secondary
262 && matches!(
263 event,
264 InputEvent::Pointer(p)
265 if matches!(
266 p.phase,
267 PointerPhase::Down | PointerPhase::Up | PointerPhase::Cancel
268 )
269 );
270 DispatchFrame {
271 pointer_id,
272 secondary,
273 live_focus_epoch,
274 candidate_focus_epoch,
275 focus_active_before: self.focus_active,
276 hover_pass: is_move && self.capture_claimant.is_none(),
277 hover_ends,
278 hover_epoch: self.hover_epoch,
279 hover_was_active: self.hover_active,
280 root_identity: self.root_identity,
281 cursor_pass: !secondary && is_move,
282 contacts_captor_is_root: self.capture_claimant.is_some()
283 && self.capture_contacts
284 && self.contacts_captor_is_root,
285 grant: grant.is_some(),
286 root_grant: grant == Some(true),
287 }
288 }
289
290 fn dispatch_root(
294 pod: &mut WidgetPod,
295 pending: &mut ChangeFlags,
296 frame: &DispatchFrame,
297 state: &mut State,
298 event: &InputEvent,
299 ) -> RootDispatch {
300 crate::widget::clear_hover_claimant();
302 crate::widget::clear_focus_req_from_live();
303 let state_any: &mut dyn Any = state;
304 let mut ctx = EventCtx::new(state_any, pod.origin(), pod.size());
305 ctx.set_has_focus(frame.focus_active_before);
307 ctx.set_hovered(frame.hover_was_active);
308 ctx.set_hover_epoch(frame.hover_epoch);
309 ctx.set_hover_eligible(frame.hover_pass);
310 ctx.set_hover_root(frame.root_identity);
312 if frame.root_grant {
313 ctx.request_focus();
314 }
315 let contact_frame = ContactFrame::enter(frame.contacts_captor_is_root);
317 let result = if frame.secondary && !frame.contacts_captor_is_root {
318 let widget = pod.widget_mut();
320 let carrier = crate::event::secondary_walk_carrier();
321 let (_, delivered) = crate::event::run_secondary_walk(event.clone(), || {
322 widget.event(&mut ctx, &carrier)
323 });
324 match delivered {
325 Some(result) => result,
326 None => crate::event::without_secondary_walk(|| widget.event(&mut ctx, event)),
327 }
328 } else {
329 pod.widget_mut().event(&mut ctx, event)
330 };
331 let root_opted_in = contact_frame.close().0;
332 let handled = matches!(result, EventResult::Handled);
333 if ctx.needs_layout() || ctx.is_layout_path_dirty() || handled || ctx.needs_redraw() {
336 *pending |= ChangeFlags::LAYOUT;
337 }
338 RootDispatch {
339 handled,
340 needs_redraw: ctx.needs_redraw() || handled,
341 captured: ctx.is_pointer_captured(),
342 hover_claimed: ctx.is_hover_claimed(),
343 focus_req: ctx.is_focus_requested(),
344 focus_req_from_live: crate::widget::take_focus_req_from_live()
346 .unwrap_or(frame.focus_active_before),
347 focus_rel: ctx.is_focus_released(),
348 ime: ctx.take_ime_state(),
349 ime_published: false,
350 root_opted_in,
351 }
352 }
353
354 fn publish_ime(&mut self, event: &InputEvent, focus_req: bool, ime: Option<ImeState>) {
358 let publish_attributable = match event {
359 InputEvent::Overlay(overlay) => focus_req || self.focus_surface == Some(overlay.key),
360 _ => self.focus_active || focus_req,
361 };
362 match ime {
363 Some(_) if !publish_attributable => {}
364 Some(ime) if !ime.active => {
365 self.release_focus_session();
366 }
367 Some(ime) => self.store_ime_state(Some(ime)),
368 None => {}
369 }
370 }
371
372 fn commit_event(
376 &mut self,
377 event: &InputEvent,
378 frame: &DispatchFrame,
379 root: &RootDispatch,
380 contact_pass: &ContactPass,
381 ) -> bool {
382 let mut focus_claim_honoured = false;
383 match event {
384 InputEvent::Pointer(_) if frame.secondary => {
386 focus_claim_honoured = self.commit_focus_request(root);
387 }
388 InputEvent::PointerContact { .. } => {}
390 InputEvent::Pointer(pointer) => {
391 focus_claim_honoured =
392 self.commit_pointer(pointer.phase, frame.pointer_id, root, contact_pass);
393 }
394 InputEvent::Scroll { .. }
397 | InputEvent::Scale(_)
398 | InputEvent::FileDrop(_)
399 | InputEvent::Key(_)
400 | InputEvent::Ime(_)
401 | InputEvent::EditCommand(_)
402 | InputEvent::Shortcut(_) => {
403 focus_claim_honoured = self.commit_focus_request(root);
404 }
405 InputEvent::Housekeeping => {}
408 InputEvent::Overlay(overlay) => {
409 focus_claim_honoured =
410 self.commit_overlay(overlay, frame.pointer_id, root, contact_pass);
411 }
412 }
413 if !frame.secondary && self.capture_claimant.is_some() && contact_pass.capture_released() {
416 self.capture_contacts = contact_pass.contacts_requested();
417 }
418 focus_claim_honoured
419 }
420
421 fn commit_focus_request(&mut self, root: &RootDispatch) -> bool {
425 if root.focus_req {
426 self.set_focus_active(true);
427 }
428 if root.focus_rel {
429 self.release_focus_session();
430 }
431 root.focus_req
432 }
433
434 fn commit_pointer(
440 &mut self,
441 phase: PointerPhase,
442 pointer_id: PointerId,
443 root: &RootDispatch,
444 contact_pass: &ContactPass,
445 ) -> bool {
446 match phase {
447 PointerPhase::Down => {
448 if root.captured {
449 self.latch_capture(pointer_id, contact_pass, root.root_opted_in);
451 }
452 if root.focus_req {
453 self.set_focus_active(true);
454 self.focus_surface = None;
456 if !root.ime_published && !root.focus_req_from_live {
457 self.store_ime_state(None);
458 }
459 true
460 } else {
461 self.release_focus_session();
463 false
464 }
465 }
466 PointerPhase::Up | PointerPhase::Cancel => {
467 self.clear_capture();
468 false
469 }
470 PointerPhase::Move => false,
471 }
472 }
473
474 fn commit_overlay(
478 &mut self,
479 overlay: &OverlayEvent,
480 pointer_id: PointerId,
481 root: &RootDispatch,
482 contact_pass: &ContactPass,
483 ) -> bool {
484 if root.focus_req {
487 if self.focus_surface.is_some_and(|owner| owner != overlay.key) {
488 self.release_focus_session();
489 }
490 self.set_focus_active(true);
491 }
492 if root.focus_rel {
493 self.release_focus_session();
494 }
495 if root.captured {
497 self.latch_capture(pointer_id, contact_pass, root.root_opted_in);
498 }
499 if let OverlayEventKind::Pointer(pointer) = &overlay.kind
502 && matches!(pointer.phase, PointerPhase::Up | PointerPhase::Cancel)
503 && self
504 .capture_claimant
505 .is_none_or(|claimant| claimant == pointer_id)
506 {
507 self.clear_capture();
508 }
509 root.focus_req
510 }
511
512 fn latch_capture(&mut self, pointer_id: PointerId, pass: &ContactPass, root_opted_in: bool) {
515 self.capture_claimant = Some(pointer_id);
516 self.capture_contacts = pass.contacts_requested();
517 self.contacts_captor_is_root = root_opted_in;
518 }
519
520 fn clear_capture(&mut self) {
522 self.capture_claimant = None;
523 self.capture_contacts = false;
524 self.contacts_captor_is_root = false;
525 }
526
527 fn resolve_focus_session(&mut self, frame: &DispatchFrame, focus_claim_honoured: bool) {
531 if focus_claim_honoured && !frame.grant {
532 self.set_keyboard_focus(false);
533 }
534 let session_ended = frame.focus_active_before && !self.focus_active;
535 self.focus_epoch = if session_ended {
536 advance_focus_epoch(frame.candidate_focus_epoch)
537 } else if focus_claim_honoured {
538 frame.candidate_focus_epoch
539 } else {
540 frame.live_focus_epoch
541 };
542 self.publish_focus_session();
543 }
544
545 fn resolve_hover(&mut self, frame: &DispatchFrame, hover_claimed: bool) {
549 let hover_claimant = crate::widget::take_hover_claimant();
550 if frame.hover_pass || frame.hover_ends {
551 self.hover_epoch = self.hover_epoch.wrapping_add(1);
552 self.hover_active = frame.hover_pass && hover_claimed;
553 self.hover_link = self.hover_active.then(|| hover_claimant.unwrap_or(0));
555 crate::event::set_live_hover_link(
558 self.root_identity,
559 if self.hover_active {
560 self.hover_epoch
561 } else {
562 0
563 },
564 );
565 }
566 }
567
568 fn resolve_requests(&mut self, request_slot: RequestPass, cursor_pass: bool) {
572 let requested = request_slot.take();
573 if cursor_pass {
574 self.cursor = requested.cursor.unwrap_or_default();
575 }
576 if let Some(text) = requested.clipboard_write {
579 self.pending_clipboard_write = Some(text);
580 }
581 self.pending_paste_request |= requested.paste_request;
582 }
583
584 fn dispatch_declined_key(
591 &mut self,
592 state: &mut State,
593 event: &InputEvent,
594 mut carried: EventOutcome,
595 ) -> EventOutcome {
596 let InputEvent::Key(key) = event else {
597 return carried;
598 };
599 let interactive = |hit: &&OverlayHit| hit.input == OverlayInput::Interactive;
600 let modal = self.overlay_hits.iter().rev().find(|hit| hit.is_modal());
601 let modal = modal.map(|hit| hit.key);
602 let forward = self.live_key_forward().filter(|pod| {
603 self.overlay_hits
604 .iter()
605 .filter(interactive)
606 .any(|hit| hit.key == *pod)
607 });
608 let escape = modal.filter(|pod| is_bare_escape(key) && forward != Some(*pod));
609 for pod in forward.into_iter().chain(escape) {
610 let kind = OverlayEventKind::Key(key.clone());
611 let delivery = InputEvent::Overlay(OverlayEvent { key: pod, kind });
612 if self.deliver_declined(state, &delivery, &mut carried) {
613 return carried;
614 }
615 }
616 let top_overlay = modal.or_else(|| {
617 let top = self.overlay_hits.iter().rev().find(interactive);
618 top.map(|hit| hit.key)
619 });
620 for (id, overlay) in self.shortcuts.candidates(key, top_overlay, modal.is_some()) {
621 let delivery = match overlay {
623 None => InputEvent::Shortcut(id),
624 Some(key) => InputEvent::Overlay(OverlayEvent {
625 key,
626 kind: OverlayEventKind::Shortcut(id),
627 }),
628 };
629 if self.deliver_declined(state, &delivery, &mut carried) {
630 return carried;
631 }
632 }
633 if let Some(backward) = traversal_direction(key).filter(|_| self.tab_traversal) {
634 self.traverse_focus(state, backward, &mut carried);
635 }
636 carried
637 }
638
639 fn traverse_focus(&mut self, state: &mut State, backward: bool, carried: &mut EventOutcome) {
652 let stops = self.focus_stops();
653 let len = stops.len();
654 let current = stops.iter().rposition(|stop| stop.current);
655 let next = match current {
656 _ if len == 0 => return,
657 None if backward => len - 1,
658 None => 0,
659 Some(i) if backward => (i + len - 1) % len,
660 Some(i) => (i + 1) % len,
661 };
662 let step = |n: usize| if backward { len - n } else { n };
663 let landed = current == Some(next)
664 || (0..len)
665 .map(|n| (next + step(n)) % len)
666 .take_while(|&i| Some(i) != current)
667 .any(|i| self.grant_focus(state, &stops[i]));
668 if landed {
669 carried.handled = true;
670 carried.needs_redraw = true;
671 self.set_keyboard_focus(true);
672 }
673 }
674
675 fn grant_focus(&mut self, state: &mut State, stop: &FocusStop) -> bool {
677 let carrier = self.focus_grant;
678 let delivery = match stop.surface {
679 None => InputEvent::Shortcut(carrier),
680 Some(key) => InputEvent::Overlay(OverlayEvent {
681 key,
682 kind: OverlayEventKind::Shortcut(carrier),
683 }),
684 };
685 let _grant = FocusGrant::enter(carrier, stop.id);
686 let _probe = DeliveryProbe::enter();
687 let root_is_target = stop.id == ROOT_STOP;
688 self.dispatch_pass(state, &delivery, Some(root_is_target)).1
689 }
690
691 fn focus_stops(&self) -> Vec<FocusStop> {
695 self.publish_focus_session();
696 let floated: Vec<(OverlayPod, OverlayHit)> = self
697 .overlay_pods
698 .iter()
699 .zip(&self.overlay_hits)
700 .filter_map(|(weak, hit)| Some((weak.upgrade()?, *hit)))
701 .collect();
702 let mut walk = FocusWalk {
703 floated: &floated,
704 stops: Vec::new(),
705 };
706 let chain = self.focus_active;
707 if let Some(modal) = self.overlay_hits.iter().rposition(|hit| hit.is_modal()) {
708 if let Some(pod) = self.overlay_pods.get(modal).and_then(Weak::upgrade)
710 && let Ok(pod) = pod.try_borrow()
711 {
712 walk.visit(&pod, chain, None);
713 }
714 } else if let Some(root) = self.root_id.and_then(|id| self.tree.pod(id)) {
715 if root.widget().is_focusable() {
716 walk.stops.push(FocusStop {
717 id: ROOT_STOP,
718 surface: None,
719 current: chain,
720 });
721 }
722 root.widget()
723 .visit_focus_children(&mut |pod| walk.visit(pod, chain, None));
724 }
725 walk.stops
726 }
727
728 fn deliver_declined(
731 &mut self,
732 state: &mut State,
733 delivery: &InputEvent,
734 carried: &mut EventOutcome,
735 ) -> bool {
736 let probe = DeliveryProbe::enter();
737 let outcome = self.event(state, delivery);
738 let answered = probe.handled() || outcome.handled;
739 carried.needs_redraw |= outcome.needs_redraw || answered;
740 carried.handled |= answered;
741 answered
742 }
743
744 fn build_outcome(
747 &self,
748 frame: &DispatchFrame,
749 root: &RootDispatch,
750 carried: EventOutcome,
751 ) -> EventOutcome {
752 let needs_redraw = root.needs_redraw || (frame.hover_was_active && !self.hover_active);
753 EventOutcome {
754 handled: root.handled || carried.handled,
755 needs_redraw: needs_redraw || carried.needs_redraw,
756 }
757 }
758
759 fn file_drop_follow_up(
762 &mut self,
763 state: &mut State,
764 event: &InputEvent,
765 outcome: &mut EventOutcome,
766 ) {
767 if let InputEvent::FileDrop(drop) = event
768 && matches!(drop.phase, FileDropPhase::Drop | FileDropPhase::Cancel)
769 {
770 let ended = InputEvent::FileDrop(FileDropEvent {
771 phase: FileDropPhase::Ended,
772 position: Point::ZERO,
773 paths: Vec::new(),
774 });
775 let follow_up = self.event(state, &ended);
776 outcome.handled |= follow_up.handled;
777 outcome.needs_redraw |= follow_up.needs_redraw;
778 }
779 }
780
781 fn contact_route(&self, pointer_id: PointerId) -> Option<bool> {
786 match self.capture_claimant {
787 None if pointer_id.slot == 0 => Some(false),
788 None => None,
789 Some(claimant) if claimant == pointer_id => Some(false),
790 Some(_) if self.capture_contacts => Some(true),
791 Some(_) => None,
792 }
793 }
794
795 fn route_overlay(&mut self, state: &mut State, event: &InputEvent) -> OverlayRoute {
804 if self.capture_claimant.is_some() || self.overlay_hits.is_empty() {
805 return OverlayRoute::Continue(EventOutcome::default());
806 }
807 let (position, kind) = match event {
808 InputEvent::Pointer(pointer) | InputEvent::PointerContact { event: pointer, .. } => {
810 (pointer.position, OverlayEventKind::Pointer(*pointer))
811 }
812 InputEvent::Scroll { position, delta } => (
813 *position,
814 OverlayEventKind::Scroll {
815 position: *position,
816 delta: *delta,
817 },
818 ),
819 InputEvent::Scale(scale) => (
820 scale.focal,
821 OverlayEventKind::Scale {
822 focal: scale.focal,
823 phase: scale.phase,
824 scale_delta: scale.scale_delta,
825 velocity: scale.velocity,
826 },
827 ),
828 InputEvent::FileDrop(_)
829 | InputEvent::Key(_)
830 | InputEvent::Ime(_)
831 | InputEvent::EditCommand(_)
832 | InputEvent::Housekeeping
833 | InputEvent::Overlay(_)
834 | InputEvent::Shortcut(_) => {
835 return OverlayRoute::Continue(EventOutcome::default());
836 }
837 };
838
839 let hits = self.overlay_hits.clone();
842 for hit in hits.iter().rev() {
843 if hit.input == OverlayInput::Transparent {
845 continue;
846 }
847 if hit.contains(position) {
848 let routed = InputEvent::Overlay(OverlayEvent {
849 key: hit.key,
850 kind: kind.clone(),
851 });
852 return OverlayRoute::Consumed(self.event(state, &routed));
855 }
856 }
857
858 let dismissing = matches!(
861 event,
862 InputEvent::Pointer(pointer) | InputEvent::PointerContact { event: pointer, .. }
863 if pointer.phase == PointerPhase::Down
864 && pointer.button == PointerButton::Primary
865 );
866 if !dismissing {
867 return OverlayRoute::Continue(EventOutcome::default());
868 }
869
870 let mut carried = EventOutcome::default();
871 let mut consumed = false;
872 for hit in hits.iter().rev() {
873 if hit.input == OverlayInput::Transparent {
875 continue;
876 }
877 let OutsideTap::Notify { consume } = hit.outside_tap else {
878 continue;
879 };
880 let routed = InputEvent::Overlay(OverlayEvent {
881 key: hit.key,
882 kind: OverlayEventKind::OutsideDown,
883 });
884 let outcome = self.event(state, &routed);
885 carried.handled |= outcome.handled;
886 carried.needs_redraw |= outcome.needs_redraw;
887 consumed |= consume;
889 }
890 if consumed {
891 OverlayRoute::Consumed(carried)
892 } else {
893 OverlayRoute::Continue(carried)
894 }
895 }
896}