Skip to repository content879 lines · 27.6 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T04:30:42.147Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
interactive.rs
1use crate::{
2 Bounds, Capslock, Context, Empty, IntoElement, Keystroke, Modifiers, Pixels, Point, Render,
3 Window, point, seal::Sealed,
4};
5use smallvec::SmallVec;
6use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf};
7
8/// An event from a platform input source.
9pub trait InputEvent: Sealed + 'static {
10 /// Convert this event into the platform input enum.
11 fn to_platform_input(self) -> PlatformInput;
12}
13
14/// A key event from the platform.
15pub trait KeyEvent: InputEvent {}
16
17/// A mouse event from the platform.
18pub trait MouseEvent: InputEvent {}
19
20/// A gesture event from the platform.
21pub trait GestureEvent: InputEvent {}
22
23/// The key down event equivalent for the platform.
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct KeyDownEvent {
26 /// The keystroke that was generated.
27 pub keystroke: Keystroke,
28
29 /// Whether the key is currently held down.
30 pub is_held: bool,
31
32 /// Whether to prefer character input over keybindings for this keystroke.
33 /// In some cases, like AltGr on Windows, modifiers are significant for character input.
34 pub prefer_character_input: bool,
35}
36
37impl Sealed for KeyDownEvent {}
38impl InputEvent for KeyDownEvent {
39 fn to_platform_input(self) -> PlatformInput {
40 PlatformInput::KeyDown(self)
41 }
42}
43impl KeyEvent for KeyDownEvent {}
44
45/// The key up event equivalent for the platform.
46#[derive(Clone, Debug)]
47pub struct KeyUpEvent {
48 /// The keystroke that was released.
49 pub keystroke: Keystroke,
50}
51
52impl Sealed for KeyUpEvent {}
53impl InputEvent for KeyUpEvent {
54 fn to_platform_input(self) -> PlatformInput {
55 PlatformInput::KeyUp(self)
56 }
57}
58impl KeyEvent for KeyUpEvent {}
59
60/// The modifiers changed event equivalent for the platform.
61#[derive(Clone, Debug, Default)]
62pub struct ModifiersChangedEvent {
63 /// The new state of the modifier keys
64 pub modifiers: Modifiers,
65 /// The new state of the capslock key
66 pub capslock: Capslock,
67}
68
69impl Sealed for ModifiersChangedEvent {}
70impl InputEvent for ModifiersChangedEvent {
71 fn to_platform_input(self) -> PlatformInput {
72 PlatformInput::ModifiersChanged(self)
73 }
74}
75impl KeyEvent for ModifiersChangedEvent {}
76
77impl Deref for ModifiersChangedEvent {
78 type Target = Modifiers;
79
80 fn deref(&self) -> &Self::Target {
81 &self.modifiers
82 }
83}
84
85/// The phase of a touch motion event.
86/// Based on the winit enum of the same name.
87#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
88pub enum TouchPhase {
89 /// The touch started.
90 Started,
91 /// The touch event is moving.
92 #[default]
93 Moved,
94 /// The touch phase has ended
95 Ended,
96 /// The touch was cancelled: the system took it and it will not end
97 /// normally. Consumers must fully unwind any in-progress interaction,
98 /// treating the touch as if it never committed.
99 Cancelled,
100}
101
102/// Identifies one touch (finger or stylus contact) for its lifetime, from
103/// [`TouchPhase::Started`] through [`TouchPhase::Ended`] or
104/// [`TouchPhase::Cancelled`].
105///
106/// The value is opaque and platform-defined; it is only guaranteed to be
107/// stable for the duration of the touch and unique among concurrent touches.
108#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
109pub struct TouchId(pub u64);
110
111/// A raw touch event from the platform.
112///
113///
114/// Dispatch contract (core implementation pending): a touch is hit-tested
115/// once, at [`TouchPhase::Started`], occlusion-aware; all subsequent events
116/// for the same [`TouchId`] are delivered to the elements under the starting
117/// position, even after the touch moves outside them.
118#[derive(Clone, Debug, Default)]
119pub struct TouchEvent {
120 /// Which touch this event belongs to.
121 pub id: TouchId,
122 /// The phase of the touch.
123 pub phase: TouchPhase,
124 /// The position of the touch in window coordinates.
125 pub position: Point<Pixels>,
126 /// Normalized touch force in `0.0..=1.0`, if the hardware reports it.
127 pub force: Option<f32>,
128}
129
130impl Sealed for TouchEvent {}
131impl InputEvent for TouchEvent {
132 fn to_platform_input(self) -> PlatformInput {
133 PlatformInput::Touch(self)
134 }
135}
136
137/// A mouse down event from the platform
138#[derive(Clone, Debug, Default)]
139pub struct MouseDownEvent {
140 /// Which mouse button was pressed.
141 pub button: MouseButton,
142
143 /// The position of the mouse on the window.
144 pub position: Point<Pixels>,
145
146 /// The modifiers that were held down when the mouse was pressed.
147 pub modifiers: Modifiers,
148
149 /// The number of times the button has been clicked.
150 pub click_count: usize,
151
152 /// Whether this is the first, focusing click.
153 pub first_mouse: bool,
154}
155
156impl Sealed for MouseDownEvent {}
157impl InputEvent for MouseDownEvent {
158 fn to_platform_input(self) -> PlatformInput {
159 PlatformInput::MouseDown(self)
160 }
161}
162impl MouseEvent for MouseDownEvent {}
163
164impl MouseDownEvent {
165 /// Returns true if this mouse up event should focus the element.
166 pub fn is_focusing(&self) -> bool {
167 match self.button {
168 MouseButton::Left => true,
169 _ => false,
170 }
171 }
172}
173
174/// A mouse up event from the platform
175#[derive(Clone, Debug, Default)]
176pub struct MouseUpEvent {
177 /// Which mouse button was released.
178 pub button: MouseButton,
179
180 /// The position of the mouse on the window.
181 pub position: Point<Pixels>,
182
183 /// The modifiers that were held down when the mouse was released.
184 pub modifiers: Modifiers,
185
186 /// The number of times the button has been clicked.
187 pub click_count: usize,
188}
189
190impl Sealed for MouseUpEvent {}
191impl InputEvent for MouseUpEvent {
192 fn to_platform_input(self) -> PlatformInput {
193 PlatformInput::MouseUp(self)
194 }
195}
196
197impl MouseEvent for MouseUpEvent {}
198
199impl MouseUpEvent {
200 /// Returns true if this mouse up event should focus the element.
201 pub fn is_focusing(&self) -> bool {
202 match self.button {
203 MouseButton::Left => true,
204 _ => false,
205 }
206 }
207}
208
209/// A click event, generated when a mouse button is pressed and released.
210#[derive(Clone, Debug, Default)]
211pub struct MouseClickEvent {
212 /// The mouse event when the button was pressed.
213 pub down: MouseDownEvent,
214
215 /// The mouse event when the button was released.
216 pub up: MouseUpEvent,
217}
218
219/// The stage of a pressure click event.
220#[derive(Clone, Copy, Debug, Default, PartialEq)]
221pub enum PressureStage {
222 /// No pressure.
223 #[default]
224 Zero,
225 /// Normal click pressure.
226 Normal,
227 /// High pressure, enough to trigger a force click.
228 Force,
229}
230
231/// A mouse pressure event from the platform. Generated when a force-sensitive trackpad is pressed hard.
232/// Currently only implemented for macOS trackpads.
233#[derive(Debug, Clone, Default)]
234pub struct MousePressureEvent {
235 /// Pressure of the current stage as a float between 0 and 1
236 pub pressure: f32,
237 /// The pressure stage of the event.
238 pub stage: PressureStage,
239 /// The position of the mouse on the window.
240 pub position: Point<Pixels>,
241 /// The modifiers that were held down when the mouse pressure changed.
242 pub modifiers: Modifiers,
243}
244
245impl Sealed for MousePressureEvent {}
246impl InputEvent for MousePressureEvent {
247 fn to_platform_input(self) -> PlatformInput {
248 PlatformInput::MousePressure(self)
249 }
250}
251impl MouseEvent for MousePressureEvent {}
252
253/// A click event that was generated by a keyboard button being pressed and released.
254#[derive(Clone, Debug, Default)]
255pub struct KeyboardClickEvent {
256 /// The keyboard button that was pressed to trigger the click.
257 pub button: KeyboardButton,
258
259 /// The bounds of the element that was clicked.
260 pub bounds: Bounds<Pixels>,
261}
262
263/// A click event that was generated by a recognized tap gesture on a touch
264/// screen.
265#[derive(Clone, Debug, Default)]
266pub struct TouchClickEvent {
267 /// The position of the tap in window coordinates.
268 pub position: Point<Pixels>,
269 /// The number of consecutive taps at this location (double tap = 2),
270 /// analogous to the mouse `click_count`.
271 pub tap_count: usize,
272 /// Whether this was a long press rather than a tap. Long presses are
273 /// touch's secondary activation: they are delivered to aux-click
274 /// listeners alongside right clicks, not to primary click listeners.
275 pub long_press: bool,
276}
277
278/// A click event, generated when a mouse button or keyboard button is pressed and released,
279/// or when a tap gesture is recognized on a touch screen.
280#[derive(Clone, Debug)]
281pub enum ClickEvent {
282 /// A click event trigger by a mouse button being pressed and released.
283 Mouse(MouseClickEvent),
284 /// A click event trigger by a keyboard button being pressed and released.
285 Keyboard(KeyboardClickEvent),
286 /// A click event triggered by a recognized tap gesture on a touch screen.
287 Touch(TouchClickEvent),
288}
289
290impl Default for ClickEvent {
291 fn default() -> Self {
292 ClickEvent::Keyboard(KeyboardClickEvent::default())
293 }
294}
295
296impl ClickEvent {
297 /// Returns the modifiers that were held during the click event
298 ///
299 /// `Keyboard`: The keyboard click events never have modifiers.
300 /// `Mouse`: Modifiers that were held during the mouse key up event.
301 pub fn modifiers(&self) -> Modifiers {
302 match self {
303 // Click events are only generated from keyboard events _without any modifiers_, so we know the modifiers are always Default
304 ClickEvent::Keyboard(_) => Modifiers::default(),
305 // Click events on the web only reflect the modifiers for the keyup event,
306 // tested via observing the behavior of the `ClickEvent.shiftKey` field in Chrome 138
307 // under various combinations of modifiers and keyUp / keyDown events.
308 ClickEvent::Mouse(event) => event.up.modifiers,
309 // Touch screens have no modifier keys.
310 ClickEvent::Touch(_) => Modifiers::default(),
311 }
312 }
313
314 /// Returns the position of the click event
315 ///
316 /// `Keyboard`: The bottom left corner of the clicked hitbox
317 /// `Mouse`: The position of the mouse when the button was released.
318 /// `Touch`: The position of the tap.
319 pub fn position(&self) -> Point<Pixels> {
320 match self {
321 ClickEvent::Keyboard(event) => event.bounds.bottom_left(),
322 ClickEvent::Mouse(event) => event.up.position,
323 ClickEvent::Touch(event) => event.position,
324 }
325 }
326
327 /// Returns the mouse position of the click event
328 ///
329 /// `Keyboard`: None
330 /// `Mouse`: The position of the mouse when the button was released.
331 /// `Touch`: None, touches are not mouse input and there is no cursor.
332 pub fn mouse_position(&self) -> Option<Point<Pixels>> {
333 match self {
334 ClickEvent::Keyboard(_) => None,
335 ClickEvent::Mouse(event) => Some(event.up.position),
336 ClickEvent::Touch(_) => None,
337 }
338 }
339
340 /// Returns if this was a right click
341 ///
342 /// `Keyboard`: false
343 /// `Mouse`: Whether the right button was pressed and released
344 pub fn is_right_click(&self) -> bool {
345 match self {
346 ClickEvent::Keyboard(_) => false,
347 ClickEvent::Mouse(event) => {
348 event.down.button == MouseButton::Right && event.up.button == MouseButton::Right
349 }
350 ClickEvent::Touch(_) => false,
351 }
352 }
353
354 /// Returns if this was a middle click
355 ///
356 /// `Keyboard`: false
357 /// `Mouse`: Whether the middle button was pressed and released
358 pub fn is_middle_click(&self) -> bool {
359 match self {
360 ClickEvent::Keyboard(_) => false,
361 ClickEvent::Mouse(event) => {
362 event.down.button == MouseButton::Middle && event.up.button == MouseButton::Middle
363 }
364 ClickEvent::Touch(_) => false,
365 }
366 }
367
368 /// Returns whether the click is a secondary activation, i.e. a context
369 /// menu trigger: a right click from a mouse (macOS ctrl-clicks arrive
370 /// already converted to right clicks by the platform layer), or a long
371 /// press on a touch screen.
372 pub fn is_secondary(&self) -> bool {
373 match self {
374 ClickEvent::Keyboard(_) => false,
375 ClickEvent::Mouse(event) => {
376 event.down.button == MouseButton::Right && event.up.button == MouseButton::Right
377 }
378 ClickEvent::Touch(event) => event.long_press,
379 }
380 }
381
382 /// Returns whether the click was a standard click
383 ///
384 /// `Keyboard`: Always true
385 /// `Mouse`: Left button pressed and released
386 /// `Touch`: A tap, but not a long press
387 pub fn standard_click(&self) -> bool {
388 match self {
389 ClickEvent::Keyboard(_) => true,
390 ClickEvent::Mouse(event) => {
391 event.down.button == MouseButton::Left && event.up.button == MouseButton::Left
392 }
393 ClickEvent::Touch(event) => !event.long_press,
394 }
395 }
396
397 /// Returns whether the click focused the element
398 ///
399 /// `Keyboard`: false, keyboard clicks only work if an element is already focused
400 /// `Mouse`: Whether this was the first focusing click
401 /// `Touch`: false, mobile windows are already active when tappable
402 pub fn first_focus(&self) -> bool {
403 match self {
404 ClickEvent::Keyboard(_) => false,
405 ClickEvent::Mouse(event) => event.down.first_mouse,
406 ClickEvent::Touch(_) => false,
407 }
408 }
409
410 /// Returns the click count of the click event
411 ///
412 /// `Keyboard`: Always 1
413 /// `Mouse`: Count of clicks from MouseUpEvent
414 /// `Touch`: Count of consecutive taps
415 pub fn click_count(&self) -> usize {
416 match self {
417 ClickEvent::Keyboard(_) => 1,
418 ClickEvent::Mouse(event) => event.up.click_count,
419 ClickEvent::Touch(event) => event.tap_count,
420 }
421 }
422
423 /// Returns whether the click event is generated by a keyboard event
424 pub fn is_keyboard(&self) -> bool {
425 match self {
426 ClickEvent::Mouse(_) | ClickEvent::Touch(_) => false,
427 ClickEvent::Keyboard(_) => true,
428 }
429 }
430}
431
432/// An enum representing the keyboard button that was pressed for a click event.
433#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug, Default)]
434pub enum KeyboardButton {
435 /// Enter key was clicked
436 #[default]
437 Enter,
438 /// Space key was clicked
439 Space,
440}
441
442/// An enum representing the mouse button that was pressed.
443#[derive(Hash, Default, PartialEq, Eq, Copy, Clone, Debug)]
444pub enum MouseButton {
445 /// The left mouse button.
446 #[default]
447 Left,
448
449 /// The right mouse button.
450 Right,
451
452 /// The middle mouse button.
453 Middle,
454
455 /// A navigation button, such as back or forward.
456 Navigate(NavigationDirection),
457}
458
459impl MouseButton {
460 /// Get all the mouse buttons in a list.
461 pub fn all() -> Vec<Self> {
462 vec![
463 MouseButton::Left,
464 MouseButton::Right,
465 MouseButton::Middle,
466 MouseButton::Navigate(NavigationDirection::Back),
467 MouseButton::Navigate(NavigationDirection::Forward),
468 ]
469 }
470}
471
472/// A navigation direction, such as back or forward.
473#[derive(Hash, Default, PartialEq, Eq, Copy, Clone, Debug)]
474pub enum NavigationDirection {
475 /// The back button.
476 #[default]
477 Back,
478
479 /// The forward button.
480 Forward,
481}
482
483/// A mouse move event from the platform.
484#[derive(Clone, Debug, Default)]
485pub struct MouseMoveEvent {
486 /// The position of the mouse on the window.
487 pub position: Point<Pixels>,
488
489 /// The mouse button that was pressed, if any.
490 pub pressed_button: Option<MouseButton>,
491
492 /// The modifiers that were held down when the mouse was moved.
493 pub modifiers: Modifiers,
494}
495
496impl Sealed for MouseMoveEvent {}
497impl InputEvent for MouseMoveEvent {
498 fn to_platform_input(self) -> PlatformInput {
499 PlatformInput::MouseMove(self)
500 }
501}
502impl MouseEvent for MouseMoveEvent {}
503
504impl MouseMoveEvent {
505 /// Returns true if the left mouse button is currently held down.
506 pub fn dragging(&self) -> bool {
507 self.pressed_button == Some(MouseButton::Left)
508 }
509}
510
511/// A mouse wheel event from the platform.
512#[derive(Clone, Debug, Default)]
513pub struct ScrollWheelEvent {
514 /// The position of the mouse on the window.
515 pub position: Point<Pixels>,
516
517 /// The change in scroll wheel position for this event.
518 pub delta: ScrollDelta,
519
520 /// The modifiers that were held down when the mouse was moved.
521 pub modifiers: Modifiers,
522
523 /// The phase of the touch event.
524 pub touch_phase: TouchPhase,
525}
526
527impl Sealed for ScrollWheelEvent {}
528impl InputEvent for ScrollWheelEvent {
529 fn to_platform_input(self) -> PlatformInput {
530 PlatformInput::ScrollWheel(self)
531 }
532}
533impl MouseEvent for ScrollWheelEvent {}
534
535impl Deref for ScrollWheelEvent {
536 type Target = Modifiers;
537
538 fn deref(&self) -> &Self::Target {
539 &self.modifiers
540 }
541}
542
543/// The scroll delta for a scroll wheel event.
544#[derive(Clone, Copy, Debug)]
545pub enum ScrollDelta {
546 /// An exact scroll delta in pixels.
547 Pixels(Point<Pixels>),
548 /// An inexact scroll delta in lines.
549 Lines(Point<f32>),
550}
551
552impl Default for ScrollDelta {
553 fn default() -> Self {
554 Self::Lines(Default::default())
555 }
556}
557
558/// A pinch gesture event from the platform, generated when the user performs
559/// a pinch-to-zoom gesture (typically on a trackpad).
560///
561#[derive(Clone, Debug, Default)]
562pub struct PinchEvent {
563 /// The position of the pinch center on the window.
564 pub position: Point<Pixels>,
565
566 /// The zoom delta for this event.
567 /// Positive values indicate zooming in, negative values indicate zooming out.
568 /// For example, 0.1 represents a 10% zoom increase.
569 pub delta: f32,
570
571 /// The modifiers that were held down during the pinch gesture.
572 pub modifiers: Modifiers,
573
574 /// The phase of the pinch gesture.
575 pub phase: TouchPhase,
576}
577
578impl Sealed for PinchEvent {}
579impl InputEvent for PinchEvent {
580 fn to_platform_input(self) -> PlatformInput {
581 PlatformInput::Pinch(self)
582 }
583}
584impl GestureEvent for PinchEvent {}
585impl MouseEvent for PinchEvent {}
586
587impl Deref for PinchEvent {
588 type Target = Modifiers;
589
590 fn deref(&self) -> &Self::Target {
591 &self.modifiers
592 }
593}
594
595impl ScrollDelta {
596 /// Returns true if this is a precise scroll delta in pixels.
597 pub fn precise(&self) -> bool {
598 match self {
599 ScrollDelta::Pixels(_) => true,
600 ScrollDelta::Lines(_) => false,
601 }
602 }
603
604 /// Converts this scroll event into exact pixels.
605 pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
606 match self {
607 ScrollDelta::Pixels(delta) => *delta,
608 ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
609 }
610 }
611
612 /// Combines two scroll deltas into one.
613 /// If the signs of the deltas are the same (both positive or both negative),
614 /// the deltas are added together. If the signs are opposite, the second delta
615 /// (other) is used, effectively overriding the first delta.
616 pub fn coalesce(self, other: ScrollDelta) -> ScrollDelta {
617 match (self, other) {
618 (ScrollDelta::Pixels(a), ScrollDelta::Pixels(b)) => {
619 let x = if a.x.signum() == b.x.signum() {
620 a.x + b.x
621 } else {
622 b.x
623 };
624
625 let y = if a.y.signum() == b.y.signum() {
626 a.y + b.y
627 } else {
628 b.y
629 };
630
631 ScrollDelta::Pixels(point(x, y))
632 }
633
634 (ScrollDelta::Lines(a), ScrollDelta::Lines(b)) => {
635 let x = if a.x.signum() == b.x.signum() {
636 a.x + b.x
637 } else {
638 b.x
639 };
640
641 let y = if a.y.signum() == b.y.signum() {
642 a.y + b.y
643 } else {
644 b.y
645 };
646
647 ScrollDelta::Lines(point(x, y))
648 }
649
650 _ => other,
651 }
652 }
653}
654
655/// A mouse exit event from the platform, generated when the mouse leaves the window.
656#[derive(Clone, Debug, Default)]
657pub struct MouseExitEvent {
658 /// The position of the mouse relative to the window.
659 pub position: Point<Pixels>,
660 /// The mouse button that was pressed, if any.
661 pub pressed_button: Option<MouseButton>,
662 /// The modifiers that were held down when the mouse was moved.
663 pub modifiers: Modifiers,
664}
665
666impl Sealed for MouseExitEvent {}
667impl InputEvent for MouseExitEvent {
668 fn to_platform_input(self) -> PlatformInput {
669 PlatformInput::MouseExited(self)
670 }
671}
672
673impl MouseEvent for MouseExitEvent {}
674
675impl Deref for MouseExitEvent {
676 type Target = Modifiers;
677
678 fn deref(&self) -> &Self::Target {
679 &self.modifiers
680 }
681}
682
683/// A collection of paths from the platform, such as from a file drop.
684#[derive(Debug, Clone, Default, Eq, PartialEq)]
685pub struct ExternalPaths(pub SmallVec<[PathBuf; 2]>);
686
687impl ExternalPaths {
688 /// Convert this collection of paths into a slice.
689 pub fn paths(&self) -> &[PathBuf] {
690 &self.0
691 }
692}
693
694impl Render for ExternalPaths {
695 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
696 // the platform will render icons for the dragged files
697 Empty
698 }
699}
700
701/// A file drop event from the platform, generated when files are dragged and dropped onto the window.
702#[derive(Debug, Clone)]
703pub enum FileDropEvent {
704 /// The files have entered the window.
705 Entered {
706 /// The position of the mouse relative to the window.
707 position: Point<Pixels>,
708 /// The paths of the files that are being dragged.
709 paths: ExternalPaths,
710 },
711 /// The files are being dragged over the window
712 Pending {
713 /// The position of the mouse relative to the window.
714 position: Point<Pixels>,
715 },
716 /// The files have been dropped onto the window.
717 Submit {
718 /// The position of the mouse relative to the window.
719 position: Point<Pixels>,
720 },
721 /// The user has stopped dragging the files over the window.
722 Exited,
723}
724
725impl Sealed for FileDropEvent {}
726impl InputEvent for FileDropEvent {
727 fn to_platform_input(self) -> PlatformInput {
728 PlatformInput::FileDrop(self)
729 }
730}
731impl MouseEvent for FileDropEvent {}
732
733/// An enum corresponding to all kinds of platform input events.
734#[derive(Clone, Debug)]
735pub enum PlatformInput {
736 /// A key was pressed.
737 KeyDown(KeyDownEvent),
738 /// A key was released.
739 KeyUp(KeyUpEvent),
740 /// The keyboard modifiers were changed.
741 ModifiersChanged(ModifiersChangedEvent),
742 /// The mouse was pressed.
743 MouseDown(MouseDownEvent),
744 /// The mouse was released.
745 MouseUp(MouseUpEvent),
746 /// Mouse pressure.
747 MousePressure(MousePressureEvent),
748 /// The mouse was moved.
749 MouseMove(MouseMoveEvent),
750 /// The mouse exited the window.
751 MouseExited(MouseExitEvent),
752 /// The scroll wheel was used.
753 ScrollWheel(ScrollWheelEvent),
754 /// A pinch gesture was performed.
755 Pinch(PinchEvent),
756 /// Files were dragged and dropped onto the window.
757 FileDrop(FileDropEvent),
758 /// A raw touch event on a touch screen.
759 Touch(TouchEvent),
760}
761
762impl PlatformInput {
763 pub(crate) fn mouse_event(&self) -> Option<&dyn Any> {
764 match self {
765 PlatformInput::KeyDown { .. } => None,
766 PlatformInput::KeyUp { .. } => None,
767 PlatformInput::ModifiersChanged { .. } => None,
768 PlatformInput::MouseDown(event) => Some(event),
769 PlatformInput::MouseUp(event) => Some(event),
770 PlatformInput::MouseMove(event) => Some(event),
771 PlatformInput::MousePressure(event) => Some(event),
772 PlatformInput::MouseExited(event) => Some(event),
773 PlatformInput::ScrollWheel(event) => Some(event),
774 PlatformInput::Pinch(event) => Some(event),
775 PlatformInput::FileDrop(event) => Some(event),
776 PlatformInput::Touch(_) => None,
777 }
778 }
779
780 pub(crate) fn keyboard_event(&self) -> Option<&dyn Any> {
781 match self {
782 PlatformInput::KeyDown(event) => Some(event),
783 PlatformInput::KeyUp(event) => Some(event),
784 PlatformInput::ModifiersChanged(event) => Some(event),
785 PlatformInput::MouseDown(_) => None,
786 PlatformInput::MouseUp(_) => None,
787 PlatformInput::MouseMove(_) => None,
788 PlatformInput::MousePressure(_) => None,
789 PlatformInput::MouseExited(_) => None,
790 PlatformInput::ScrollWheel(_) => None,
791 PlatformInput::Pinch(_) => None,
792 PlatformInput::FileDrop(_) => None,
793 PlatformInput::Touch(_) => None,
794 }
795 }
796
797 /// Returns the touch event contained in this input, if any.
798 pub fn touch_event(&self) -> Option<&TouchEvent> {
799 match self {
800 PlatformInput::Touch(event) => Some(event),
801 _ => None,
802 }
803 }
804}
805
806#[cfg(test)]
807mod test {
808
809 use crate::{
810 self as gpui, AppContext as _, Context, FocusHandle, InteractiveElement, IntoElement,
811 KeyBinding, Keystroke, ParentElement, Render, TestAppContext, Window, div,
812 };
813
814 struct TestView {
815 saw_key_down: bool,
816 saw_action: bool,
817 focus_handle: FocusHandle,
818 }
819
820 actions!(test_only, [TestAction]);
821
822 impl Render for TestView {
823 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
824 div().id("testview").child(
825 div()
826 .key_context("parent")
827 .on_key_down(cx.listener(|this, _, _, cx| {
828 cx.stop_propagation();
829 this.saw_key_down = true
830 }))
831 .on_action(cx.listener(|this: &mut TestView, _: &TestAction, _, _| {
832 this.saw_action = true
833 }))
834 .child(
835 div()
836 .key_context("nested")
837 .track_focus(&self.focus_handle)
838 .into_element(),
839 ),
840 )
841 }
842 }
843
844 #[gpui::test]
845 fn test_on_events(cx: &mut TestAppContext) {
846 let window = cx.update(|cx| {
847 cx.open_window(Default::default(), |_, cx| {
848 cx.new(|cx| TestView {
849 saw_key_down: false,
850 saw_action: false,
851 focus_handle: cx.focus_handle(),
852 })
853 })
854 .unwrap()
855 });
856
857 cx.update(|cx| {
858 cx.bind_keys(vec![KeyBinding::new("ctrl-g", TestAction, Some("parent"))]);
859 });
860
861 window
862 .update(cx, |test_view, window, cx| {
863 window.focus(&test_view.focus_handle, cx)
864 })
865 .unwrap();
866
867 cx.dispatch_keystroke(*window, Keystroke::parse("a").unwrap());
868 cx.dispatch_keystroke(*window, Keystroke::parse("ctrl-g").unwrap());
869
870 window
871 .update(cx, |test_view, _, _| {
872 assert!(test_view.saw_key_down || test_view.saw_action);
873 assert!(test_view.saw_key_down);
874 assert!(test_view.saw_action);
875 })
876 .unwrap();
877 }
878}
879