Support passing back some events to the platform (#90)
* Add mutable event status argument to WindowHandler::on_event * macOS: simplify method declaration for simple mouse event handlers * macOS: add macro for adding simple keyboard class methods * macOS: reorder code in mouse_moved * Take EventStatus as return value in WindowHandler::on_event * Add doc comments for EventStatus * Improve EventStatus documentation * x11: ignore return value of on_event for now * EventStatus: improve docs * Improve EventsStatus docs * Improve EventStatus docs further * macOS: ignore EventStatus::Ignored for mouse events * macOS: minor formatting improvement * improve EventStatus docs again
This commit is contained in:
parent
663f9d5d4c
commit
72b6a4a2d1
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
26
src/event.rs
26
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,
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
state.trigger_event(
|
||||
Event::Mouse(MouseEvent::CursorMoved { position })
|
||||
);
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -251,7 +251,7 @@ impl Window {
|
|||
handler.on_event(
|
||||
&mut crate::Window::new(self),
|
||||
Event::Window(WindowEvent::Resized(window_info))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue