mirror of
https://github.com/bevyengine/bevy
synced 2025-03-07 08:47:24 +00:00
bevy_winit(emit raw winit events) (#15884)
# Objective - Exposes raw winit events making Bevy even more modular and powerful for custom plugin developers (e.g. a custom render plugin). XRef: https://github.com/bevyengine/bevy/issues/5977 It doesn't quite close the issue as sending events is not supported (or not very useful to be precise). I would think that supporting that requires some extra considerations by someone a bit more familiar with the `bevy_winit` crate. That said, this PR could be a nice step forward. ## Solution Emit `RawWinitWindowEvent` objects for each received event. ## Testing I verified that the events are emitted using a basic test app. I don't think it makes sense to solidify this behavior in one of the examples. --- ## Showcase My example usage for a custom `egui_winit` integration: ```rust for ev in winit_events.read() { if ev.window_id == window.id { let _ = egui_winit.on_window_event(&window, &ev.event); } } ``` --------- Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
This commit is contained in:
parent
1fe38b85f1
commit
b9cc6e16da
2 changed files with 40 additions and 11 deletions
|
@ -19,7 +19,7 @@ use bevy_reflect::prelude::ReflectDefault;
|
|||
use bevy_reflect::Reflect;
|
||||
use bevy_window::{RawHandleWrapperHolder, WindowEvent};
|
||||
use core::marker::PhantomData;
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::{event_loop::EventLoop, window::WindowId};
|
||||
|
||||
use bevy_a11y::AccessibilityRequested;
|
||||
use bevy_app::{App, Last, Plugin};
|
||||
|
@ -121,6 +121,7 @@ impl<T: Event> Plugin for WinitPlugin<T> {
|
|||
app.init_non_send_resource::<WinitWindows>()
|
||||
.init_resource::<WinitMonitors>()
|
||||
.init_resource::<WinitSettings>()
|
||||
.add_event::<RawWinitWindowEvent>()
|
||||
.set_runner(winit_runner::<T>)
|
||||
.add_systems(
|
||||
Last,
|
||||
|
@ -153,6 +154,21 @@ impl<T: Event> Plugin for WinitPlugin<T> {
|
|||
#[reflect(Debug, Default)]
|
||||
pub struct WakeUp;
|
||||
|
||||
/// The original window event as produced by Winit. This is meant as an escape
|
||||
/// hatch for power users that wish to add custom Winit integrations.
|
||||
/// If you want to process events for your app or game, you should instead use
|
||||
/// `bevy::window::WindowEvent`, or one of its sub-events.
|
||||
///
|
||||
/// When you receive this event it has already been handled by Bevy's main loop.
|
||||
/// Sending these events will NOT cause them to be processed by Bevy.
|
||||
#[derive(Debug, Clone, Event)]
|
||||
pub struct RawWinitWindowEvent {
|
||||
/// The window for which the event was fired.
|
||||
pub window_id: WindowId,
|
||||
/// The raw winit window event.
|
||||
pub event: winit::event::WindowEvent,
|
||||
}
|
||||
|
||||
/// A wrapper type around [`winit::event_loop::EventLoopProxy`] with the specific
|
||||
/// [`winit::event::Event::UserEvent`] used in the [`WinitPlugin`].
|
||||
///
|
||||
|
|
|
@ -46,8 +46,8 @@ use crate::{
|
|||
accessibility::AccessKitAdapters,
|
||||
converters, create_windows,
|
||||
system::{create_monitors, CachedWindow},
|
||||
AppSendEvent, CreateMonitorParams, CreateWindowParams, EventLoopProxyWrapper, UpdateMode,
|
||||
WinitSettings, WinitWindows,
|
||||
AppSendEvent, CreateMonitorParams, CreateWindowParams, EventLoopProxyWrapper,
|
||||
RawWinitWindowEvent, UpdateMode, WinitSettings, WinitWindows,
|
||||
};
|
||||
|
||||
/// Persistent state that is used to run the [`App`] according to the current
|
||||
|
@ -80,6 +80,8 @@ struct WinitAppRunnerState<T: Event> {
|
|||
previous_lifecycle: AppLifecycle,
|
||||
/// Bevy window events to send
|
||||
bevy_window_events: Vec<bevy_window::WindowEvent>,
|
||||
/// Raw Winit window events to send
|
||||
raw_winit_events: Vec<RawWinitWindowEvent>,
|
||||
_marker: PhantomData<T>,
|
||||
|
||||
event_writer_system_state: SystemState<(
|
||||
|
@ -121,6 +123,7 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||
// 3 seems to be enough, 5 is a safe margin
|
||||
startup_forced_updates: 5,
|
||||
bevy_window_events: Vec::new(),
|
||||
raw_winit_events: Vec::new(),
|
||||
_marker: PhantomData,
|
||||
event_writer_system_state,
|
||||
}
|
||||
|
@ -250,6 +253,12 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||
return;
|
||||
};
|
||||
|
||||
// Store a copy of the event to send to an EventWriter later.
|
||||
self.raw_winit_events.push(RawWinitWindowEvent {
|
||||
window_id,
|
||||
event: event.clone(),
|
||||
});
|
||||
|
||||
// Allow AccessKit to respond to `WindowEvent`s before they reach
|
||||
// the engine.
|
||||
if let Some(adapter) = access_kit_adapters.get_mut(&window) {
|
||||
|
@ -690,14 +699,16 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||
}
|
||||
|
||||
fn forward_bevy_events(&mut self) {
|
||||
let raw_winit_events = self.raw_winit_events.drain(..).collect::<Vec<_>>();
|
||||
let buffered_events = self.bevy_window_events.drain(..).collect::<Vec<_>>();
|
||||
|
||||
if buffered_events.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let world = self.world_mut();
|
||||
|
||||
if !raw_winit_events.is_empty() {
|
||||
world
|
||||
.resource_mut::<Events<RawWinitWindowEvent>>()
|
||||
.send_batch(raw_winit_events);
|
||||
}
|
||||
|
||||
for winit_event in buffered_events.iter() {
|
||||
match winit_event.clone() {
|
||||
BevyWindowEvent::AppLifecycle(e) => {
|
||||
|
@ -784,9 +795,11 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||
}
|
||||
}
|
||||
|
||||
world
|
||||
.resource_mut::<Events<BevyWindowEvent>>()
|
||||
.send_batch(buffered_events);
|
||||
if !buffered_events.is_empty() {
|
||||
world
|
||||
.resource_mut::<Events<BevyWindowEvent>>()
|
||||
.send_batch(buffered_events);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_cursors(&mut self, #[cfg(feature = "custom_cursor")] event_loop: &ActiveEventLoop) {
|
||||
|
|
Loading…
Add table
Reference in a new issue