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}