Skip to main content

tao/
event.rs

1// Copyright 2014-2021 The winit contributors
2// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
3// SPDX-License-Identifier: Apache-2.0
4
5//! The `Event` enum and assorted supporting types.
6//!
7//! These are sent to the closure given to [`EventLoop::run(...)`][event_loop_run], where they get
8//! processed and used to modify the program state. For more details, see the root-level documentation.
9//!
10//! Some of these events represent different "parts" of a traditional event-handling loop. You could
11//! approximate the basic ordering loop of [`EventLoop::run(...)`][event_loop_run] like this:
12//!
13//! ```rust,ignore
14//! let mut control_flow = ControlFlow::Poll;
15//! let mut start_cause = StartCause::Init;
16//!
17//! while control_flow != ControlFlow::Exit {
18//!     event_handler(NewEvents(start_cause), ..., &mut control_flow);
19//!
20//!     for e in (window events, user events, device events) {
21//!         event_handler(e, ..., &mut control_flow);
22//!     }
23//!     event_handler(MainEventsCleared, ..., &mut control_flow);
24//!
25//!     for w in (redraw windows) {
26//!         event_handler(RedrawRequested(w), ..., &mut control_flow);
27//!     }
28//!     event_handler(RedrawEventsCleared, ..., &mut control_flow);
29//!
30//!     start_cause = wait_if_necessary(control_flow);
31//! }
32//!
33//! event_handler(LoopDestroyed, ..., &mut control_flow);
34//! ```
35//!
36//! This leaves out timing details like `ControlFlow::WaitUntil` but hopefully
37//! describes what happens in what order.
38//!
39//! [event_loop_run]: crate::event_loop::EventLoop::run
40use std::{path::PathBuf, time::Instant};
41
42use crate::{
43  dpi::{PhysicalPosition, PhysicalSize},
44  keyboard::{self, ModifiersState},
45  platform_impl,
46  window::{Theme, WindowId},
47};
48
49/// Describes a generic event.
50///
51/// See the module-level docs for more information on the event loop manages each event.
52#[non_exhaustive]
53#[derive(Debug, PartialEq)]
54pub enum Event<'a, T: 'static> {
55  /// Emitted when new events arrive from the OS to be processed.
56  ///
57  /// This event type is useful as a place to put code that should be done before you start
58  /// processing events, such as updating frame timing information for benchmarking or checking
59  /// the [`StartCause`][crate::event::StartCause] to see if a timer set by
60  /// [`ControlFlow::WaitUntil`](crate::event_loop::ControlFlow::WaitUntil) has elapsed.
61  NewEvents(StartCause),
62
63  /// Emitted when the OS sends an event to a tao window.
64  #[non_exhaustive]
65  WindowEvent {
66    window_id: WindowId,
67    event: WindowEvent<'a>,
68  },
69
70  /// Emitted when the OS sends an event to a device.
71  #[non_exhaustive]
72  DeviceEvent {
73    device_id: DeviceId,
74    event: DeviceEvent,
75  },
76
77  /// Emitted when an event is sent from [`EventLoopProxy::send_event`](crate::event_loop::EventLoopProxy::send_event)
78  UserEvent(T),
79
80  /// Emitted when the application has been suspended.
81  Suspended,
82
83  /// Emitted when the application has been resumed.
84  Resumed,
85
86  /// Emitted when all of the event loop's input events have been processed and redraw processing
87  /// is about to begin.
88  ///
89  /// This event is useful as a place to put your code that should be run after all
90  /// state-changing events have been handled and you want to do stuff (updating state, performing
91  /// calculations, etc) that happens as the "main body" of your event loop. If your program only draws
92  /// graphics when something changes, it's usually better to do it in response to
93  /// [`Event::RedrawRequested`](crate::event::Event::RedrawRequested), which gets emitted
94  /// immediately after this event. Programs that draw graphics continuously, like most games,
95  /// can render here unconditionally for simplicity.
96  MainEventsCleared,
97
98  /// Emitted after `MainEventsCleared` when a window should be redrawn.
99  ///
100  /// This gets triggered in two scenarios:
101  /// - The OS has performed an operation that's invalidated the window's contents (such as
102  ///   resizing the window).
103  /// - The application has explicitly requested a redraw via
104  ///   [`Window::request_redraw`](crate::window::Window::request_redraw).
105  ///
106  /// During each iteration of the event loop, Tao will aggregate duplicate redraw requests
107  /// into a single event, to help avoid duplicating rendering work.
108  ///
109  /// Mainly of interest to applications with mostly-static graphics that avoid redrawing unless
110  /// something changes, like most non-game GUIs.
111  ///
112  /// ## Platform-specific
113  ///
114  /// - **Linux: This is triggered by `draw` signal of the gtk window. It can be used to detect if
115  ///   the window is requested to redraw. But widgets it contains are usually not tied to its signal.
116  ///   So if you really want to draw each component, please consider using `connect_draw` method
117  ///   from [`WidgetExt`] directly.**
118  ///
119  /// [`WidgetExt`]: https://gtk-rs.org/gtk3-rs/stable/latest/docs/gtk/prelude/trait.WidgetExt.html
120  RedrawRequested(WindowId),
121
122  /// Emitted after all `RedrawRequested` events have been processed and control flow is about to
123  /// be taken away from the program. If there are no `RedrawRequested` events, it is emitted
124  /// immediately after `MainEventsCleared`.
125  ///
126  /// This event is useful for doing any cleanup or bookkeeping work after all the rendering
127  /// tasks have been completed.
128  RedrawEventsCleared,
129
130  /// Emitted when the event loop is being shut down.
131  ///
132  /// This is irreversable - if this event is emitted, it is guaranteed to be the last event that
133  /// gets emitted. You generally want to treat this as an "do on quit" event.
134  LoopDestroyed,
135
136  /// Emitted when the app is open by external resources, like opening a file or deeplink.
137  Opened { urls: Vec<url::Url> },
138
139  /// ## Platform-specific
140  ///
141  /// - **macOS**: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428638-applicationshouldhandlereopen with return value same as hasVisibleWindows
142  /// - **Other**: Unsupported.
143  #[non_exhaustive]
144  Reopen { has_visible_windows: bool },
145}
146
147impl<T: Clone> Clone for Event<'static, T> {
148  fn clone(&self) -> Self {
149    use self::Event::*;
150    match self {
151      WindowEvent { window_id, event } => WindowEvent {
152        window_id: *window_id,
153        event: event.clone(),
154      },
155      UserEvent(event) => UserEvent(event.clone()),
156      DeviceEvent { device_id, event } => DeviceEvent {
157        device_id: *device_id,
158        event: event.clone(),
159      },
160      NewEvents(cause) => NewEvents(*cause),
161      MainEventsCleared => MainEventsCleared,
162      RedrawRequested(wid) => RedrawRequested(*wid),
163      RedrawEventsCleared => RedrawEventsCleared,
164      LoopDestroyed => LoopDestroyed,
165      Suspended => Suspended,
166      Resumed => Resumed,
167      Opened { urls } => Opened { urls: urls.clone() },
168      Reopen {
169        has_visible_windows,
170      } => Reopen {
171        has_visible_windows: *has_visible_windows,
172      },
173    }
174  }
175}
176
177impl<'a, T> Event<'a, T> {
178  pub fn map_nonuser_event<U>(self) -> Result<Event<'a, U>, Event<'a, T>> {
179    use self::Event::*;
180    match self {
181      UserEvent(_) => Err(self),
182      WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
183      DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
184      NewEvents(cause) => Ok(NewEvents(cause)),
185      MainEventsCleared => Ok(MainEventsCleared),
186      RedrawRequested(wid) => Ok(RedrawRequested(wid)),
187      RedrawEventsCleared => Ok(RedrawEventsCleared),
188      LoopDestroyed => Ok(LoopDestroyed),
189      Suspended => Ok(Suspended),
190      Resumed => Ok(Resumed),
191      Opened { urls } => Ok(Opened { urls }),
192      Reopen {
193        has_visible_windows,
194      } => Ok(Reopen {
195        has_visible_windows,
196      }),
197    }
198  }
199
200  /// If the event doesn't contain a reference, turn it into an event with a `'static` lifetime.
201  /// Otherwise, return `None`.
202  pub fn to_static(self) -> Option<Event<'static, T>> {
203    use self::Event::*;
204    match self {
205      WindowEvent { window_id, event } => event
206        .to_static()
207        .map(|event| WindowEvent { window_id, event }),
208      UserEvent(event) => Some(UserEvent(event)),
209      DeviceEvent { device_id, event } => Some(DeviceEvent { device_id, event }),
210      NewEvents(cause) => Some(NewEvents(cause)),
211      MainEventsCleared => Some(MainEventsCleared),
212      RedrawRequested(wid) => Some(RedrawRequested(wid)),
213      RedrawEventsCleared => Some(RedrawEventsCleared),
214      LoopDestroyed => Some(LoopDestroyed),
215      Suspended => Some(Suspended),
216      Resumed => Some(Resumed),
217      Opened { urls } => Some(Opened { urls }),
218      Reopen {
219        has_visible_windows,
220      } => Some(Reopen {
221        has_visible_windows,
222      }),
223    }
224  }
225}
226
227/// Describes the reason the event loop is resuming.
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229#[non_exhaustive]
230pub enum StartCause {
231  /// Sent if the time specified by `ControlFlow::WaitUntil` has been reached. Contains the
232  /// moment the timeout was requested and the requested resume time. The actual resume time is
233  /// guaranteed to be equal to or after the requested resume time.
234  #[non_exhaustive]
235  ResumeTimeReached {
236    start: Instant,
237    requested_resume: Instant,
238  },
239
240  /// Sent if the OS has new events to send to the window, after a wait was requested. Contains
241  /// the moment the wait was requested and the resume time, if requested.
242  #[non_exhaustive]
243  WaitCancelled {
244    start: Instant,
245    requested_resume: Option<Instant>,
246  },
247
248  /// Sent if the event loop is being resumed after the loop's control flow was set to
249  /// `ControlFlow::Poll`.
250  Poll,
251
252  /// Sent once, immediately after `run` is called. Indicates that the loop was just initialized.
253  Init,
254}
255
256/// Describes an event from a `Window`.
257#[non_exhaustive]
258#[derive(Debug, PartialEq)]
259pub enum WindowEvent<'a> {
260  /// The size of the window has changed. Contains the client area's new dimensions.
261  Resized(PhysicalSize<u32>),
262
263  /// The position of the window has changed. Contains the window's new position.
264  ///
265  /// ## Platform-specific
266  ///
267  /// - **Linux(Wayland)**: will always be (0, 0) since Wayland doesn't support a global cordinate system.
268  Moved(PhysicalPosition<i32>),
269
270  /// The window has been requested to close.
271  CloseRequested,
272
273  /// The window has been destroyed.
274  ///
275  /// ## Platform-specific
276  ///
277  /// - **Windows / Linux:** Only fired if the [`crate::window::Window`] is dropped.
278  /// - **macOS:** Fired if the [`crate::window::Window`] is dropped or the dock `Quit` item is clicked.
279  Destroyed,
280
281  /// A file has been dropped into the window.
282  ///
283  /// When the user drops multiple files at once, this event will be emitted for each file
284  /// separately.
285  DroppedFile(PathBuf),
286
287  /// A file is being hovered over the window.
288  ///
289  /// When the user hovers multiple files at once, this event will be emitted for each file
290  /// separately.
291  HoveredFile(PathBuf),
292
293  /// A file was hovered, but has exited the window.
294  ///
295  /// There will be a single `HoveredFileCancelled` event triggered even if multiple files were
296  /// hovered.
297  HoveredFileCancelled,
298
299  /// The window received a unicode character.
300  ReceivedImeText(String),
301
302  /// The window gained or lost focus.
303  ///
304  /// The parameter is true if the window has gained focus, and false if it has lost focus.
305  Focused(bool),
306
307  /// An event from the keyboard has been received.
308  ///
309  /// ## Platform-specific
310  /// - **Windows:** The shift key overrides NumLock. In other words, while shift is held down,
311  ///   numpad keys act as if NumLock wasn't active. When this is used, the OS sends fake key
312  ///   events which are not marked as `is_synthetic`.
313  #[non_exhaustive]
314  KeyboardInput {
315    device_id: DeviceId,
316    event: KeyEvent,
317
318    /// If `true`, the event was generated synthetically by tao
319    /// in one of the following circumstances:
320    ///
321    /// * Synthetic key press events are generated for all keys pressed
322    ///   when a window gains focus. Likewise, synthetic key release events
323    ///   are generated for all keys pressed when a window goes out of focus.
324    ///   ***Currently, this is only functional on Linux and Windows***
325    ///
326    /// Otherwise, this value is always `false`.
327    is_synthetic: bool,
328  },
329
330  /// The keyboard modifiers have changed.
331  ModifiersChanged(ModifiersState),
332
333  /// The cursor has moved on the window.
334  CursorMoved {
335    device_id: DeviceId,
336
337    /// (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this data is
338    /// limited by the display area and it may have been transformed by the OS to implement effects such as cursor
339    /// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
340    position: PhysicalPosition<f64>,
341    #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
342    modifiers: ModifiersState,
343  },
344
345  /// The cursor has entered the window.
346  CursorEntered { device_id: DeviceId },
347
348  /// The cursor has left the window.
349  CursorLeft { device_id: DeviceId },
350
351  /// A mouse wheel movement or touchpad scroll occurred.
352  MouseWheel {
353    device_id: DeviceId,
354    delta: MouseScrollDelta,
355    phase: TouchPhase,
356    #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
357    modifiers: ModifiersState,
358  },
359
360  /// An mouse button press has been received.
361  MouseInput {
362    device_id: DeviceId,
363    state: ElementState,
364    button: MouseButton,
365    #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
366    modifiers: ModifiersState,
367  },
368
369  /// Touchpad pressure event.
370  ///
371  /// At the moment, only supported on Apple forcetouch-capable macbooks.
372  /// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad
373  /// is being pressed) and stage (integer representing the click level).
374  TouchpadPressure {
375    device_id: DeviceId,
376    pressure: f32,
377    stage: i64,
378  },
379
380  /// Motion on some analog axis. May report data redundant to other, more specific events.
381  AxisMotion {
382    device_id: DeviceId,
383    axis: AxisId,
384    value: f64,
385  },
386
387  /// Touch event has been received
388  Touch(Touch),
389
390  /// The window's scale factor has changed.
391  ///
392  /// The following user actions can cause DPI changes:
393  ///
394  /// * Changing the display's resolution.
395  /// * Changing the display's scale factor (e.g. in Control Panel on Windows).
396  /// * Moving the window to a display with a different scale factor.
397  ///
398  /// After this event callback has been processed, the window will be resized to whatever value
399  /// is pointed to by the `new_inner_size` reference. By default, this will contain the size suggested
400  /// by the OS, but it can be changed to any value.
401  ///
402  /// For more information about DPI in general, see the [`dpi`](crate::dpi) module.
403  ScaleFactorChanged {
404    scale_factor: f64,
405    new_inner_size: &'a mut PhysicalSize<u32>,
406  },
407
408  /// The system window theme has changed.
409  ///
410  /// Applications might wish to react to this to change the theme of the content of the window
411  /// when the system changes the window theme.
412  ///
413  /// ## Platform-specific
414  ///
415  /// - **Linux / Android / iOS:** Unsupported
416  ThemeChanged(Theme),
417
418  /// The window decorations has been clicked.
419  ///
420  /// ## Platform-specific
421  ///
422  /// - **Linux / macOS / Android / iOS:** Unsupported
423  DecorationsClick,
424}
425
426impl Clone for WindowEvent<'static> {
427  fn clone(&self) -> Self {
428    use self::WindowEvent::*;
429    match self {
430      Resized(size) => Resized(*size),
431      Moved(pos) => Moved(*pos),
432      CloseRequested => CloseRequested,
433      Destroyed => Destroyed,
434      DroppedFile(file) => DroppedFile(file.clone()),
435      HoveredFile(file) => HoveredFile(file.clone()),
436      HoveredFileCancelled => HoveredFileCancelled,
437      ReceivedImeText(c) => ReceivedImeText(c.clone()),
438      Focused(f) => Focused(*f),
439      KeyboardInput {
440        device_id,
441        event,
442        is_synthetic,
443      } => KeyboardInput {
444        device_id: *device_id,
445        event: event.clone(),
446        is_synthetic: *is_synthetic,
447      },
448
449      ModifiersChanged(modifiers) => ModifiersChanged(*modifiers),
450      #[allow(deprecated)]
451      CursorMoved {
452        device_id,
453        position,
454        modifiers,
455      } => CursorMoved {
456        device_id: *device_id,
457        position: *position,
458        modifiers: *modifiers,
459      },
460      CursorEntered { device_id } => CursorEntered {
461        device_id: *device_id,
462      },
463      CursorLeft { device_id } => CursorLeft {
464        device_id: *device_id,
465      },
466      #[allow(deprecated)]
467      MouseWheel {
468        device_id,
469        delta,
470        phase,
471        modifiers,
472      } => MouseWheel {
473        device_id: *device_id,
474        delta: *delta,
475        phase: *phase,
476        modifiers: *modifiers,
477      },
478      #[allow(deprecated)]
479      MouseInput {
480        device_id,
481        state,
482        button,
483        modifiers,
484      } => MouseInput {
485        device_id: *device_id,
486        state: *state,
487        button: *button,
488        modifiers: *modifiers,
489      },
490      TouchpadPressure {
491        device_id,
492        pressure,
493        stage,
494      } => TouchpadPressure {
495        device_id: *device_id,
496        pressure: *pressure,
497        stage: *stage,
498      },
499      AxisMotion {
500        device_id,
501        axis,
502        value,
503      } => AxisMotion {
504        device_id: *device_id,
505        axis: *axis,
506        value: *value,
507      },
508      Touch(touch) => Touch(*touch),
509      ThemeChanged(theme) => ThemeChanged(*theme),
510      ScaleFactorChanged { .. } => {
511        unreachable!("Static event can't be about scale factor changing")
512      }
513      DecorationsClick => DecorationsClick,
514    }
515  }
516}
517
518impl<'a> WindowEvent<'a> {
519  pub fn to_static(self) -> Option<WindowEvent<'static>> {
520    use self::WindowEvent::*;
521    match self {
522      Resized(size) => Some(Resized(size)),
523      Moved(position) => Some(Moved(position)),
524      CloseRequested => Some(CloseRequested),
525      Destroyed => Some(Destroyed),
526      DroppedFile(file) => Some(DroppedFile(file)),
527      HoveredFile(file) => Some(HoveredFile(file)),
528      HoveredFileCancelled => Some(HoveredFileCancelled),
529      ReceivedImeText(c) => Some(ReceivedImeText(c)),
530      Focused(focused) => Some(Focused(focused)),
531      KeyboardInput {
532        device_id,
533        event,
534        is_synthetic,
535      } => Some(KeyboardInput {
536        device_id,
537        event,
538        is_synthetic,
539      }),
540      ModifiersChanged(modifiers) => Some(ModifiersChanged(modifiers)),
541      #[allow(deprecated)]
542      CursorMoved {
543        device_id,
544        position,
545        modifiers,
546      } => Some(CursorMoved {
547        device_id,
548        position,
549        modifiers,
550      }),
551      CursorEntered { device_id } => Some(CursorEntered { device_id }),
552      CursorLeft { device_id } => Some(CursorLeft { device_id }),
553      #[allow(deprecated)]
554      MouseWheel {
555        device_id,
556        delta,
557        phase,
558        modifiers,
559      } => Some(MouseWheel {
560        device_id,
561        delta,
562        phase,
563        modifiers,
564      }),
565      #[allow(deprecated)]
566      MouseInput {
567        device_id,
568        state,
569        button,
570        modifiers,
571      } => Some(MouseInput {
572        device_id,
573        state,
574        button,
575        modifiers,
576      }),
577      TouchpadPressure {
578        device_id,
579        pressure,
580        stage,
581      } => Some(TouchpadPressure {
582        device_id,
583        pressure,
584        stage,
585      }),
586      AxisMotion {
587        device_id,
588        axis,
589        value,
590      } => Some(AxisMotion {
591        device_id,
592        axis,
593        value,
594      }),
595      Touch(touch) => Some(Touch(touch)),
596      ThemeChanged(theme) => Some(ThemeChanged(theme)),
597      ScaleFactorChanged { .. } => None,
598      DecorationsClick => Some(DecorationsClick),
599    }
600  }
601}
602
603/// Identifier of an input device.
604///
605/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which
606/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or
607/// physical. Virtual devices typically aggregate inputs from multiple physical devices.
608#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
609pub struct DeviceId(pub(crate) platform_impl::DeviceId);
610
611impl DeviceId {
612  /// # Safety
613  /// Returns a dummy `DeviceId`, useful for unit testing. The only guarantee made about the return
614  /// value of this function is that it will always be equal to itself and to future values returned
615  /// by this function.  No other guarantees are made. This may be equal to a real `DeviceId`.
616  ///
617  /// **Passing this into a tao function will result in undefined behavior.**
618  pub unsafe fn dummy() -> Self {
619    DeviceId(platform_impl::DeviceId::dummy())
620  }
621}
622
623/// Represents raw hardware events that are not associated with any particular window.
624///
625/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person
626/// game controls. Many physical actions, such as mouse movement, can produce both device and window events. Because
627/// window events typically arise from virtual devices (corresponding to GUI cursors and keyboard focus) the device IDs
628/// may not match.
629///
630/// Note that these events are delivered regardless of input focus.
631#[non_exhaustive]
632#[derive(Clone, Debug, PartialEq)]
633pub enum DeviceEvent {
634  Added,
635  Removed,
636
637  /// Change in physical position of a pointing device.
638  ///
639  /// This represents raw, unfiltered physical motion. Not to be confused with `WindowEvent::CursorMoved`.
640  #[non_exhaustive]
641  MouseMotion {
642    /// (x, y) change in position in unspecified units.
643    ///
644    /// Different devices may use different units.
645    delta: (f64, f64),
646  },
647
648  /// Physical scroll event
649  #[non_exhaustive]
650  MouseWheel {
651    delta: MouseScrollDelta,
652  },
653
654  /// Motion on some analog axis.  This event will be reported for all arbitrary input devices
655  /// that tao supports on this platform, including mouse devices.  If the device is a mouse
656  /// device then this will be reported alongside the MouseMotion event.
657  #[non_exhaustive]
658  Motion {
659    axis: AxisId,
660    value: f64,
661  },
662
663  #[non_exhaustive]
664  Button {
665    button: ButtonId,
666    state: ElementState,
667  },
668
669  Key(RawKeyEvent),
670
671  #[non_exhaustive]
672  Text {
673    codepoint: char,
674  },
675}
676
677/// Describes a keyboard input as a raw device event.
678///
679/// Note that holding down a key may produce repeated `RawKeyEvent`s. The
680/// operating system doesn't provide information whether such an event is a
681/// repeat or the initial keypress. An application may emulate this by, for
682/// example keeping a Map/Set of pressed keys and determining whether a keypress
683/// corresponds to an already pressed key.
684#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
685#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
686pub struct RawKeyEvent {
687  pub physical_key: keyboard::KeyCode,
688  pub state: ElementState,
689}
690
691/// Describes a keyboard input targeting a window.
692#[derive(Debug, Clone, Eq, PartialEq, Hash)]
693pub struct KeyEvent {
694  /// Represents the position of a key independent of the currently active layout.
695  ///
696  /// It also uniquely identifies the physical key (i.e. it's mostly synonymous with a scancode).
697  /// The most prevalent use case for this is games. For example the default keys for the player
698  /// to move around might be the W, A, S, and D keys on a US layout. The position of these keys
699  /// is more important than their label, so they should map to Z, Q, S, and D on an "AZERTY"
700  /// layout. (This value is `KeyCode::KeyW` for the Z key on an AZERTY layout.)
701  ///
702  /// Note that `Fn` and `FnLock` key events are not guaranteed to be emitted by `tao`. These
703  /// keys are usually handled at the hardware or OS level.
704  pub physical_key: keyboard::KeyCode,
705
706  /// This value is affected by all modifiers except <kbd>Ctrl</kbd>.
707  ///
708  /// This has two use cases:
709  /// - Allows querying whether the current input is a Dead key.
710  /// - Allows handling key-bindings on platforms which don't
711  ///   support `key_without_modifiers`.
712  ///
713  /// ## Platform-specific
714  /// - **Web:** Dead keys might be reported as the real key instead
715  ///   of `Dead` depending on the browser/OS.
716  pub logical_key: keyboard::Key<'static>,
717
718  /// Contains the text produced by this keypress.
719  ///
720  /// In most cases this is identical to the content
721  /// of the `Character` variant of `logical_key`.
722  /// However, on Windows when a dead key was pressed earlier
723  /// but cannot be combined with the character from this
724  /// keypress, the produced text will consist of two characters:
725  /// the dead-key-character followed by the character resulting
726  /// from this keypress.
727  ///
728  /// An additional difference from `logical_key` is that
729  /// this field stores the text representation of any key
730  /// that has such a representation. For example when
731  /// `logical_key` is `Key::Enter`, this field is `Some("\r")`.
732  ///
733  /// This is `None` if the current keypress cannot
734  /// be interpreted as text.
735  ///
736  /// See also: `text_with_all_modifiers()`
737  pub text: Option<&'static str>,
738
739  pub location: keyboard::KeyLocation,
740  pub state: ElementState,
741  pub repeat: bool,
742
743  pub(crate) platform_specific: platform_impl::KeyEventExtra,
744}
745
746#[cfg(not(any(target_os = "android", target_os = "ios")))]
747impl KeyEvent {
748  /// Identical to `KeyEvent::text` but this is affected by <kbd>Ctrl</kbd>.
749  ///
750  /// For example, pressing <kbd>Ctrl</kbd>+<kbd>a</kbd> produces `Some("\x01")`.
751  pub fn text_with_all_modifiers(&self) -> Option<&str> {
752    self.platform_specific.text_with_all_modifiers
753  }
754
755  /// This value ignores all modifiers including,
756  /// but not limited to <kbd>Shift</kbd>, <kbd>Caps Lock</kbd>,
757  /// and <kbd>Ctrl</kbd>. In most cases this means that the
758  /// unicode character in the resulting string is lowercase.
759  ///
760  /// This is useful for key-bindings / shortcut key combinations.
761  ///
762  /// In case `logical_key` reports `Dead`, this will still report the
763  /// key as `Character` according to the current keyboard layout. This value
764  /// cannot be `Dead`.
765  pub fn key_without_modifiers(&self) -> keyboard::Key<'static> {
766    self.platform_specific.key_without_modifiers.clone()
767  }
768}
769
770#[cfg(any(target_os = "android", target_os = "ios"))]
771impl KeyEvent {
772  /// Identical to `KeyEvent::text`.
773  pub fn text_with_all_modifiers(&self) -> Option<&str> {
774    self.text
775  }
776
777  /// Identical to `KeyEvent::logical_key`.
778  pub fn key_without_modifiers(&self) -> keyboard::Key<'static> {
779    self.logical_key.clone()
780  }
781}
782
783/// Describes touch-screen input state.
784#[non_exhaustive]
785#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
786#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
787pub enum TouchPhase {
788  Started,
789  Moved,
790  Ended,
791  Cancelled,
792}
793
794/// Represents a touch event
795///
796/// Every time the user touches the screen, a new `Start` event with an unique
797/// identifier for the finger is generated. When the finger is lifted, an `End`
798/// event is generated with the same finger id.
799///
800/// After a `Start` event has been emitted, there may be zero or more `Move`
801/// events when the finger is moved or the touch pressure changes.
802///
803/// The finger id may be reused by the system after an `End` event. The user
804/// should assume that a new `Start` event received with the same id has nothing
805/// to do with the old finger and is a new finger.
806///
807/// A `Cancelled` event is emitted when the system has canceled tracking this
808/// touch, such as when the window loses focus, or on iOS if the user moves the
809/// device against their face.
810#[derive(Debug, Clone, Copy, PartialEq)]
811pub struct Touch {
812  pub device_id: DeviceId,
813  pub phase: TouchPhase,
814  pub location: PhysicalPosition<f64>,
815  /// Describes how hard the screen was pressed. May be `None` if the platform
816  /// does not support pressure sensitivity.
817  ///
818  /// ## Platform-specific
819  ///
820  /// - Only available on **iOS** 9.0+ and **Windows** 8+.
821  pub force: Option<Force>,
822  /// Unique identifier of a finger.
823  pub id: u64,
824}
825
826/// Describes the force of a touch event
827#[non_exhaustive]
828#[derive(Debug, Clone, Copy, PartialEq)]
829pub enum Force {
830  /// On iOS, the force is calibrated so that the same number corresponds to
831  /// roughly the same amount of pressure on the screen regardless of the
832  /// device.
833  #[non_exhaustive]
834  Calibrated {
835    /// The force of the touch, where a value of 1.0 represents the force of
836    /// an average touch (predetermined by the system, not user-specific).
837    ///
838    /// The force reported by Apple Pencil is measured along the axis of the
839    /// pencil. If you want a force perpendicular to the device, you need to
840    /// calculate this value using the `altitude_angle` value.
841    force: f64,
842    /// The maximum possible force for a touch.
843    ///
844    /// The value of this field is sufficiently high to provide a wide
845    /// dynamic range for values of the `force` field.
846    max_possible_force: f64,
847    /// The altitude (in radians) of the stylus.
848    ///
849    /// A value of 0 radians indicates that the stylus is parallel to the
850    /// surface. The value of this property is Pi/2 when the stylus is
851    /// perpendicular to the surface.
852    altitude_angle: Option<f64>,
853  },
854  /// If the platform reports the force as normalized, we have no way of
855  /// knowing how much pressure 1.0 corresponds to - we know it's the maximum
856  /// amount of force, but as to how much force, you might either have to
857  /// press really really hard, or not hard at all, depending on the device.
858  Normalized(f64),
859}
860
861impl Force {
862  /// Returns the force normalized to the range between 0.0 and 1.0 inclusive.
863  /// Instead of normalizing the force, you should prefer to handle
864  /// `Force::Calibrated` so that the amount of force the user has to apply is
865  /// consistent across devices.
866  pub fn normalized(&self) -> f64 {
867    match self {
868      Force::Calibrated {
869        force,
870        max_possible_force,
871        altitude_angle,
872      } => {
873        let force = match altitude_angle {
874          Some(altitude_angle) => force / altitude_angle.sin(),
875          None => *force,
876        };
877        force / max_possible_force
878      }
879      Force::Normalized(force) => *force,
880    }
881  }
882}
883
884/// Identifier for a specific analog axis on some device.
885pub type AxisId = u32;
886
887/// Identifier for a specific button on some device.
888pub type ButtonId = u32;
889
890/// Describes the input state of a key.
891#[non_exhaustive]
892#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
893#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
894pub enum ElementState {
895  Pressed,
896  Released,
897}
898
899/// Describes a button of a mouse controller.
900#[non_exhaustive]
901#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
902#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
903pub enum MouseButton {
904  Left,
905  Right,
906  Middle,
907  Other(u16),
908}
909
910/// Describes a difference in the mouse scroll wheel state.
911#[non_exhaustive]
912#[derive(Debug, Clone, Copy, PartialEq)]
913#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
914pub enum MouseScrollDelta {
915  /// Amount in lines or rows to scroll in the horizontal
916  /// and vertical directions.
917  ///
918  /// Positive values indicate movement forward
919  /// (away from the user) or rightwards.
920  LineDelta(f32, f32),
921  /// Amount in pixels to scroll in the horizontal and
922  /// vertical direction.
923  ///
924  /// Scroll events are expressed as a PixelDelta if
925  /// supported by the device (eg. a touchpad) and
926  /// platform.
927  PixelDelta(PhysicalPosition<f64>),
928}