bevy_input/
mouse.rs

1//! The mouse input functionality.
2
3use crate::{ButtonInput, ButtonState};
4use bevy_ecs::{
5    change_detection::DetectChangesMut,
6    entity::Entity,
7    message::{Message, MessageReader},
8    resource::Resource,
9    system::ResMut,
10};
11use bevy_math::Vec2;
12#[cfg(feature = "bevy_reflect")]
13use {
14    bevy_ecs::reflect::ReflectResource,
15    bevy_reflect::{std_traits::ReflectDefault, Reflect},
16};
17
18#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
19use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
20
21/// A mouse button input event.
22///
23/// This event is the translated version of the `WindowEvent::MouseInput` from the `winit` crate.
24///
25/// ## Usage
26///
27/// The event is read inside of the [`mouse_button_input_system`]
28/// to update the [`ButtonInput<MouseButton>`] resource.
29#[derive(Message, Debug, Clone, Copy, PartialEq, Eq)]
30#[cfg_attr(
31    feature = "bevy_reflect",
32    derive(Reflect),
33    reflect(Debug, PartialEq, Clone)
34)]
35#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
36#[cfg_attr(
37    all(feature = "serialize", feature = "bevy_reflect"),
38    reflect(Serialize, Deserialize)
39)]
40pub struct MouseButtonInput {
41    /// The mouse button assigned to the event.
42    pub button: MouseButton,
43    /// The pressed state of the button.
44    pub state: ButtonState,
45    /// Window that received the input.
46    pub window: Entity,
47}
48
49/// A button on a mouse device.
50///
51/// ## Usage
52///
53/// It is used as the generic `T` value of an [`ButtonInput`] to create a `bevy`
54/// resource.
55///
56/// ## Updating
57///
58/// The resource is updated inside of the [`mouse_button_input_system`].
59#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
60#[cfg_attr(
61    feature = "bevy_reflect",
62    derive(Reflect),
63    reflect(Debug, Hash, PartialEq, Clone)
64)]
65#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
66#[cfg_attr(
67    all(feature = "serialize", feature = "bevy_reflect"),
68    reflect(Serialize, Deserialize)
69)]
70pub enum MouseButton {
71    /// The left mouse button.
72    Left,
73    /// The right mouse button.
74    Right,
75    /// The middle mouse button.
76    Middle,
77    /// The back mouse button.
78    Back,
79    /// The forward mouse button.
80    Forward,
81    /// Another mouse button with the associated number.
82    Other(u16),
83}
84
85/// An event reporting the change in physical position of a pointing device.
86///
87/// This represents raw, unfiltered physical motion.
88/// It is the translated version of [`DeviceEvent::MouseMotion`] from the `winit` crate.
89///
90/// All pointing devices connected to a single machine at the same time can emit the event independently.
91/// However, the event data does not make it possible to distinguish which device it is referring to.
92///
93/// [`DeviceEvent::MouseMotion`]: https://docs.rs/winit/latest/winit/event/enum.DeviceEvent.html#variant.MouseMotion
94#[derive(Message, Debug, Clone, Copy, PartialEq)]
95#[cfg_attr(
96    feature = "bevy_reflect",
97    derive(Reflect),
98    reflect(Debug, PartialEq, Clone)
99)]
100#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
101#[cfg_attr(
102    all(feature = "serialize", feature = "bevy_reflect"),
103    reflect(Serialize, Deserialize)
104)]
105pub struct MouseMotion {
106    /// The change in the position of the pointing device since the last event was sent.
107    pub delta: Vec2,
108}
109
110/// The scroll unit.
111///
112/// Describes how a value of a [`MouseWheel`] event has to be interpreted.
113///
114/// The value of the event can either be interpreted as the amount of lines or the amount of pixels
115/// to scroll.
116#[derive(Debug, Hash, Clone, Copy, Eq, PartialEq)]
117#[cfg_attr(
118    feature = "bevy_reflect",
119    derive(Reflect),
120    reflect(Debug, PartialEq, Clone)
121)]
122#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
123#[cfg_attr(
124    all(feature = "serialize", feature = "bevy_reflect"),
125    reflect(Serialize, Deserialize)
126)]
127pub enum MouseScrollUnit {
128    /// The line scroll unit.
129    ///
130    /// The delta of the associated [`MouseWheel`] event corresponds
131    /// to the amount of lines or rows to scroll.
132    Line,
133    /// The pixel scroll unit.
134    ///
135    /// The delta of the associated [`MouseWheel`] event corresponds
136    /// to the amount of pixels to scroll.
137    Pixel,
138}
139
140impl MouseScrollUnit {
141    /// An approximate conversion factor to account for the difference between
142    /// [`MouseScrollUnit::Line`] and [`MouseScrollUnit::Pixel`].
143    ///
144    /// Each line corresponds to many pixels; this must be corrected for in order to ensure that
145    /// mouse wheel controls are scaled properly regardless of the provided input events for the end user.
146    ///
147    /// This value is correct for Microsoft Edge, but its validity has not been broadly tested.
148    /// Please file an issue if you find that this differs on certain platforms or hardware!
149    pub const SCROLL_UNIT_CONVERSION_FACTOR: f32 = 100.;
150}
151
152/// A mouse wheel event.
153///
154/// This event is the translated version of the `WindowEvent::MouseWheel` from the `winit` crate.
155#[derive(Message, Debug, Clone, Copy, PartialEq)]
156#[cfg_attr(
157    feature = "bevy_reflect",
158    derive(Reflect),
159    reflect(Debug, PartialEq, Clone)
160)]
161#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
162#[cfg_attr(
163    all(feature = "serialize", feature = "bevy_reflect"),
164    reflect(Serialize, Deserialize)
165)]
166pub struct MouseWheel {
167    /// The mouse scroll unit.
168    pub unit: MouseScrollUnit,
169    /// The horizontal scroll value.
170    pub x: f32,
171    /// The vertical scroll value.
172    pub y: f32,
173    /// Window that received the input.
174    pub window: Entity,
175}
176
177/// Updates the [`ButtonInput<MouseButton>`] resource with the latest [`MouseButtonInput`] events.
178///
179/// ## Differences
180///
181/// The main difference between the [`MouseButtonInput`] event and the [`ButtonInput<MouseButton>`] resource is that
182/// the latter has convenient functions like [`ButtonInput::pressed`], [`ButtonInput::just_pressed`] and [`ButtonInput::just_released`].
183pub fn mouse_button_input_system(
184    mut mouse_button_input: ResMut<ButtonInput<MouseButton>>,
185    mut mouse_button_input_events: MessageReader<MouseButtonInput>,
186) {
187    mouse_button_input.bypass_change_detection().clear();
188    for event in mouse_button_input_events.read() {
189        match event.state {
190            ButtonState::Pressed => mouse_button_input.press(event.button),
191            ButtonState::Released => mouse_button_input.release(event.button),
192        }
193    }
194}
195
196/// Tracks how much the mouse has moved every frame.
197///
198/// This resource is reset to zero every frame.
199///
200/// This resource sums the total [`MouseMotion`] events received this frame.
201#[derive(Resource, Debug, Clone, Copy, PartialEq, Default)]
202#[cfg_attr(
203    feature = "bevy_reflect",
204    derive(Reflect),
205    reflect(Debug, Default, Resource, PartialEq, Clone)
206)]
207#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
208#[cfg_attr(
209    all(feature = "serialize", feature = "bevy_reflect"),
210    reflect(Serialize, Deserialize)
211)]
212pub struct AccumulatedMouseMotion {
213    /// The change in mouse position.
214    pub delta: Vec2,
215}
216
217/// Tracks how much the mouse has scrolled every frame.
218///
219/// This resource is reset to zero every frame.
220///
221/// This resource sums the total [`MouseWheel`] events received this frame.
222#[derive(Resource, Debug, Clone, Copy, PartialEq)]
223#[cfg_attr(
224    feature = "bevy_reflect",
225    derive(Reflect),
226    reflect(Debug, Default, Resource, PartialEq, Clone)
227)]
228#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
229#[cfg_attr(
230    all(feature = "serialize", feature = "bevy_reflect"),
231    reflect(Serialize, Deserialize)
232)]
233pub struct AccumulatedMouseScroll {
234    /// The mouse scroll unit.
235    /// If this value changes while scrolling, then the
236    /// result of the accumulation could be incorrect
237    pub unit: MouseScrollUnit,
238    /// The change in scroll position.
239    pub delta: Vec2,
240}
241
242impl Default for AccumulatedMouseScroll {
243    fn default() -> Self {
244        Self {
245            unit: MouseScrollUnit::Line,
246            delta: Vec2::ZERO,
247        }
248    }
249}
250
251/// Updates the [`AccumulatedMouseMotion`] resource using the [`MouseMotion`] event.
252/// The value of [`AccumulatedMouseMotion`] is reset to zero every frame
253pub fn accumulate_mouse_motion_system(
254    mut mouse_motion_event: MessageReader<MouseMotion>,
255    mut accumulated_mouse_motion: ResMut<AccumulatedMouseMotion>,
256) {
257    let mut delta = Vec2::ZERO;
258    for event in mouse_motion_event.read() {
259        delta += event.delta;
260    }
261    accumulated_mouse_motion.delta = delta;
262}
263
264/// Updates the [`AccumulatedMouseScroll`] resource using the [`MouseWheel`] event.
265/// The value of [`AccumulatedMouseScroll`] is reset to zero every frame
266pub fn accumulate_mouse_scroll_system(
267    mut mouse_scroll_event: MessageReader<MouseWheel>,
268    mut accumulated_mouse_scroll: ResMut<AccumulatedMouseScroll>,
269) {
270    let mut delta = Vec2::ZERO;
271    let mut unit = MouseScrollUnit::Line;
272    for event in mouse_scroll_event.read() {
273        if event.unit != unit {
274            unit = event.unit;
275        }
276        delta += Vec2::new(event.x, event.y);
277    }
278    accumulated_mouse_scroll.delta = delta;
279    accumulated_mouse_scroll.unit = unit;
280}