winit/
event.rs

1//! The [`Event`] enum and assorted supporting types.
2//!
3//! These are sent to the closure given to [`EventLoop::run(...)`], where they get
4//! processed and used to modify the program state. For more details, see the root-level documentation.
5//!
6//! Some of these events represent different "parts" of a traditional event-handling loop. You could
7//! approximate the basic ordering loop of [`EventLoop::run(...)`] like this:
8//!
9//! ```rust,ignore
10//! let mut control_flow = ControlFlow::Poll;
11//! let mut start_cause = StartCause::Init;
12//!
13//! while control_flow != ControlFlow::Exit {
14//!     event_handler(NewEvents(start_cause), ..., &mut control_flow);
15//!
16//!     for e in (window events, user events, device events) {
17//!         event_handler(e, ..., &mut control_flow);
18//!     }
19//!     event_handler(MainEventsCleared, ..., &mut control_flow);
20//!
21//!     for w in (redraw windows) {
22//!         event_handler(RedrawRequested(w), ..., &mut control_flow);
23//!     }
24//!     event_handler(RedrawEventsCleared, ..., &mut control_flow);
25//!
26//!     start_cause = wait_if_necessary(control_flow);
27//! }
28//!
29//! event_handler(LoopDestroyed, ..., &mut control_flow);
30//! ```
31//!
32//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully
33//! describes what happens in what order.
34//!
35//! [`EventLoop::run(...)`]: crate::event_loop::EventLoop::run
36//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
37use instant::Instant;
38use std::path::PathBuf;
39
40#[cfg(doc)]
41use crate::window::Window;
42use crate::{
43    dpi::{PhysicalPosition, PhysicalSize},
44    platform_impl,
45    window::{Theme, WindowId},
46};
47
48/// Describes a generic event.
49///
50/// See the module-level docs for more information on the event loop manages each event.
51#[derive(Debug, PartialEq)]
52pub enum Event<'a, T: 'static> {
53    /// Emitted when new events arrive from the OS to be processed.
54    ///
55    /// This event type is useful as a place to put code that should be done before you start
56    /// processing events, such as updating frame timing information for benchmarking or checking
57    /// the [`StartCause`] to see if a timer set by
58    /// [`ControlFlow::WaitUntil`](crate::event_loop::ControlFlow::WaitUntil) has elapsed.
59    NewEvents(StartCause),
60
61    /// Emitted when the OS sends an event to a winit window.
62    WindowEvent {
63        window_id: WindowId,
64        event: WindowEvent<'a>,
65    },
66
67    /// Emitted when the OS sends an event to a device.
68    DeviceEvent {
69        device_id: DeviceId,
70        event: DeviceEvent,
71    },
72
73    /// Emitted when an event is sent from [`EventLoopProxy::send_event`](crate::event_loop::EventLoopProxy::send_event)
74    UserEvent(T),
75
76    /// Emitted when the application has been suspended.
77    ///
78    /// # Portability
79    ///
80    /// Not all platforms support the notion of suspending applications, and there may be no
81    /// technical way to guarantee being able to emit a `Suspended` event if the OS has
82    /// no formal application lifecycle (currently only Android and iOS do). For this reason,
83    /// Winit does not currently try to emit pseudo `Suspended` events before the application
84    /// quits on platforms without an application lifecycle.
85    ///
86    /// Considering that the implementation of `Suspended` and [`Resumed`] events may be internally
87    /// driven by multiple platform-specific events, and that there may be subtle differences across
88    /// platforms with how these internal events are delivered, it's recommended that applications
89    /// be able to gracefully handle redundant (i.e. back-to-back) `Suspended` or [`Resumed`] events.
90    ///
91    /// Also see [`Resumed`] notes.
92    ///
93    /// ## Android
94    ///
95    /// On Android, the `Suspended` event is only sent when the application's associated
96    /// [`SurfaceView`] is destroyed. This is expected to closely correlate with the [`onPause`]
97    /// lifecycle event but there may technically be a discrepancy.
98    ///
99    /// [`onPause`]: https://developer.android.com/reference/android/app/Activity#onPause()
100    ///
101    /// Applications that need to run on Android should assume their [`SurfaceView`] has been
102    /// destroyed, which indirectly invalidates any existing render surfaces that may have been
103    /// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
104    ///
105    /// After being `Suspended` on Android applications must drop all render surfaces before
106    /// the event callback completes, which may be re-created when the application is next [`Resumed`].
107    ///
108    /// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
109    /// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
110    /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
111    /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
112    ///
113    /// ## iOS
114    ///
115    /// On iOS, the `Suspended` event is currently emitted in response to an
116    /// [`applicationWillResignActive`] callback which means that the application is
117    /// about to transition from the active to inactive state (according to the
118    /// [iOS application lifecycle]).
119    ///
120    /// [`applicationWillResignActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive
121    /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
122    ///
123    /// [`Resumed`]: Self::Resumed
124    Suspended,
125
126    /// Emitted when the application has been resumed.
127    ///
128    /// For consistency, all platforms emit a `Resumed` event even if they don't themselves have a
129    /// formal suspend/resume lifecycle. For systems without a standard suspend/resume lifecycle
130    /// the `Resumed` event is always emitted after the [`NewEvents(StartCause::Init)`][StartCause::Init]
131    /// event.
132    ///
133    /// # Portability
134    ///
135    /// It's recommended that applications should only initialize their graphics context and create
136    /// a window after they have received their first `Resumed` event. Some systems
137    /// (specifically Android) won't allow applications to create a render surface until they are
138    /// resumed.
139    ///
140    /// Considering that the implementation of [`Suspended`] and `Resumed` events may be internally
141    /// driven by multiple platform-specific events, and that there may be subtle differences across
142    /// platforms with how these internal events are delivered, it's recommended that applications
143    /// be able to gracefully handle redundant (i.e. back-to-back) [`Suspended`] or `Resumed` events.
144    ///
145    /// Also see [`Suspended`] notes.
146    ///
147    /// ## Android
148    ///
149    /// On Android, the `Resumed` event is sent when a new [`SurfaceView`] has been created. This is
150    /// expected to closely correlate with the [`onResume`] lifecycle event but there may technically
151    /// be a discrepancy.
152    ///
153    /// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume()
154    ///
155    /// Applications that need to run on Android must wait until they have been `Resumed`
156    /// before they will be able to create a render surface (such as an `EGLSurface`,
157    /// [`VkSurfaceKHR`] or [`wgpu::Surface`]) which depend on having a
158    /// [`SurfaceView`]. Applications must also assume that if they are [`Suspended`], then their
159    /// render surfaces are invalid and should be dropped.
160    ///
161    /// Also see [`Suspended`] notes.
162    ///
163    /// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView
164    /// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
165    /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html
166    /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html
167    ///
168    /// ## iOS
169    ///
170    /// On iOS, the `Resumed` event is emitted in response to an [`applicationDidBecomeActive`]
171    /// callback which means the application is "active" (according to the
172    /// [iOS application lifecycle]).
173    ///
174    /// [`applicationDidBecomeActive`]: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive
175    /// [iOS application lifecycle]: https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
176    ///
177    /// [`Suspended`]: Self::Suspended
178    Resumed,
179
180    /// Emitted when all of the event loop's input events have been processed and redraw processing
181    /// is about to begin.
182    ///
183    /// This event is useful as a place to put your code that should be run after all
184    /// state-changing events have been handled and you want to do stuff (updating state, performing
185    /// calculations, etc) that happens as the "main body" of your event loop. If your program only draws
186    /// graphics when something changes, it's usually better to do it in response to
187    /// [`Event::RedrawRequested`], which gets emitted
188    /// immediately after this event. Programs that draw graphics continuously, like most games,
189    /// can render here unconditionally for simplicity.
190    MainEventsCleared,
191
192    /// Emitted after [`MainEventsCleared`] when a window should be redrawn.
193    ///
194    /// This gets triggered in two scenarios:
195    /// - The OS has performed an operation that's invalidated the window's contents (such as
196    ///   resizing the window).
197    /// - The application has explicitly requested a redraw via [`Window::request_redraw`].
198    ///
199    /// During each iteration of the event loop, Winit will aggregate duplicate redraw requests
200    /// into a single event, to help avoid duplicating rendering work.
201    ///
202    /// Mainly of interest to applications with mostly-static graphics that avoid redrawing unless
203    /// something changes, like most non-game GUIs.
204    ///
205    ///
206    /// ## Platform-specific
207    ///
208    /// - **macOS / iOS:** Due to implementation difficulties, this will often, but not always, be
209    ///   emitted directly inside `drawRect:`, with neither a preceding [`MainEventsCleared`] nor
210    ///   subsequent `RedrawEventsCleared`. See [#2640] for work on this.
211    ///
212    /// [`MainEventsCleared`]: Self::MainEventsCleared
213    /// [`RedrawEventsCleared`]: Self::RedrawEventsCleared
214    /// [#2640]: https://github.com/rust-windowing/winit/issues/2640
215    RedrawRequested(WindowId),
216
217    /// Emitted after all [`RedrawRequested`] events have been processed and control flow is about to
218    /// be taken away from the program. If there are no `RedrawRequested` events, it is emitted
219    /// immediately after `MainEventsCleared`.
220    ///
221    /// This event is useful for doing any cleanup or bookkeeping work after all the rendering
222    /// tasks have been completed.
223    ///
224    /// [`RedrawRequested`]: Self::RedrawRequested
225    RedrawEventsCleared,
226
227    /// Emitted when the event loop is being shut down.
228    ///
229    /// This is irreversible - if this event is emitted, it is guaranteed to be the last event that
230    /// gets emitted. You generally want to treat this as an "do on quit" event.
231    LoopDestroyed,
232}
233
234impl<T: Clone> Clone for Event<'static, T> {
235    fn clone(&self) -> Self {
236        use self::Event::*;
237        match self {
238            WindowEvent { window_id, event } => WindowEvent {
239                window_id: *window_id,
240                event: event.clone(),
241            },
242            UserEvent(event) => UserEvent(event.clone()),
243            DeviceEvent { device_id, event } => DeviceEvent {
244                device_id: *device_id,
245                event: event.clone(),
246            },
247            NewEvents(cause) => NewEvents(*cause),
248            MainEventsCleared => MainEventsCleared,
249            RedrawRequested(wid) => RedrawRequested(*wid),
250            RedrawEventsCleared => RedrawEventsCleared,
251            LoopDestroyed => LoopDestroyed,
252            Suspended => Suspended,
253            Resumed => Resumed,
254        }
255    }
256}
257
258impl<'a, T> Event<'a, T> {
259    pub fn map_nonuser_event<U>(self) -> Result<Event<'a, U>, Event<'a, T>> {
260        use self::Event::*;
261        match self {
262            UserEvent(_) => Err(self),
263            WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
264            DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
265            NewEvents(cause) => Ok(NewEvents(cause)),
266            MainEventsCleared => Ok(MainEventsCleared),
267            RedrawRequested(wid) => Ok(RedrawRequested(wid)),
268            RedrawEventsCleared => Ok(RedrawEventsCleared),
269            LoopDestroyed => Ok(LoopDestroyed),
270            Suspended => Ok(Suspended),
271            Resumed => Ok(Resumed),
272        }
273    }
274
275    /// If the event doesn't contain a reference, turn it into an event with a `'static` lifetime.
276    /// Otherwise, return `None`.
277    pub fn to_static(self) -> Option<Event<'static, T>> {
278        use self::Event::*;
279        match self {
280            WindowEvent { window_id, event } => event
281                .to_static()
282                .map(|event| WindowEvent { window_id, event }),
283            UserEvent(event) => Some(UserEvent(event)),
284            DeviceEvent { device_id, event } => Some(DeviceEvent { device_id, event }),
285            NewEvents(cause) => Some(NewEvents(cause)),
286            MainEventsCleared => Some(MainEventsCleared),
287            RedrawRequested(wid) => Some(RedrawRequested(wid)),
288            RedrawEventsCleared => Some(RedrawEventsCleared),
289            LoopDestroyed => Some(LoopDestroyed),
290            Suspended => Some(Suspended),
291            Resumed => Some(Resumed),
292        }
293    }
294}
295
296/// Describes the reason the event loop is resuming.
297#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298pub enum StartCause {
299    /// Sent if the time specified by [`ControlFlow::WaitUntil`] has been reached. Contains the
300    /// moment the timeout was requested and the requested resume time. The actual resume time is
301    /// guaranteed to be equal to or after the requested resume time.
302    ///
303    /// [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
304    ResumeTimeReached {
305        start: Instant,
306        requested_resume: Instant,
307    },
308
309    /// Sent if the OS has new events to send to the window, after a wait was requested. Contains
310    /// the moment the wait was requested and the resume time, if requested.
311    WaitCancelled {
312        start: Instant,
313        requested_resume: Option<Instant>,
314    },
315
316    /// Sent if the event loop is being resumed after the loop's control flow was set to
317    /// [`ControlFlow::Poll`].
318    ///
319    /// [`ControlFlow::Poll`]: crate::event_loop::ControlFlow::Poll
320    Poll,
321
322    /// Sent once, immediately after `run` is called. Indicates that the loop was just initialized.
323    Init,
324}
325
326/// Describes an event from a [`Window`].
327#[derive(Debug, PartialEq)]
328pub enum WindowEvent<'a> {
329    /// The size of the window has changed. Contains the client area's new dimensions.
330    Resized(PhysicalSize<u32>),
331
332    /// The position of the window has changed. Contains the window's new position.
333    ///
334    /// ## Platform-specific
335    ///
336    /// - **iOS / Android / Web / Wayland:** Unsupported.
337    Moved(PhysicalPosition<i32>),
338
339    /// The window has been requested to close.
340    CloseRequested,
341
342    /// The window has been destroyed.
343    Destroyed,
344
345    /// A file has been dropped into the window.
346    ///
347    /// When the user drops multiple files at once, this event will be emitted for each file
348    /// separately.
349    DroppedFile(PathBuf),
350
351    /// A file is being hovered over the window.
352    ///
353    /// When the user hovers multiple files at once, this event will be emitted for each file
354    /// separately.
355    HoveredFile(PathBuf),
356
357    /// A file was hovered, but has exited the window.
358    ///
359    /// There will be a single `HoveredFileCancelled` event triggered even if multiple files were
360    /// hovered.
361    HoveredFileCancelled,
362
363    /// The window received a unicode character.
364    ///
365    /// See also the [`Ime`](Self::Ime) event for more complex character sequences.
366    ReceivedCharacter(char),
367
368    /// The window gained or lost focus.
369    ///
370    /// The parameter is true if the window has gained focus, and false if it has lost focus.
371    Focused(bool),
372
373    /// An event from the keyboard has been received.
374    KeyboardInput {
375        device_id: DeviceId,
376        input: KeyboardInput,
377        /// If `true`, the event was generated synthetically by winit
378        /// in one of the following circumstances:
379        ///
380        /// * Synthetic key press events are generated for all keys pressed
381        ///   when a window gains focus. Likewise, synthetic key release events
382        ///   are generated for all keys pressed when a window goes out of focus.
383        ///   ***Currently, this is only functional on X11 and Windows***
384        ///
385        /// Otherwise, this value is always `false`.
386        is_synthetic: bool,
387    },
388
389    /// The keyboard modifiers have changed.
390    ///
391    /// ## Platform-specific
392    ///
393    /// - **Web:** This API is currently unimplemented on the web. This isn't by design - it's an
394    ///   issue, and it should get fixed - but it's the current state of the API.
395    ModifiersChanged(ModifiersState),
396
397    /// An event from an input method.
398    ///
399    /// **Note:** You have to explicitly enable this event using [`Window::set_ime_allowed`].
400    ///
401    /// ## Platform-specific
402    ///
403    /// - **iOS / Android / Web / Orbital:** Unsupported.
404    Ime(Ime),
405
406    /// The cursor has moved on the window.
407    CursorMoved {
408        device_id: DeviceId,
409
410        /// (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this data is
411        /// limited by the display area and it may have been transformed by the OS to implement effects such as cursor
412        /// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
413        position: PhysicalPosition<f64>,
414        #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
415        modifiers: ModifiersState,
416    },
417
418    /// The cursor has entered the window.
419    CursorEntered { device_id: DeviceId },
420
421    /// The cursor has left the window.
422    CursorLeft { device_id: DeviceId },
423
424    /// A mouse wheel movement or touchpad scroll occurred.
425    MouseWheel {
426        device_id: DeviceId,
427        delta: MouseScrollDelta,
428        phase: TouchPhase,
429        #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
430        modifiers: ModifiersState,
431    },
432
433    /// An mouse button press has been received.
434    MouseInput {
435        device_id: DeviceId,
436        state: ElementState,
437        button: MouseButton,
438        #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
439        modifiers: ModifiersState,
440    },
441
442    /// Touchpad magnification event with two-finger pinch gesture.
443    ///
444    /// Positive delta values indicate magnification (zooming in) and
445    /// negative delta values indicate shrinking (zooming out).
446    ///
447    /// ## Platform-specific
448    ///
449    /// - Only available on **macOS**.
450    TouchpadMagnify {
451        device_id: DeviceId,
452        delta: f64,
453        phase: TouchPhase,
454    },
455
456    /// Smart magnification event.
457    ///
458    /// On a Mac, smart magnification is triggered by a double tap with two fingers
459    /// on the trackpad and is commonly used to zoom on a certain object
460    /// (e.g. a paragraph of a PDF) or (sort of like a toggle) to reset any zoom.
461    /// The gesture is also supported in Safari, Pages, etc.
462    ///
463    /// The event is general enough that its generating gesture is allowed to vary
464    /// across platforms. It could also be generated by another device.
465    ///
466    /// Unfortunatly, neither [Windows](https://support.microsoft.com/en-us/windows/touch-gestures-for-windows-a9d28305-4818-a5df-4e2b-e5590f850741)
467    /// nor [Wayland](https://wayland.freedesktop.org/libinput/doc/latest/gestures.html)
468    /// support this gesture or any other gesture with the same effect.
469    ///
470    /// ## Platform-specific
471    ///
472    /// - Only available on **macOS 10.8** and later.
473    SmartMagnify { device_id: DeviceId },
474
475    /// Touchpad rotation event with two-finger rotation gesture.
476    ///
477    /// Positive delta values indicate rotation counterclockwise and
478    /// negative delta values indicate rotation clockwise.
479    ///
480    /// ## Platform-specific
481    ///
482    /// - Only available on **macOS**.
483    TouchpadRotate {
484        device_id: DeviceId,
485        delta: f32,
486        phase: TouchPhase,
487    },
488
489    /// Touchpad pressure event.
490    ///
491    /// At the moment, only supported on Apple forcetouch-capable macbooks.
492    /// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad
493    /// is being pressed) and stage (integer representing the click level).
494    TouchpadPressure {
495        device_id: DeviceId,
496        pressure: f32,
497        stage: i64,
498    },
499
500    /// Motion on some analog axis. May report data redundant to other, more specific events.
501    AxisMotion {
502        device_id: DeviceId,
503        axis: AxisId,
504        value: f64,
505    },
506
507    /// Touch event has been received
508    ///
509    /// ## Platform-specific
510    ///
511    /// - **macOS:** Unsupported.
512    Touch(Touch),
513
514    /// The window's scale factor has changed.
515    ///
516    /// The following user actions can cause DPI changes:
517    ///
518    /// * Changing the display's resolution.
519    /// * Changing the display's scale factor (e.g. in Control Panel on Windows).
520    /// * Moving the window to a display with a different scale factor.
521    ///
522    /// After this event callback has been processed, the window will be resized to whatever value
523    /// is pointed to by the `new_inner_size` reference. By default, this will contain the size suggested
524    /// by the OS, but it can be changed to any value.
525    ///
526    /// For more information about DPI in general, see the [`dpi`](crate::dpi) module.
527    ScaleFactorChanged {
528        scale_factor: f64,
529        new_inner_size: &'a mut PhysicalSize<u32>,
530    },
531
532    /// The system window theme has changed.
533    ///
534    /// Applications might wish to react to this to change the theme of the content of the window
535    /// when the system changes the window theme.
536    ///
537    /// ## Platform-specific
538    ///
539    /// - **iOS / Android / X11 / Wayland / Orbital:** Unsupported.
540    ThemeChanged(Theme),
541
542    /// The window has been occluded (completely hidden from view).
543    ///
544    /// This is different to window visibility as it depends on whether the window is closed,
545    /// minimised, set invisible, or fully occluded by another window.
546    ///
547    /// Platform-specific behavior:
548    /// - **iOS / Android / Web / Wayland / Windows / Orbital:** Unsupported.
549    Occluded(bool),
550}
551
552impl Clone for WindowEvent<'static> {
553    fn clone(&self) -> Self {
554        use self::WindowEvent::*;
555        return match self {
556            Resized(size) => Resized(*size),
557            Moved(pos) => Moved(*pos),
558            CloseRequested => CloseRequested,
559            Destroyed => Destroyed,
560            DroppedFile(file) => DroppedFile(file.clone()),
561            HoveredFile(file) => HoveredFile(file.clone()),
562            HoveredFileCancelled => HoveredFileCancelled,
563            ReceivedCharacter(c) => ReceivedCharacter(*c),
564            Focused(f) => Focused(*f),
565            KeyboardInput {
566                device_id,
567                input,
568                is_synthetic,
569            } => KeyboardInput {
570                device_id: *device_id,
571                input: *input,
572                is_synthetic: *is_synthetic,
573            },
574            Ime(preedit_state) => Ime(preedit_state.clone()),
575            ModifiersChanged(modifiers) => ModifiersChanged(*modifiers),
576            #[allow(deprecated)]
577            CursorMoved {
578                device_id,
579                position,
580                modifiers,
581            } => CursorMoved {
582                device_id: *device_id,
583                position: *position,
584                modifiers: *modifiers,
585            },
586            CursorEntered { device_id } => CursorEntered {
587                device_id: *device_id,
588            },
589            CursorLeft { device_id } => CursorLeft {
590                device_id: *device_id,
591            },
592            #[allow(deprecated)]
593            MouseWheel {
594                device_id,
595                delta,
596                phase,
597                modifiers,
598            } => MouseWheel {
599                device_id: *device_id,
600                delta: *delta,
601                phase: *phase,
602                modifiers: *modifiers,
603            },
604            #[allow(deprecated)]
605            MouseInput {
606                device_id,
607                state,
608                button,
609                modifiers,
610            } => MouseInput {
611                device_id: *device_id,
612                state: *state,
613                button: *button,
614                modifiers: *modifiers,
615            },
616            TouchpadMagnify {
617                device_id,
618                delta,
619                phase,
620            } => TouchpadMagnify {
621                device_id: *device_id,
622                delta: *delta,
623                phase: *phase,
624            },
625            SmartMagnify { device_id } => SmartMagnify {
626                device_id: *device_id,
627            },
628            TouchpadRotate {
629                device_id,
630                delta,
631                phase,
632            } => TouchpadRotate {
633                device_id: *device_id,
634                delta: *delta,
635                phase: *phase,
636            },
637            TouchpadPressure {
638                device_id,
639                pressure,
640                stage,
641            } => TouchpadPressure {
642                device_id: *device_id,
643                pressure: *pressure,
644                stage: *stage,
645            },
646            AxisMotion {
647                device_id,
648                axis,
649                value,
650            } => AxisMotion {
651                device_id: *device_id,
652                axis: *axis,
653                value: *value,
654            },
655            Touch(touch) => Touch(*touch),
656            ThemeChanged(theme) => ThemeChanged(*theme),
657            ScaleFactorChanged { .. } => {
658                unreachable!("Static event can't be about scale factor changing")
659            }
660            Occluded(occluded) => Occluded(*occluded),
661        };
662    }
663}
664
665impl<'a> WindowEvent<'a> {
666    pub fn to_static(self) -> Option<WindowEvent<'static>> {
667        use self::WindowEvent::*;
668        match self {
669            Resized(size) => Some(Resized(size)),
670            Moved(position) => Some(Moved(position)),
671            CloseRequested => Some(CloseRequested),
672            Destroyed => Some(Destroyed),
673            DroppedFile(file) => Some(DroppedFile(file)),
674            HoveredFile(file) => Some(HoveredFile(file)),
675            HoveredFileCancelled => Some(HoveredFileCancelled),
676            ReceivedCharacter(c) => Some(ReceivedCharacter(c)),
677            Focused(focused) => Some(Focused(focused)),
678            KeyboardInput {
679                device_id,
680                input,
681                is_synthetic,
682            } => Some(KeyboardInput {
683                device_id,
684                input,
685                is_synthetic,
686            }),
687            ModifiersChanged(modifiers) => Some(ModifiersChanged(modifiers)),
688            Ime(event) => Some(Ime(event)),
689            #[allow(deprecated)]
690            CursorMoved {
691                device_id,
692                position,
693                modifiers,
694            } => Some(CursorMoved {
695                device_id,
696                position,
697                modifiers,
698            }),
699            CursorEntered { device_id } => Some(CursorEntered { device_id }),
700            CursorLeft { device_id } => Some(CursorLeft { device_id }),
701            #[allow(deprecated)]
702            MouseWheel {
703                device_id,
704                delta,
705                phase,
706                modifiers,
707            } => Some(MouseWheel {
708                device_id,
709                delta,
710                phase,
711                modifiers,
712            }),
713            #[allow(deprecated)]
714            MouseInput {
715                device_id,
716                state,
717                button,
718                modifiers,
719            } => Some(MouseInput {
720                device_id,
721                state,
722                button,
723                modifiers,
724            }),
725            TouchpadMagnify {
726                device_id,
727                delta,
728                phase,
729            } => Some(TouchpadMagnify {
730                device_id,
731                delta,
732                phase,
733            }),
734            SmartMagnify { device_id } => Some(SmartMagnify { device_id }),
735            TouchpadRotate {
736                device_id,
737                delta,
738                phase,
739            } => Some(TouchpadRotate {
740                device_id,
741                delta,
742                phase,
743            }),
744            TouchpadPressure {
745                device_id,
746                pressure,
747                stage,
748            } => Some(TouchpadPressure {
749                device_id,
750                pressure,
751                stage,
752            }),
753            AxisMotion {
754                device_id,
755                axis,
756                value,
757            } => Some(AxisMotion {
758                device_id,
759                axis,
760                value,
761            }),
762            Touch(touch) => Some(Touch(touch)),
763            ThemeChanged(theme) => Some(ThemeChanged(theme)),
764            ScaleFactorChanged { .. } => None,
765            Occluded(occluded) => Some(Occluded(occluded)),
766        }
767    }
768}
769
770/// Identifier of an input device.
771///
772/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which
773/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or
774/// physical. Virtual devices typically aggregate inputs from multiple physical devices.
775#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
776pub struct DeviceId(pub(crate) platform_impl::DeviceId);
777
778impl DeviceId {
779    /// Returns a dummy id, useful for unit testing.
780    ///
781    /// # Safety
782    ///
783    /// The only guarantee made about the return value of this function is that
784    /// it will always be equal to itself and to future values returned by this function.
785    /// No other guarantees are made. This may be equal to a real `DeviceId`.
786    ///
787    /// **Passing this into a winit function will result in undefined behavior.**
788    pub const unsafe fn dummy() -> Self {
789        DeviceId(platform_impl::DeviceId::dummy())
790    }
791}
792
793/// Represents raw hardware events that are not associated with any particular window.
794///
795/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person
796/// game controls. Many physical actions, such as mouse movement, can produce both device and window events. Because
797/// window events typically arise from virtual devices (corresponding to GUI cursors and keyboard focus) the device IDs
798/// may not match.
799///
800/// Note that these events are delivered regardless of input focus.
801#[derive(Clone, Debug, PartialEq)]
802pub enum DeviceEvent {
803    Added,
804    Removed,
805
806    /// Change in physical position of a pointing device.
807    ///
808    /// This represents raw, unfiltered physical motion. Not to be confused with [`WindowEvent::CursorMoved`].
809    MouseMotion {
810        /// (x, y) change in position in unspecified units.
811        ///
812        /// Different devices may use different units.
813        delta: (f64, f64),
814    },
815
816    /// Physical scroll event
817    MouseWheel {
818        delta: MouseScrollDelta,
819    },
820
821    /// Motion on some analog axis. This event will be reported for all arbitrary input devices
822    /// that winit supports on this platform, including mouse devices.  If the device is a mouse
823    /// device then this will be reported alongside the MouseMotion event.
824    Motion {
825        axis: AxisId,
826        value: f64,
827    },
828
829    Button {
830        button: ButtonId,
831        state: ElementState,
832    },
833
834    Key(KeyboardInput),
835
836    Text {
837        codepoint: char,
838    },
839}
840
841/// Describes a keyboard input event.
842#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
843#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
844pub struct KeyboardInput {
845    /// Identifies the physical key pressed
846    ///
847    /// This should not change if the user adjusts the host's keyboard map. Use when the physical location of the
848    /// key is more important than the key's host GUI semantics, such as for movement controls in a first-person
849    /// game.
850    pub scancode: ScanCode,
851
852    pub state: ElementState,
853
854    /// Identifies the semantic meaning of the key
855    ///
856    /// Use when the semantics of the key are more important than the physical location of the key, such as when
857    /// implementing appropriate behavior for "page up."
858    pub virtual_keycode: Option<VirtualKeyCode>,
859
860    /// Modifier keys active at the time of this input.
861    ///
862    /// This is tracked internally to avoid tracking errors arising from modifier key state changes when events from
863    /// this device are not being delivered to the application, e.g. due to keyboard focus being elsewhere.
864    #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
865    pub modifiers: ModifiersState,
866}
867
868/// Describes [input method](https://en.wikipedia.org/wiki/Input_method) events.
869///
870/// This is also called a "composition event".
871///
872/// Most keypresses using a latin-like keyboard layout simply generate a [`WindowEvent::ReceivedCharacter`].
873/// However, one couldn't possibly have a key for every single unicode character that the user might want to type
874/// - so the solution operating systems employ is to allow the user to type these using _a sequence of keypresses_ instead.
875///
876/// A prominent example of this is accents - many keyboard layouts allow you to first click the "accent key", and then
877/// the character you want to apply the accent to. This will generate the following event sequence:
878/// ```ignore
879/// // Press "`" key
880/// Ime::Preedit("`", Some((0, 0)))
881/// // Press "E" key
882/// Ime::Preedit("", None) // Synthetic event generated by winit to clear preedit.
883/// Ime::Commit("é")
884/// ```
885///
886/// Additionally, certain input devices are configured to display a candidate box that allow the user to select the
887/// desired character interactively. (To properly position this box, you must use [`Window::set_ime_position`].)
888///
889/// An example of a keyboard layout which uses candidate boxes is pinyin. On a latin keybaord the following event
890/// sequence could be obtained:
891/// ```ignore
892/// // Press "A" key
893/// Ime::Preedit("a", Some((1, 1)))
894/// // Press "B" key
895/// Ime::Preedit("a b", Some((3, 3)))
896/// // Press left arrow key
897/// Ime::Preedit("a b", Some((1, 1)))
898/// // Press space key
899/// Ime::Preedit("啊b", Some((3, 3)))
900/// // Press space key
901/// Ime::Preedit("", None) // Synthetic event generated by winit to clear preedit.
902/// Ime::Commit("啊不")
903/// ```
904#[derive(Debug, Clone, PartialEq, Eq, Hash)]
905#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
906pub enum Ime {
907    /// Notifies when the IME was enabled.
908    ///
909    /// After getting this event you could receive [`Preedit`](Self::Preedit) and
910    /// [`Commit`](Self::Commit) events. You should also start performing IME related requests
911    /// like [`Window::set_ime_position`].
912    Enabled,
913
914    /// Notifies when a new composing text should be set at the cursor position.
915    ///
916    /// The value represents a pair of the preedit string and the cursor begin position and end
917    /// position. When it's `None`, the cursor should be hidden. When `String` is an empty string
918    /// this indicates that preedit was cleared.
919    ///
920    /// The cursor position is byte-wise indexed.
921    Preedit(String, Option<(usize, usize)>),
922
923    /// Notifies when text should be inserted into the editor widget.
924    ///
925    /// Right before this event winit will send empty [`Self::Preedit`] event.
926    Commit(String),
927
928    /// Notifies when the IME was disabled.
929    ///
930    /// After receiving this event you won't get any more [`Preedit`](Self::Preedit) or
931    /// [`Commit`](Self::Commit) events until the next [`Enabled`](Self::Enabled) event. You should
932    /// also stop issuing IME related requests like [`Window::set_ime_position`] and clear pending
933    /// preedit text.
934    Disabled,
935}
936
937/// Describes touch-screen input state.
938#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
939#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
940pub enum TouchPhase {
941    Started,
942    Moved,
943    Ended,
944    Cancelled,
945}
946
947/// Represents a touch event
948///
949/// Every time the user touches the screen, a new [`TouchPhase::Started`] event with an unique
950/// identifier for the finger is generated. When the finger is lifted, an [`TouchPhase::Ended`]
951/// event is generated with the same finger id.
952///
953/// After a `Started` event has been emitted, there may be zero or more `Move`
954/// events when the finger is moved or the touch pressure changes.
955///
956/// The finger id may be reused by the system after an `Ended` event. The user
957/// should assume that a new `Started` event received with the same id has nothing
958/// to do with the old finger and is a new finger.
959///
960/// A [`TouchPhase::Cancelled`] event is emitted when the system has canceled tracking this
961/// touch, such as when the window loses focus, or on iOS if the user moves the
962/// device against their face.
963///
964/// ## Platform-specific
965///
966/// - **macOS:** Unsupported.
967#[derive(Debug, Clone, Copy, PartialEq)]
968pub struct Touch {
969    pub device_id: DeviceId,
970    pub phase: TouchPhase,
971    pub location: PhysicalPosition<f64>,
972    /// Describes how hard the screen was pressed. May be `None` if the platform
973    /// does not support pressure sensitivity.
974    ///
975    /// ## Platform-specific
976    ///
977    /// - Only available on **iOS** 9.0+ and **Windows** 8+.
978    pub force: Option<Force>,
979    /// Unique identifier of a finger.
980    pub id: u64,
981}
982
983/// Describes the force of a touch event
984#[derive(Debug, Clone, Copy, PartialEq)]
985pub enum Force {
986    /// On iOS, the force is calibrated so that the same number corresponds to
987    /// roughly the same amount of pressure on the screen regardless of the
988    /// device.
989    Calibrated {
990        /// The force of the touch, where a value of 1.0 represents the force of
991        /// an average touch (predetermined by the system, not user-specific).
992        ///
993        /// The force reported by Apple Pencil is measured along the axis of the
994        /// pencil. If you want a force perpendicular to the device, you need to
995        /// calculate this value using the `altitude_angle` value.
996        force: f64,
997        /// The maximum possible force for a touch.
998        ///
999        /// The value of this field is sufficiently high to provide a wide
1000        /// dynamic range for values of the `force` field.
1001        max_possible_force: f64,
1002        /// The altitude (in radians) of the stylus.
1003        ///
1004        /// A value of 0 radians indicates that the stylus is parallel to the
1005        /// surface. The value of this property is Pi/2 when the stylus is
1006        /// perpendicular to the surface.
1007        altitude_angle: Option<f64>,
1008    },
1009    /// If the platform reports the force as normalized, we have no way of
1010    /// knowing how much pressure 1.0 corresponds to – we know it's the maximum
1011    /// amount of force, but as to how much force, you might either have to
1012    /// press really really hard, or not hard at all, depending on the device.
1013    Normalized(f64),
1014}
1015
1016impl Force {
1017    /// Returns the force normalized to the range between 0.0 and 1.0 inclusive.
1018    ///
1019    /// Instead of normalizing the force, you should prefer to handle
1020    /// [`Force::Calibrated`] so that the amount of force the user has to apply is
1021    /// consistent across devices.
1022    pub fn normalized(&self) -> f64 {
1023        match self {
1024            Force::Calibrated {
1025                force,
1026                max_possible_force,
1027                altitude_angle,
1028            } => {
1029                let force = match altitude_angle {
1030                    Some(altitude_angle) => force / altitude_angle.sin(),
1031                    None => *force,
1032                };
1033                force / max_possible_force
1034            }
1035            Force::Normalized(force) => *force,
1036        }
1037    }
1038}
1039
1040/// Hardware-dependent keyboard scan code.
1041pub type ScanCode = u32;
1042
1043/// Identifier for a specific analog axis on some device.
1044pub type AxisId = u32;
1045
1046/// Identifier for a specific button on some device.
1047pub type ButtonId = u32;
1048
1049/// Describes the input state of a key.
1050#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
1051#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1052pub enum ElementState {
1053    Pressed,
1054    Released,
1055}
1056
1057/// Describes a button of a mouse controller.
1058#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
1059#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1060pub enum MouseButton {
1061    Left,
1062    Right,
1063    Middle,
1064    Other(u16),
1065}
1066
1067/// Describes a difference in the mouse scroll wheel state.
1068#[derive(Debug, Clone, Copy, PartialEq)]
1069#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1070pub enum MouseScrollDelta {
1071    /// Amount in lines or rows to scroll in the horizontal
1072    /// and vertical directions.
1073    ///
1074    /// Positive values indicate that the content that is being scrolled should move
1075    /// right and down (revealing more content left and up).
1076    LineDelta(f32, f32),
1077
1078    /// Amount in pixels to scroll in the horizontal and
1079    /// vertical direction.
1080    ///
1081    /// Scroll events are expressed as a `PixelDelta` if
1082    /// supported by the device (eg. a touchpad) and
1083    /// platform.
1084    ///
1085    /// Positive values indicate that the content being scrolled should
1086    /// move right/down.
1087    ///
1088    /// For a 'natural scrolling' touch pad (that acts like a touch screen)
1089    /// this means moving your fingers right and down should give positive values,
1090    /// and move the content right and down (to reveal more things left and up).
1091    PixelDelta(PhysicalPosition<f64>),
1092}
1093
1094/// Symbolic name for a keyboard key.
1095#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
1096#[repr(u32)]
1097#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1098pub enum VirtualKeyCode {
1099    /// The '1' key over the letters.
1100    Key1,
1101    /// The '2' key over the letters.
1102    Key2,
1103    /// The '3' key over the letters.
1104    Key3,
1105    /// The '4' key over the letters.
1106    Key4,
1107    /// The '5' key over the letters.
1108    Key5,
1109    /// The '6' key over the letters.
1110    Key6,
1111    /// The '7' key over the letters.
1112    Key7,
1113    /// The '8' key over the letters.
1114    Key8,
1115    /// The '9' key over the letters.
1116    Key9,
1117    /// The '0' key over the 'O' and 'P' keys.
1118    Key0,
1119
1120    A,
1121    B,
1122    C,
1123    D,
1124    E,
1125    F,
1126    G,
1127    H,
1128    I,
1129    J,
1130    K,
1131    L,
1132    M,
1133    N,
1134    O,
1135    P,
1136    Q,
1137    R,
1138    S,
1139    T,
1140    U,
1141    V,
1142    W,
1143    X,
1144    Y,
1145    Z,
1146
1147    /// The Escape key, next to F1.
1148    Escape,
1149
1150    F1,
1151    F2,
1152    F3,
1153    F4,
1154    F5,
1155    F6,
1156    F7,
1157    F8,
1158    F9,
1159    F10,
1160    F11,
1161    F12,
1162    F13,
1163    F14,
1164    F15,
1165    F16,
1166    F17,
1167    F18,
1168    F19,
1169    F20,
1170    F21,
1171    F22,
1172    F23,
1173    F24,
1174
1175    /// Print Screen/SysRq.
1176    Snapshot,
1177    /// Scroll Lock.
1178    Scroll,
1179    /// Pause/Break key, next to Scroll lock.
1180    Pause,
1181
1182    /// `Insert`, next to Backspace.
1183    Insert,
1184    Home,
1185    Delete,
1186    End,
1187    PageDown,
1188    PageUp,
1189
1190    Left,
1191    Up,
1192    Right,
1193    Down,
1194
1195    /// The Backspace key, right over Enter.
1196    // TODO: rename
1197    Back,
1198    /// The Enter key.
1199    Return,
1200    /// The space bar.
1201    Space,
1202
1203    /// The "Compose" key on Linux.
1204    Compose,
1205
1206    Caret,
1207
1208    Numlock,
1209    Numpad0,
1210    Numpad1,
1211    Numpad2,
1212    Numpad3,
1213    Numpad4,
1214    Numpad5,
1215    Numpad6,
1216    Numpad7,
1217    Numpad8,
1218    Numpad9,
1219    NumpadAdd,
1220    NumpadDivide,
1221    NumpadDecimal,
1222    NumpadComma,
1223    NumpadEnter,
1224    NumpadEquals,
1225    NumpadMultiply,
1226    NumpadSubtract,
1227
1228    AbntC1,
1229    AbntC2,
1230    Apostrophe,
1231    Apps,
1232    Asterisk,
1233    At,
1234    Ax,
1235    Backslash,
1236    Calculator,
1237    Capital,
1238    Colon,
1239    Comma,
1240    Convert,
1241    Equals,
1242    Grave,
1243    Kana,
1244    Kanji,
1245    LAlt,
1246    LBracket,
1247    LControl,
1248    LShift,
1249    LWin,
1250    Mail,
1251    MediaSelect,
1252    MediaStop,
1253    Minus,
1254    Mute,
1255    MyComputer,
1256    // also called "Next"
1257    NavigateForward,
1258    // also called "Prior"
1259    NavigateBackward,
1260    NextTrack,
1261    NoConvert,
1262    OEM102,
1263    Period,
1264    PlayPause,
1265    Plus,
1266    Power,
1267    PrevTrack,
1268    RAlt,
1269    RBracket,
1270    RControl,
1271    RShift,
1272    RWin,
1273    Semicolon,
1274    Slash,
1275    Sleep,
1276    Stop,
1277    Sysrq,
1278    Tab,
1279    Underline,
1280    Unlabeled,
1281    VolumeDown,
1282    VolumeUp,
1283    Wake,
1284    WebBack,
1285    WebFavorites,
1286    WebForward,
1287    WebHome,
1288    WebRefresh,
1289    WebSearch,
1290    WebStop,
1291    Yen,
1292    Copy,
1293    Paste,
1294    Cut,
1295}
1296
1297impl ModifiersState {
1298    /// Returns `true` if the shift key is pressed.
1299    pub fn shift(&self) -> bool {
1300        self.intersects(Self::SHIFT)
1301    }
1302    /// Returns `true` if the control key is pressed.
1303    pub fn ctrl(&self) -> bool {
1304        self.intersects(Self::CTRL)
1305    }
1306    /// Returns `true` if the alt key is pressed.
1307    pub fn alt(&self) -> bool {
1308        self.intersects(Self::ALT)
1309    }
1310    /// Returns `true` if the logo key is pressed.
1311    pub fn logo(&self) -> bool {
1312        self.intersects(Self::LOGO)
1313    }
1314}
1315
1316bitflags! {
1317    /// Represents the current state of the keyboard modifiers
1318    ///
1319    /// Each flag represents a modifier and is set if this modifier is active.
1320    #[derive(Default)]
1321    pub struct ModifiersState: u32 {
1322        // left and right modifiers are currently commented out, but we should be able to support
1323        // them in a future release
1324        /// The "shift" key.
1325        const SHIFT = 0b100;
1326        // const LSHIFT = 0b010;
1327        // const RSHIFT = 0b001;
1328        /// The "control" key.
1329        const CTRL = 0b100 << 3;
1330        // const LCTRL = 0b010 << 3;
1331        // const RCTRL = 0b001 << 3;
1332        /// The "alt" key.
1333        const ALT = 0b100 << 6;
1334        // const LALT = 0b010 << 6;
1335        // const RALT = 0b001 << 6;
1336        /// This is the "windows" key on PC and "command" key on Mac.
1337        const LOGO = 0b100 << 9;
1338        // const LLOGO = 0b010 << 9;
1339        // const RLOGO = 0b001 << 9;
1340    }
1341}
1342
1343#[cfg(feature = "serde")]
1344mod modifiers_serde {
1345    use super::ModifiersState;
1346    use serde::{Deserialize, Deserializer, Serialize, Serializer};
1347
1348    #[derive(Default, Serialize, Deserialize)]
1349    #[serde(default)]
1350    #[serde(rename = "ModifiersState")]
1351    pub struct ModifiersStateSerialize {
1352        pub shift: bool,
1353        pub ctrl: bool,
1354        pub alt: bool,
1355        pub logo: bool,
1356    }
1357
1358    impl Serialize for ModifiersState {
1359        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1360        where
1361            S: Serializer,
1362        {
1363            let s = ModifiersStateSerialize {
1364                shift: self.shift(),
1365                ctrl: self.ctrl(),
1366                alt: self.alt(),
1367                logo: self.logo(),
1368            };
1369            s.serialize(serializer)
1370        }
1371    }
1372
1373    impl<'de> Deserialize<'de> for ModifiersState {
1374        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1375        where
1376            D: Deserializer<'de>,
1377        {
1378            let ModifiersStateSerialize {
1379                shift,
1380                ctrl,
1381                alt,
1382                logo,
1383            } = ModifiersStateSerialize::deserialize(deserializer)?;
1384            let mut m = ModifiersState::empty();
1385            m.set(ModifiersState::SHIFT, shift);
1386            m.set(ModifiersState::CTRL, ctrl);
1387            m.set(ModifiersState::ALT, alt);
1388            m.set(ModifiersState::LOGO, logo);
1389            Ok(m)
1390        }
1391    }
1392}