summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--glfw/src/window.rs126
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();
+ }
+}