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}