sdl2/mouse/
mod.rs

1use crate::get_error;
2use crate::surface::SurfaceRef;
3use crate::video;
4use crate::EventPump;
5use std::iter::FilterMap;
6use std::mem::transmute;
7
8use crate::sys;
9use crate::sys::SDL_SystemCursor;
10
11mod relative;
12pub use self::relative::RelativeMouseState;
13
14#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
15#[repr(u32)]
16pub enum SystemCursor {
17    Arrow = SDL_SystemCursor::SDL_SYSTEM_CURSOR_ARROW as u32,
18    IBeam = SDL_SystemCursor::SDL_SYSTEM_CURSOR_IBEAM as u32,
19    Wait = SDL_SystemCursor::SDL_SYSTEM_CURSOR_WAIT as u32,
20    Crosshair = SDL_SystemCursor::SDL_SYSTEM_CURSOR_CROSSHAIR as u32,
21    WaitArrow = SDL_SystemCursor::SDL_SYSTEM_CURSOR_WAITARROW as u32,
22    SizeNWSE = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENWSE as u32,
23    SizeNESW = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENESW as u32,
24    SizeWE = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZEWE as u32,
25    SizeNS = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZENS as u32,
26    SizeAll = SDL_SystemCursor::SDL_SYSTEM_CURSOR_SIZEALL as u32,
27    No = SDL_SystemCursor::SDL_SYSTEM_CURSOR_NO as u32,
28    Hand = SDL_SystemCursor::SDL_SYSTEM_CURSOR_HAND as u32,
29}
30
31pub struct Cursor {
32    raw: *mut sys::SDL_Cursor,
33}
34
35impl Drop for Cursor {
36    #[inline]
37    #[doc(alias = "SDL_FreeCursor")]
38    fn drop(&mut self) {
39        unsafe { sys::SDL_FreeCursor(self.raw) };
40    }
41}
42
43impl Cursor {
44    #[doc(alias = "SDL_CreateCursor")]
45    pub fn new(
46        data: &[u8],
47        mask: &[u8],
48        width: i32,
49        height: i32,
50        hot_x: i32,
51        hot_y: i32,
52    ) -> Result<Cursor, String> {
53        unsafe {
54            let raw =
55                sys::SDL_CreateCursor(data.as_ptr(), mask.as_ptr(), width, height, hot_x, hot_y);
56
57            if raw.is_null() {
58                Err(get_error())
59            } else {
60                Ok(Cursor { raw })
61            }
62        }
63    }
64
65    // TODO: figure out how to pass Surface in here correctly
66    #[doc(alias = "SDL_CreateColorCursor")]
67    pub fn from_surface<S: AsRef<SurfaceRef>>(
68        surface: S,
69        hot_x: i32,
70        hot_y: i32,
71    ) -> Result<Cursor, String> {
72        unsafe {
73            let raw = sys::SDL_CreateColorCursor(surface.as_ref().raw(), hot_x, hot_y);
74
75            if raw.is_null() {
76                Err(get_error())
77            } else {
78                Ok(Cursor { raw })
79            }
80        }
81    }
82
83    #[doc(alias = "SDL_CreateSystemCursor")]
84    pub fn from_system(cursor: SystemCursor) -> Result<Cursor, String> {
85        unsafe {
86            let raw = sys::SDL_CreateSystemCursor(transmute(cursor as u32));
87
88            if raw.is_null() {
89                Err(get_error())
90            } else {
91                Ok(Cursor { raw })
92            }
93        }
94    }
95
96    #[doc(alias = "SDL_SetCursor")]
97    pub fn set(&self) {
98        unsafe {
99            sys::SDL_SetCursor(self.raw);
100        }
101    }
102}
103
104#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
105pub enum MouseWheelDirection {
106    Normal,
107    Flipped,
108    Unknown(u32),
109}
110
111// 0 and 1 are not fixed values in the SDL source code.  This value is defined as an enum which is then cast to a Uint32.
112// The enum in C is defined as such:
113
114/**
115 * \brief Scroll direction types for the Scroll event
116 */
117//typedef enum
118//{
119//    SDL_MOUSEWHEEL_NORMAL,    /**< The scroll direction is normal */
120//    SDL_MOUSEWHEEL_FLIPPED    /**< The scroll direction is flipped / natural */
121//} SDL_MouseWheelDirection;
122
123// Since no value is given in the enum definition these values are auto assigned by the C compiler starting at 0.
124// Normally I would prefer to use the enum rather than hard code what it is implied to represent however
125// the mouse wheel direction value could be described equally as well by a bool, so I don't think changes
126// to this enum in the C source code are going to be a problem.
127
128impl MouseWheelDirection {
129    #[inline]
130    pub fn from_ll(direction: u32) -> MouseWheelDirection {
131        match direction {
132            0 => MouseWheelDirection::Normal,
133            1 => MouseWheelDirection::Flipped,
134            _ => MouseWheelDirection::Unknown(direction),
135        }
136    }
137    #[inline]
138    pub fn to_ll(self) -> u32 {
139        match self {
140            MouseWheelDirection::Normal => 0,
141            MouseWheelDirection::Flipped => 1,
142            MouseWheelDirection::Unknown(direction) => direction,
143        }
144    }
145}
146
147#[repr(u8)]
148#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
149pub enum MouseButton {
150    Unknown = 0,
151    Left = sys::SDL_BUTTON_LEFT as u8,
152    Middle = sys::SDL_BUTTON_MIDDLE as u8,
153    Right = sys::SDL_BUTTON_RIGHT as u8,
154    X1 = sys::SDL_BUTTON_X1 as u8,
155    X2 = sys::SDL_BUTTON_X2 as u8,
156}
157
158impl MouseButton {
159    #[inline]
160    pub fn from_ll(button: u8) -> MouseButton {
161        match button as u32 {
162            sys::SDL_BUTTON_LEFT => MouseButton::Left,
163            sys::SDL_BUTTON_MIDDLE => MouseButton::Middle,
164            sys::SDL_BUTTON_RIGHT => MouseButton::Right,
165            sys::SDL_BUTTON_X1 => MouseButton::X1,
166            sys::SDL_BUTTON_X2 => MouseButton::X2,
167            _ => MouseButton::Unknown,
168        }
169    }
170}
171
172#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
173pub struct MouseState {
174    mouse_state: u32,
175    x: i32,
176    y: i32,
177}
178
179impl MouseState {
180    #[doc(alias = "SDL_GetMouseState")]
181    pub fn new(_e: &EventPump) -> MouseState {
182        let mut x = 0;
183        let mut y = 0;
184        let mouse_state: u32 = unsafe { sys::SDL_GetMouseState(&mut x, &mut y) };
185
186        MouseState { mouse_state, x, y }
187    }
188
189    pub fn from_sdl_state(state: u32) -> MouseState {
190        MouseState {
191            mouse_state: state,
192            x: 0,
193            y: 0,
194        }
195    }
196    pub fn to_sdl_state(&self) -> u32 {
197        self.mouse_state
198    }
199
200    fn button_mask(&self, button: u32) -> u32 {
201        1 << (button - 1)
202    }
203
204    /// Returns true if the left mouse button is pressed.
205    ///
206    /// # Example
207    /// ```no_run
208    /// use sdl2::mouse::MouseButton;
209    ///
210    /// fn is_left_pressed(e: &sdl2::EventPump) -> bool {
211    ///     e.mouse_state().left()
212    /// }
213    /// ```
214    pub fn left(&self) -> bool {
215        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_LEFT)) != 0
216    }
217
218    /// Tests if the middle mouse button was pressed.
219    pub fn middle(&self) -> bool {
220        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_MIDDLE)) != 0
221    }
222
223    /// Tests if the right mouse button was pressed.
224    pub fn right(&self) -> bool {
225        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_RIGHT)) != 0
226    }
227
228    /// Tests if the X1 mouse button was pressed.
229    pub fn x1(&self) -> bool {
230        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_X1)) != 0
231    }
232
233    /// Tests if the X2 mouse button was pressed.
234    pub fn x2(&self) -> bool {
235        (self.mouse_state & self.button_mask(sys::SDL_BUTTON_X2)) != 0
236    }
237
238    /// Returns the x coordinate of the state
239    pub fn x(&self) -> i32 {
240        self.x
241    }
242
243    /// Returns the y coordinate of the state
244    pub fn y(&self) -> i32 {
245        self.y
246    }
247
248    /// Returns true if the mouse button is pressed.
249    ///
250    /// # Example
251    /// ```no_run
252    /// use sdl2::mouse::MouseButton;
253    ///
254    /// fn is_left_pressed(e: &sdl2::EventPump) -> bool {
255    ///     e.mouse_state().is_mouse_button_pressed(MouseButton::Left)
256    /// }
257    /// ```
258    pub fn is_mouse_button_pressed(&self, mouse_button: MouseButton) -> bool {
259        let mask = 1 << ((mouse_button as u32) - 1);
260        self.mouse_state & mask != 0
261    }
262
263    /// Returns an iterator all mouse buttons with a boolean indicating if the scancode is pressed.
264    ///
265    /// # Example
266    /// ```no_run
267    /// use sdl2::mouse::MouseButton;
268    /// use std::collections::HashMap;
269    ///
270    /// fn mouse_button_set(e: &sdl2::EventPump) -> HashMap<MouseButton, bool> {
271    ///     e.mouse_state().mouse_buttons().collect()
272    /// }
273    ///
274    /// fn find_first_pressed(e: &sdl2::EventPump) -> bool {
275    ///     for (key,value) in mouse_button_set(e) {
276    ///         return value != false
277    ///     }
278    ///     false
279    /// }
280    ///
281    /// ```
282    pub fn mouse_buttons(&self) -> MouseButtonIterator {
283        MouseButtonIterator {
284            cur_button: 1,
285            mouse_state: &self.mouse_state,
286        }
287    }
288
289    /// Returns an iterator of pressed mouse buttons.
290    ///
291    /// # Example
292    /// ```no_run
293    /// use sdl2::mouse::MouseButton;
294    /// use std::collections::HashSet;
295    ///
296    /// fn pressed_mouse_button_set(e: &sdl2::EventPump) -> HashSet<MouseButton> {
297    ///     e.mouse_state().pressed_mouse_buttons().collect()
298    /// }
299    ///
300    /// fn newly_pressed(old: &HashSet<MouseButton>, new: &HashSet<MouseButton>) -> HashSet<MouseButton> {
301    ///     new - old
302    ///     // sugar for: new.difference(old).collect()
303    /// }
304    /// ```
305    pub fn pressed_mouse_buttons(&self) -> PressedMouseButtonIterator {
306        self.mouse_buttons().into_pressed_buttons_iter()
307    }
308}
309
310pub struct MouseButtonIterator<'a> {
311    cur_button: u8,
312    mouse_state: &'a u32,
313}
314
315impl<'a> Iterator for MouseButtonIterator<'a> {
316    type Item = (MouseButton, bool);
317
318    fn next(&mut self) -> Option<(MouseButton, bool)> {
319        if self.cur_button < MouseButton::X2 as u8 + 1 {
320            let mouse_button = self.cur_button;
321            let mask = 1 << ((self.cur_button as u32) - 1);
322            let pressed = self.mouse_state & mask != 0;
323            self.cur_button += 1;
324            Some((MouseButton::from_ll(mouse_button), pressed))
325        } else {
326            None
327        }
328    }
329}
330
331impl<'a> MouseButtonIterator<'a> {
332    fn into_pressed_buttons_iter(self) -> PressedMouseButtonIterator<'a> {
333        self.filter_map(|(mouse_button, pressed)| pressed.then_some(mouse_button))
334    }
335}
336
337pub type PressedMouseButtonIterator<'a> =
338    FilterMap<MouseButtonIterator<'a>, fn((MouseButton, bool)) -> Option<MouseButton>>;
339
340impl crate::Sdl {
341    #[inline]
342    pub fn mouse(&self) -> MouseUtil {
343        MouseUtil {
344            _sdldrop: self.sdldrop(),
345        }
346    }
347}
348
349/// Mouse utility functions. Access with `Sdl::mouse()`.
350///
351/// ```no_run
352/// let sdl_context = sdl2::init().unwrap();
353///
354/// // Hide the cursor
355/// sdl_context.mouse().show_cursor(false);
356/// ```
357pub struct MouseUtil {
358    _sdldrop: crate::SdlDrop,
359}
360
361impl MouseUtil {
362    /// Gets the id of the window which currently has mouse focus.
363    #[doc(alias = "SDL_GetMouseFocus")]
364    pub fn focused_window_id(&self) -> Option<u32> {
365        let raw = unsafe { sys::SDL_GetMouseFocus() };
366        if raw.is_null() {
367            None
368        } else {
369            let id = unsafe { sys::SDL_GetWindowID(raw) };
370            Some(id)
371        }
372    }
373
374    #[doc(alias = "SDL_WarpMouseInWindow")]
375    pub fn warp_mouse_in_window(&self, window: &video::Window, x: i32, y: i32) {
376        unsafe {
377            sys::SDL_WarpMouseInWindow(window.raw(), x, y);
378        }
379    }
380
381    #[doc(alias = "SDL_SetRelativeMouseMode")]
382    pub fn set_relative_mouse_mode(&self, on: bool) {
383        let on = if on {
384            sys::SDL_bool::SDL_TRUE
385        } else {
386            sys::SDL_bool::SDL_FALSE
387        };
388        unsafe {
389            sys::SDL_SetRelativeMouseMode(on);
390        }
391    }
392
393    #[doc(alias = "SDL_GetRelativeMouseMode")]
394    pub fn relative_mouse_mode(&self) -> bool {
395        unsafe { sys::SDL_GetRelativeMouseMode() == sys::SDL_bool::SDL_TRUE }
396    }
397
398    #[doc(alias = "SDL_ShowCursor")]
399    pub fn is_cursor_showing(&self) -> bool {
400        unsafe { sys::SDL_ShowCursor(crate::sys::SDL_QUERY) == 1 }
401    }
402
403    #[doc(alias = "SDL_ShowCursor")]
404    pub fn show_cursor(&self, show: bool) {
405        unsafe {
406            sys::SDL_ShowCursor(show as i32);
407        }
408    }
409
410    #[doc(alias = "SDL_CaptureMouse")]
411    pub fn capture(&self, enable: bool) {
412        let enable = if enable {
413            sys::SDL_bool::SDL_TRUE
414        } else {
415            sys::SDL_bool::SDL_FALSE
416        };
417        unsafe {
418            sys::SDL_CaptureMouse(enable);
419        }
420    }
421}