diff --git a/examples/open_window.rs b/examples/open_window.rs index b248b55..5e148a3 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -2,7 +2,7 @@ use std::time::Duration; use rtrb::{RingBuffer, Consumer}; -use baseview::{Event, Window, WindowHandler, WindowScalePolicy}; +use baseview::{Event, EventStatus, Window, WindowHandler, WindowScalePolicy}; #[derive(Debug, Clone)] enum Message { @@ -20,12 +20,14 @@ impl WindowHandler for OpenWindowExample { } } - fn on_event(&mut self, _window: &mut Window, event: Event) { + fn on_event(&mut self, _window: &mut Window, event: Event) -> EventStatus { match event { Event::Mouse(e) => println!("Mouse event: {:?}", e), Event::Keyboard(e) => println!("Keyboard event: {:?}", e), Event::Window(e) => println!("Window event: {:?}", e), } + + EventStatus::Captured } } diff --git a/src/event.rs b/src/event.rs index 64dd4ed..5423ddf 100644 --- a/src/event.rs +++ b/src/event.rs @@ -68,7 +68,7 @@ pub enum MouseEvent { CursorLeft, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum WindowEvent { Resized(WindowInfo), Focused, @@ -76,9 +76,31 @@ pub enum WindowEvent { WillClose, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Event { Mouse(MouseEvent), Keyboard(KeyboardEvent), Window(WindowEvent), } + + +/// Return value for [WindowHandler::on_event](`crate::WindowHandler::on_event()`), +/// indicating whether the event was handled by your window or should be passed +/// back to the platform. +/// +/// For most event types, this value won't have any effect. This is the case +/// when there is no clear meaning of passing back the event to the platform, +/// or it isn't obviously useful. Currently, only [`Event::Keyboard`] variants +/// are supported. +#[derive(Debug)] +pub enum EventStatus { + /// Event was handled by your window and will not be sent back to the + /// platform for further processing. + Captured, + /// Event was **not** handled by your window, so pass it back to the + /// platform. For parented windows, this usually means that the parent + /// window will receive the event. This is useful for cases such as using + /// DAW functionality for playing piano keys with the keyboard while a + /// plugin window is in focus. + Ignored, +} diff --git a/src/macos/view.rs b/src/macos/view.rs index 0161b26..17cbda0 100644 --- a/src/macos/view.rs +++ b/src/macos/view.rs @@ -13,7 +13,7 @@ use objc::{ }; use uuid::Uuid; -use crate::{Event, MouseButton, MouseEvent, Point, WindowOpenOptions}; +use crate::{Event, EventStatus, MouseButton, MouseEvent, Point, WindowOpenOptions}; use crate::MouseEvent::{ButtonPressed, ButtonReleased}; use super::window::WindowState; @@ -23,6 +23,54 @@ use super::window::WindowState; pub(super) const BASEVIEW_STATE_IVAR: &str = "baseview_state"; +macro_rules! add_simple_mouse_class_method { + ($class:ident, $sel:ident, $event:expr) => { + #[allow(non_snake_case)] + extern "C" fn $sel(this: &Object, _: Sel, _: id){ + let state: &mut WindowState = unsafe { + WindowState::from_field(this) + }; + + state.trigger_event(Event::Mouse($event)); + } + + $class.add_method( + sel!($sel:), + $sel as extern "C" fn(&Object, Sel, id), + ); + }; +} + + +macro_rules! add_simple_keyboard_class_method { + ($class:ident, $sel:ident) => { + #[allow(non_snake_case)] + extern "C" fn $sel(this: &Object, _: Sel, event: id){ + let state: &mut WindowState = unsafe { + WindowState::from_field(this) + }; + + if let Some(key_event) = state.process_native_key_event(event){ + let status = state.trigger_event(Event::Keyboard(key_event)); + + if let EventStatus::Ignored = status { + unsafe { + let superclass = msg_send![this, superclass]; + + let () = msg_send![super(this, superclass), $sel:event]; + } + } + } + } + + $class.add_method( + sel!($sel:), + $sel as extern "C" fn(&Object, Sel, id), + ); + }; +} + + pub(super) unsafe fn create_view( window_options: &WindowOpenOptions, ) -> id { @@ -97,55 +145,50 @@ unsafe fn create_view_class() -> &'static Class { mouse_moved as extern "C" fn(&Object, Sel, id), ); - class.add_method( - sel!(mouseEntered:), - mouse_entered as extern "C" fn(&Object, Sel, id), + add_simple_mouse_class_method!( + class, + mouseDown, + ButtonPressed(MouseButton::Left) + ); + add_simple_mouse_class_method!( + class, + mouseUp, + ButtonReleased(MouseButton::Left) + ); + add_simple_mouse_class_method!( + class, + rightMouseDown, + ButtonPressed(MouseButton::Right) + ); + add_simple_mouse_class_method!( + class, + rightMouseUp, + ButtonReleased(MouseButton::Right) + ); + add_simple_mouse_class_method!( + class, + otherMouseDown, + ButtonPressed(MouseButton::Middle) + ); + add_simple_mouse_class_method!( + class, + otherMouseUp, + ButtonReleased(MouseButton::Middle) + ); + add_simple_mouse_class_method!( + class, + mouseEntered, + MouseEvent::CursorEntered + ); + add_simple_mouse_class_method!( + class, + mouseExited, + MouseEvent::CursorLeft ); - class.add_method( - sel!(mouseExited:), - mouse_exited as extern "C" fn(&Object, Sel, id), - ); - - class.add_method( - sel!(mouseDown:), - left_mouse_down as extern "C" fn(&Object, Sel, id), - ); - class.add_method( - sel!(mouseUp:), - left_mouse_up as extern "C" fn(&Object, Sel, id), - ); - - class.add_method( - sel!(rightMouseDown:), - right_mouse_down as extern "C" fn(&Object, Sel, id), - ); - class.add_method( - sel!(rightMouseUp:), - right_mouse_up as extern "C" fn(&Object, Sel, id), - ); - - class.add_method( - sel!(otherMouseDown:), - middle_mouse_down as extern "C" fn(&Object, Sel, id), - ); - class.add_method( - sel!(otherMouseUp:), - middle_mouse_up as extern "C" fn(&Object, Sel, id), - ); - - class.add_method( - sel!(keyDown:), - key_down as extern "C" fn(&Object, Sel, id), - ); - class.add_method( - sel!(keyUp:), - key_up as extern "C" fn(&Object, Sel, id), - ); - class.add_method( - sel!(flagsChanged:), - flags_changed as extern "C" fn(&Object, Sel, id), - ); + add_simple_keyboard_class_method!(class, keyDown); + add_simple_keyboard_class_method!(class, keyUp); + add_simple_keyboard_class_method!(class, flagsChanged); class.add_ivar::<*mut c_void>(BASEVIEW_STATE_IVAR); @@ -310,6 +353,10 @@ extern "C" fn mouse_moved( _sel: Sel, event: id ){ + let state: &mut WindowState = unsafe { + WindowState::from_field(this) + }; + let point: NSPoint = unsafe { let point = NSEvent::locationInWindow(event); @@ -321,74 +368,7 @@ extern "C" fn mouse_moved( y: point.y }; - let event = Event::Mouse(MouseEvent::CursorMoved { position }); - - let state: &mut WindowState = unsafe { - WindowState::from_field(this) - }; - - state.trigger_event(event); + state.trigger_event( + Event::Mouse(MouseEvent::CursorMoved { position }) + ); } - - -macro_rules! mouse_simple_extern_fn { - ($fn:ident, $event:expr) => { - extern "C" fn $fn( - this: &Object, - _sel: Sel, - _event: id, - ){ - let state: &mut WindowState = unsafe { - WindowState::from_field(this) - }; - - state.trigger_event(Event::Mouse($event)); - } - }; -} - - -mouse_simple_extern_fn!(left_mouse_down, ButtonPressed(MouseButton::Left)); -mouse_simple_extern_fn!(left_mouse_up, ButtonReleased(MouseButton::Left)); - -mouse_simple_extern_fn!(right_mouse_down, ButtonPressed(MouseButton::Right)); -mouse_simple_extern_fn!(right_mouse_up, ButtonReleased(MouseButton::Right)); - -mouse_simple_extern_fn!(middle_mouse_down, ButtonPressed(MouseButton::Middle)); -mouse_simple_extern_fn!(middle_mouse_up, ButtonReleased(MouseButton::Middle)); - -mouse_simple_extern_fn!(mouse_entered, MouseEvent::CursorEntered); -mouse_simple_extern_fn!(mouse_exited, MouseEvent::CursorLeft); - - -extern "C" fn key_down(this: &Object, _: Sel, event: id){ - let state: &mut WindowState = unsafe { - WindowState::from_field(this) - }; - - if let Some(key_event) = state.process_native_key_event(event){ - state.trigger_event(Event::Keyboard(key_event)); - } -} - - -extern "C" fn key_up(this: &Object, _: Sel, event: id){ - let state: &mut WindowState = unsafe { - WindowState::from_field(this) - }; - - if let Some(key_event) = state.process_native_key_event(event){ - state.trigger_event(Event::Keyboard(key_event)); - } -} - - -extern "C" fn flags_changed(this: &Object, _: Sel, event: id){ - let state: &mut WindowState = unsafe { - WindowState::from_field(this) - }; - - if let Some(key_event) = state.process_native_key_event(event){ - state.trigger_event(Event::Keyboard(key_event)); - } -} \ No newline at end of file diff --git a/src/macos/window.rs b/src/macos/window.rs index 8841e8e..0918235 100644 --- a/src/macos/window.rs +++ b/src/macos/window.rs @@ -17,7 +17,8 @@ use objc::{msg_send, runtime::Object, sel, sel_impl}; use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle}; use crate::{ - Event, WindowHandler, WindowOpenOptions, WindowScalePolicy, WindowInfo, + Event, EventStatus, WindowHandler, WindowOpenOptions, WindowScalePolicy, + WindowInfo, }; use super::view::{create_view, BASEVIEW_STATE_IVAR}; @@ -217,9 +218,9 @@ impl WindowState { &mut *(state_ptr as *mut Self) } - pub(super) fn trigger_event(&mut self, event: Event) { + pub(super) fn trigger_event(&mut self, event: Event) -> EventStatus { self.window_handler - .on_event(&mut crate::Window::new(&mut self.window), event); + .on_event(&mut crate::Window::new(&mut self.window), event) } pub(super) fn trigger_frame(&mut self) { diff --git a/src/window.rs b/src/window.rs index 88f5340..199a0df 100644 --- a/src/window.rs +++ b/src/window.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; -use crate::event::Event; +use crate::event::{Event, EventStatus}; use crate::window_open_options::WindowOpenOptions; #[cfg(target_os = "macos")] @@ -14,7 +14,7 @@ use crate::x11 as platform; pub trait WindowHandler { fn on_frame(&mut self, window: &mut Window); - fn on_event(&mut self, window: &mut Window, event: Event); + fn on_event(&mut self, window: &mut Window, event: Event) -> EventStatus; } pub struct Window<'a> { diff --git a/src/x11/window.rs b/src/x11/window.rs index f0e7f0a..244824f 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -251,7 +251,7 @@ impl Window { handler.on_event( &mut crate::Window::new(self), Event::Window(WindowEvent::Resized(window_info)) - ) + ); } }