Skip to main content

bevy_input/
mouse.rs

1//! The mouse input functionality.
2
3use core::ops::{Div, Mul};
4
5use crate::{touch::TouchPhase, ButtonInput, ButtonState};
6#[cfg(feature = "bevy_reflect")]
7use bevy_ecs::prelude::ReflectMessage;
8use bevy_ecs::{
9    change_detection::DetectChangesMut,
10    entity::Entity,
11    message::{Message, MessageReader},
12    resource::Resource,
13    system::ResMut,
14};
15use bevy_math::Vec2;
16use derive_more::{Deref, DerefMut};
17
18#[cfg(feature = "bevy_reflect")]
19use {
20    bevy_ecs::reflect::ReflectResource,
21    bevy_reflect::{std_traits::ReflectDefault, Reflect},
22};
23
24#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
25use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
26
27/// A mouse button input event.
28///
29/// This event is the translated version of the `WindowEvent::MouseInput` from the `winit` crate.
30///
31/// ## Usage
32///
33/// The event is read inside of the [`mouse_button_input_system`]
34/// to update the [`ButtonInput<MouseButton>`] resource.
35#[derive(Message, Debug, Clone, Copy, PartialEq, Eq)]
36#[cfg_attr(
37    feature = "bevy_reflect",
38    derive(Reflect),
39    reflect(Debug, PartialEq, Clone, Message)
40)]
41#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
42#[cfg_attr(
43    all(feature = "serialize", feature = "bevy_reflect"),
44    reflect(Serialize, Deserialize)
45)]
46pub struct MouseButtonInput {
47    /// The mouse button assigned to the event.
48    pub button: MouseButton,
49    /// The pressed state of the button.
50    pub state: ButtonState,
51    /// Window that received the input.
52    pub window: Entity,
53}
54
55/// A button on a mouse device.
56///
57/// ## Usage
58///
59/// It is used as the generic `T` value of an [`ButtonInput`] to create a `bevy`
60/// resource.
61///
62/// ## Updating
63///
64/// The resource is updated inside of the [`mouse_button_input_system`].
65#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
66#[cfg_attr(
67    feature = "bevy_reflect",
68    derive(Reflect),
69    reflect(Debug, Hash, PartialEq, Clone)
70)]
71#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
72#[cfg_attr(
73    all(feature = "serialize", feature = "bevy_reflect"),
74    reflect(Serialize, Deserialize)
75)]
76pub enum MouseButton {
77    /// The left mouse button.
78    Left,
79    /// The right mouse button.
80    Right,
81    /// The middle mouse button.
82    Middle,
83    /// The back mouse button.
84    Back,
85    /// The forward mouse button.
86    Forward,
87    /// Another mouse button with the associated number.
88    Other(u16),
89}
90
91/// An event reporting the change in physical position of a pointing device.
92///
93/// This represents raw, unfiltered physical motion.
94/// It is the translated version of [`DeviceEvent::MouseMotion`] from the `winit` crate.
95///
96/// All pointing devices connected to a single machine at the same time can emit the event independently.
97/// However, the event data does not make it possible to distinguish which device it is referring to.
98///
99/// [`DeviceEvent::MouseMotion`]: https://docs.rs/winit/latest/winit/event/enum.DeviceEvent.html#variant.MouseMotion
100#[derive(Message, Debug, Clone, Copy, PartialEq)]
101#[cfg_attr(
102    feature = "bevy_reflect",
103    derive(Reflect),
104    reflect(Debug, PartialEq, Clone, Message)
105)]
106#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
107#[cfg_attr(
108    all(feature = "serialize", feature = "bevy_reflect"),
109    reflect(Serialize, Deserialize)
110)]
111pub struct MouseMotion {
112    /// The change in the position of the pointing device since the last event was sent.
113    pub delta: Vec2,
114}
115
116/// The scroll unit.
117///
118/// Describes how a value of a [`MouseWheel`] event has to be interpreted.
119///
120/// The value of the event can either be interpreted as the amount of lines or the amount of pixels
121/// to scroll.
122///
123/// To convert this value to the other unit use the [`Resource`] [`MouseScrollPixelsPerLine`]
124#[derive(Debug, Hash, Clone, Copy, Eq, PartialEq)]
125#[cfg_attr(
126    feature = "bevy_reflect",
127    derive(Reflect),
128    reflect(Debug, PartialEq, Clone)
129)]
130#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
131#[cfg_attr(
132    all(feature = "serialize", feature = "bevy_reflect"),
133    reflect(Serialize, Deserialize)
134)]
135pub enum MouseScrollUnit {
136    /// The line scroll unit.
137    ///
138    /// The delta of the associated [`MouseWheel`] event corresponds
139    /// to the amount of lines or rows to scroll.
140    Line,
141    /// The pixel scroll unit.
142    ///
143    /// The delta of the associated [`MouseWheel`] event corresponds
144    /// to the amount of pixels to scroll.
145    Pixel,
146}
147
148/// Describes the quantity of [`MouseScrollUnit::Pixel`]s per [`MouseScrollUnit::Line`]
149///
150/// Different platforms sometimes have different ratios between mouse scroll in pixels and mouse
151/// scroll in lines. Currently you have to set the values for different platforms yourself, although
152/// in future this will be handled automatically. The default of 100.0 pixels per line is a best
153/// guess of what it may be on your platform.
154#[derive(Debug, Clone, Copy, PartialEq, Resource, Deref, DerefMut)]
155#[cfg_attr(
156    feature = "bevy_reflect",
157    derive(Reflect),
158    reflect(Debug, PartialEq, Clone)
159)]
160#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
161#[cfg_attr(
162    all(feature = "serialize", feature = "bevy_reflect"),
163    reflect(Serialize, Deserialize)
164)]
165pub struct MouseScrollPixelsPerLine(f32);
166
167impl Default for MouseScrollPixelsPerLine {
168    fn default() -> Self {
169        MouseScrollPixelsPerLine(100.0)
170    }
171}
172
173impl Mul<MouseScrollPixelsPerLine> for f32 {
174    type Output = f32;
175    fn mul(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
176        self * rhs.0
177    }
178}
179
180impl Div<MouseScrollPixelsPerLine> for f32 {
181    type Output = f32;
182    fn div(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
183        self / rhs.0
184    }
185}
186
187impl Mul<MouseScrollPixelsPerLine> for Vec2 {
188    type Output = Vec2;
189    fn mul(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
190        self * rhs.0
191    }
192}
193
194impl Div<MouseScrollPixelsPerLine> for Vec2 {
195    type Output = Vec2;
196    fn div(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
197        self / rhs.0
198    }
199}
200/// A mouse wheel event.
201///
202/// This event is the translated version of the `WindowEvent::MouseWheel` from the `winit` crate.
203#[derive(Message, Debug, Clone, Copy, PartialEq)]
204#[cfg_attr(
205    feature = "bevy_reflect",
206    derive(Reflect),
207    reflect(Debug, PartialEq, Clone, Message)
208)]
209#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
210#[cfg_attr(
211    all(feature = "serialize", feature = "bevy_reflect"),
212    reflect(Serialize, Deserialize)
213)]
214pub struct MouseWheel {
215    /// The mouse scroll unit.
216    pub unit: MouseScrollUnit,
217    /// The horizontal scroll value.
218    pub x: f32,
219    /// The vertical scroll value.
220    pub y: f32,
221    /// Window that received the input.
222    pub window: Entity,
223    /// Touch phase of the input.
224    ///
225    /// When using a mouse, this will always be [`TouchPhase::Moved`].
226    pub phase: TouchPhase,
227}
228
229/// Updates the [`ButtonInput<MouseButton>`] resource with the latest [`MouseButtonInput`] events.
230///
231/// ## Differences
232///
233/// The main difference between the [`MouseButtonInput`] event and the [`ButtonInput<MouseButton>`] resource is that
234/// the latter has convenient functions like [`ButtonInput::pressed`], [`ButtonInput::just_pressed`] and [`ButtonInput::just_released`].
235pub fn mouse_button_input_system(
236    mut mouse_button_input: ResMut<ButtonInput<MouseButton>>,
237    mut mouse_button_input_events: MessageReader<MouseButtonInput>,
238) {
239    mouse_button_input.bypass_change_detection().clear();
240    for event in mouse_button_input_events.read() {
241        match event.state {
242            ButtonState::Pressed => mouse_button_input.press(event.button),
243            ButtonState::Released => mouse_button_input.release(event.button),
244        }
245    }
246}
247
248/// Tracks how much the mouse has moved every frame.
249///
250/// This resource is reset to zero every frame.
251///
252/// This resource sums the total [`MouseMotion`] events received this frame.
253#[derive(Resource, Debug, Clone, Copy, PartialEq, Default)]
254#[cfg_attr(
255    feature = "bevy_reflect",
256    derive(Reflect),
257    reflect(Debug, Default, Resource, PartialEq, Clone)
258)]
259#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
260#[cfg_attr(
261    all(feature = "serialize", feature = "bevy_reflect"),
262    reflect(Serialize, Deserialize)
263)]
264pub struct AccumulatedMouseMotion {
265    /// The change in mouse position.
266    pub delta: Vec2,
267}
268
269/// Tracks how much the mouse has scrolled every frame.
270///
271/// This resource is reset to zero every frame.
272///
273/// This resource sums the total [`MouseWheel`] events received this frame.
274#[derive(Resource, Debug, Clone, Copy, PartialEq)]
275#[cfg_attr(
276    feature = "bevy_reflect",
277    derive(Reflect),
278    reflect(Debug, Default, Resource, PartialEq, Clone)
279)]
280#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
281#[cfg_attr(
282    all(feature = "serialize", feature = "bevy_reflect"),
283    reflect(Serialize, Deserialize)
284)]
285pub struct AccumulatedMouseScroll {
286    /// The mouse scroll unit.
287    /// If this value changes while scrolling, then the
288    /// result of the accumulation could be incorrect
289    pub unit: MouseScrollUnit,
290    /// The change in scroll position.
291    pub delta: Vec2,
292}
293
294impl Default for AccumulatedMouseScroll {
295    fn default() -> Self {
296        Self {
297            unit: MouseScrollUnit::Line,
298            delta: Vec2::ZERO,
299        }
300    }
301}
302
303impl AccumulatedMouseScroll {
304    /// Converts the units to [`MouseScrollUnit::Line`]
305    pub fn to_lines(&self, conversion_ratio: &MouseScrollPixelsPerLine) -> Self {
306        if self.unit == MouseScrollUnit::Pixel {
307            AccumulatedMouseScroll {
308                unit: MouseScrollUnit::Line,
309                delta: self.delta / *conversion_ratio,
310            }
311        } else {
312            *self
313        }
314    }
315    /// Converts the units to [`MouseScrollUnit::Pixel`]
316    pub fn to_pixels(&self, conversion_ratio: &MouseScrollPixelsPerLine) -> Self {
317        if self.unit == MouseScrollUnit::Line {
318            AccumulatedMouseScroll {
319                unit: MouseScrollUnit::Pixel,
320                delta: self.delta * *conversion_ratio,
321            }
322        } else {
323            *self
324        }
325    }
326}
327
328/// Updates the [`AccumulatedMouseMotion`] resource using the [`MouseMotion`] event.
329/// The value of [`AccumulatedMouseMotion`] is reset to zero every frame
330pub fn accumulate_mouse_motion_system(
331    mut mouse_motion_event: MessageReader<MouseMotion>,
332    mut accumulated_mouse_motion: ResMut<AccumulatedMouseMotion>,
333) {
334    let mut delta = Vec2::ZERO;
335    for event in mouse_motion_event.read() {
336        delta += event.delta;
337    }
338    accumulated_mouse_motion.delta = delta;
339}
340
341/// Updates the [`AccumulatedMouseScroll`] resource using the [`MouseWheel`] event.
342/// The value of [`AccumulatedMouseScroll`] is reset to zero every frame
343pub fn accumulate_mouse_scroll_system(
344    mut mouse_scroll_event: MessageReader<MouseWheel>,
345    mut accumulated_mouse_scroll: ResMut<AccumulatedMouseScroll>,
346) {
347    let mut delta = Vec2::ZERO;
348    let mut unit = MouseScrollUnit::Line;
349    for event in mouse_scroll_event.read() {
350        if event.unit != unit {
351            unit = event.unit;
352        }
353        delta += Vec2::new(event.x, event.y);
354    }
355    accumulated_mouse_scroll.delta = delta;
356    accumulated_mouse_scroll.unit = unit;
357}