diff options
-rw-r--r-- | glfw/src/window.rs | 126 |
1 files changed, 92 insertions, 34 deletions
diff --git a/glfw/src/window.rs b/glfw/src/window.rs index 0fb5978..1c6fa5a 100644 --- a/glfw/src/window.rs +++ b/glfw/src/window.rs @@ -166,6 +166,28 @@ impl Window } } + /// Sets the mouse button callback. + /// + /// The callback is called when a mouse button is pressed. + pub fn set_mouse_button_callback( + &self, + callback: impl Fn(MouseButton, MouseButtonState, KeyModifiers) + 'static, + ) + { + MOUSE_BUTTON_CALLBACK.with_borrow_mut(|mouse_button_callback| { + *mouse_button_callback = Some(Box::new(callback)); + }); + + // SAFETY: The initialize function (called when the window is created) makes sure + // the current thread is the main thread + unsafe { + crate::ffi::glfwSetMouseButtonCallback( + self.handle, + Some(mouse_button_callback), + ); + } + } + /// Returns the last reported state of a keyboard key. /// /// # Errors @@ -201,9 +223,8 @@ impl Window { // SAFETY: The initialize function (called when the window is created) makes sure // the current thread is the main thread - let state = unsafe { - crate::ffi::glfwGetMouseButton(self.handle, mouse_button.into_raw()) - }; + let state = + unsafe { crate::ffi::glfwGetMouseButton(self.handle, mouse_button as i32) }; get_glfw_error()?; @@ -600,46 +621,38 @@ bitflags! { } } -#[derive(Debug, Clone, Copy)] -pub enum MouseButton -{ - One, - Two, - Three, - Four, - Five, - Six, - Seven, - Eight, -} +enum_from_repr!( + #[repr(i32)] + #[derive(Debug, Clone, Copy)] + pub enum MouseButton + { + One = crate::ffi::GLFW_MOUSE_BUTTON_1, + Two = crate::ffi::GLFW_MOUSE_BUTTON_2, + Three = crate::ffi::GLFW_MOUSE_BUTTON_3, + Four = crate::ffi::GLFW_MOUSE_BUTTON_4, + Five = crate::ffi::GLFW_MOUSE_BUTTON_5, + Six = crate::ffi::GLFW_MOUSE_BUTTON_6, + Seven = crate::ffi::GLFW_MOUSE_BUTTON_7, + Eight = crate::ffi::GLFW_MOUSE_BUTTON_8, + } +); impl MouseButton { pub const LEFT: Self = Self::One; pub const MIDDLE: Self = Self::Three; pub const RIGHT: Self = Self::Two; +} - fn into_raw(self) -> i32 +enum_from_repr!( + #[repr(i32)] + #[derive(Debug, Clone, Copy)] + pub enum MouseButtonState { - match self { - Self::One => crate::ffi::GLFW_MOUSE_BUTTON_1, - Self::Two => crate::ffi::GLFW_MOUSE_BUTTON_2, - Self::Three => crate::ffi::GLFW_MOUSE_BUTTON_3, - Self::Four => crate::ffi::GLFW_MOUSE_BUTTON_4, - Self::Five => crate::ffi::GLFW_MOUSE_BUTTON_5, - Self::Six => crate::ffi::GLFW_MOUSE_BUTTON_6, - Self::Seven => crate::ffi::GLFW_MOUSE_BUTTON_7, - Self::Eight => crate::ffi::GLFW_MOUSE_BUTTON_8, - } + Pressed = crate::ffi::GLFW_PRESS, + Released = crate::ffi::GLFW_RELEASE, } -} - -#[derive(Debug, Clone, Copy)] -pub enum MouseButtonState -{ - Pressed, - Released, -} +); #[derive(Debug, Clone)] pub struct CursorPosition @@ -651,11 +664,13 @@ pub struct CursorPosition type FramebufferSizeCb = Box<dyn Fn(Size)>; type KeyCallback = Box<dyn Fn(Key, i32, KeyState, KeyModifiers)>; type CursorPositionCallback = Box<dyn Fn(CursorPosition)>; +type MouseButtonCallback = Box<dyn Fn(MouseButton, MouseButtonState, KeyModifiers)>; thread_local! { static FRAMEBUFFER_SIZE_CB: RefCell<Option<FramebufferSizeCb>> = RefCell::new(None); static KEY_CALLBACK: RefCell<Option<KeyCallback>> = RefCell::new(None); static CURSOR_POS_CALLBACK: RefCell<Option<CursorPositionCallback>> = RefCell::new(None); +static MOUSE_BUTTON_CALLBACK: RefCell<Option<MouseButtonCallback>> = RefCell::new(None); } extern "C" fn framebuffer_size_callback( @@ -753,3 +768,46 @@ extern "C" fn cursor_pos_callback( .ok(); } } + +extern "C" fn mouse_button_callback( + _window: *mut crate::ffi::GLFWwindow, + mouse_button_raw: c_int, + mouse_action: c_int, + modifier_keys: c_int, +) +{ + let Some(mouse_button) = MouseButton::from_repr(mouse_button_raw) else { + write!(stdout(), "Unknown mouse button {mouse_button_raw}").ok(); + return; + }; + + let Some(mouse_button_state) = MouseButtonState::from_repr(mouse_action) else { + write!(stdout(), "Unknown mouse action {mouse_action}").ok(); + return; + }; + + let Some(key_modifiers) = KeyModifiers::from_bits(modifier_keys) else { + write!( + stdout(), + "Key modifiers {modifier_keys:#b} contain one or more unknown bit(s)" + ) + .ok(); + + return; + }; + + // Unwinds are catched because unwinding from Rust code into foreign code is UB. + let res = catch_unwind(|| { + MOUSE_BUTTON_CALLBACK + .try_with(|mouse_button_callback| { + if let Some(cb) = mouse_button_callback.borrow().as_deref() { + cb(mouse_button, mouse_button_state, key_modifiers); + } + }) + .ok(); + }); + + if res.is_err() { + write!(stdout(), "ERROR: Mouse button callback panicked: {res:?}").ok(); + } +} |