use bevy::ecs::message::Messages;
use bevy::ecs::system::SystemParam;
use bevy::input::mouse::{MouseButtonInput, MouseWheel};
use bevy::prelude::*;
use bevy::window::{CursorMoved, PrimaryWindow, WindowEvent};
#[cfg(feature = "plugin-screenshot")]
use bevy::camera::{ImageRenderTarget, NormalizedRenderTarget};
#[cfg(feature = "plugin-screenshot")]
use bevy::input::{mouse::MouseButton, ButtonState};
#[cfg(feature = "plugin-screenshot")]
use bevy::picking::pointer::{Location, PointerAction, PointerButton, PointerId, PointerInput};
#[derive(SystemParam)]
pub struct PointerRoute<'w, 's> {
primary: Query<'w, 's, Entity, With<PrimaryWindow>>,
window_events: Option<ResMut<'w, Messages<WindowEvent>>>,
cursor_messages: Option<ResMut<'w, Messages<CursorMoved>>>,
#[cfg(feature = "plugin-screenshot")]
target: Option<Res<'w, super::screenshot::DebugCaptureTarget>>,
#[cfg(feature = "plugin-screenshot")]
pointer: Option<ResMut<'w, Messages<PointerInput>>>,
}
impl PointerRoute<'_, '_> {
pub fn window_or_primary(&self, given: Entity) -> Entity {
if given == Entity::PLACEHOLDER {
self.primary.single().unwrap_or(given)
} else {
given
}
}
#[cfg(feature = "plugin-screenshot")]
fn image_location(&self, at: Vec2) -> Option<Location> {
let target = self.target.as_ref()?;
self.pointer.as_ref()?;
Some(Location {
target: NormalizedRenderTarget::Image(ImageRenderTarget {
handle: target.image.clone(),
scale_factor: 1.0,
}),
position: at,
})
}
pub fn moved(&mut self, from: Option<Vec2>, to: Vec2) {
let window = self.primary.single();
if let Ok(window) = window {
let event = CursorMoved { window, position: to, delta: from.map(|f| to - f) };
if let Some(messages) = self.cursor_messages.as_mut() {
messages.write(event.clone());
}
#[cfg(feature = "plugin-screenshot")]
if self.move_on_image(from, to) {
return;
}
if let Some(events) = self.window_events.as_mut() {
events.write(WindowEvent::CursorMoved(event));
}
} else {
#[cfg(feature = "plugin-screenshot")]
self.move_on_image(from, to);
}
}
#[cfg(feature = "plugin-screenshot")]
fn move_on_image(&mut self, from: Option<Vec2>, to: Vec2) -> bool {
let Some(location) = self.image_location(to) else { return false };
if let Some(pointer) = self.pointer.as_mut() {
let delta = to - from.unwrap_or(Vec2::ZERO);
pointer.write(PointerInput::new(PointerId::Mouse, location, PointerAction::Move { delta }));
}
true
}
pub fn button(&mut self, message: &MouseButtonInput, at: Vec2) {
#[cfg(feature = "plugin-screenshot")]
if let Some(location) = self.image_location(at) {
let button = match message.button {
MouseButton::Left => PointerButton::Primary,
MouseButton::Right => PointerButton::Secondary,
MouseButton::Middle => PointerButton::Middle,
_ => return,
};
let action = match message.state {
ButtonState::Pressed => PointerAction::Press(button),
ButtonState::Released => PointerAction::Release(button),
};
if let Some(pointer) = self.pointer.as_mut() {
pointer.write(PointerInput::new(PointerId::Mouse, location, action));
}
return;
}
#[cfg(not(feature = "plugin-screenshot"))]
let _ = at;
if let Some(events) = self.window_events.as_mut() {
events.write(WindowEvent::MouseButtonInput(*message));
}
}
pub fn wheel(&mut self, message: &MouseWheel, at: Vec2) {
#[cfg(feature = "plugin-screenshot")]
if let Some(location) = self.image_location(at) {
if let Some(pointer) = self.pointer.as_mut() {
pointer.write(PointerInput::new(
PointerId::Mouse,
location,
PointerAction::Scroll {
x: message.x,
y: message.y,
unit: message.unit,
phase: message.phase,
},
));
}
return;
}
#[cfg(not(feature = "plugin-screenshot"))]
let _ = at;
if let Some(events) = self.window_events.as_mut() {
events.write(WindowEvent::MouseWheel(*message));
}
}
}