Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changes/feat-device-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"tauri-runtime": "minor:feat"
"tauri-runtime-wry": "minor:feat"
"tauri": "minor:feat"
---

Adds a callback method to App builder that is called with device events and Apphandle.
Update Runtime Trait to add a device event callback method
Update wry and mock runtime with this method
13 changes: 12 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

116 changes: 84 additions & 32 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ use http::Request;
use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};

use tauri_runtime::{
device_events::DeviceEventFilter,
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
monitor::Monitor,
webview::{DetachedWebview, DownloadEvent, PendingWebview, WebviewIpcHandler},
window::{
CursorIcon, DetachedWindow, DetachedWindowWebview, DragDropEvent, PendingWindow, RawWindow,
WebviewEvent, WindowBuilder, WindowBuilderBase, WindowEvent, WindowId, WindowSizeConstraints,
},
Cookie, DeviceEventFilter, Error, EventLoopProxy, ExitRequestedEventAction, Icon,
ProgressBarState, ProgressBarStatus, Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs,
UserAttentionType, UserEvent, WebviewDispatch, WebviewEventId, WindowDispatch, WindowEventId,
Cookie, Error, EventLoopProxy, ExitRequestedEventAction, Icon, ProgressBarState,
ProgressBarStatus, Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType,
UserEvent, WebviewDispatch, WebviewEventId, WindowDispatch, WindowEventId,
};

#[cfg(target_vendor = "apple")]
Expand All @@ -37,17 +38,6 @@ use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS}
use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
#[cfg(windows)]
use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};
#[cfg(windows)]
use webview2_com::FocusChangedEventHandler;
#[cfg(windows)]
use windows::Win32::Foundation::HWND;
#[cfg(target_os = "ios")]
use wry::WebViewBuilderExtIos;
#[cfg(windows)]
use wry::WebViewBuilderExtWindows;
#[cfg(target_vendor = "apple")]
use wry::{WebViewBuilderExtDarwin, WebViewExtDarwin};

use tao::{
dpi::{
LogicalPosition as TaoLogicalPosition, LogicalSize as TaoLogicalSize,
Expand All @@ -66,6 +56,7 @@ use tao::{
UserAttentionType as TaoUserAttentionType,
},
};

#[cfg(desktop)]
use tauri_utils::config::PreventOverflowConfig;
#[cfg(target_os = "macos")]
Expand All @@ -75,10 +66,20 @@ use tauri_utils::{
Theme,
};
use url::Url;
#[cfg(windows)]
use webview2_com::FocusChangedEventHandler;
#[cfg(windows)]
use windows::Win32::Foundation::HWND;
#[cfg(target_os = "ios")]
use wry::WebViewBuilderExtIos;
#[cfg(windows)]
use wry::WebViewBuilderExtWindows;
use wry::{
DragDropEvent as WryDragDropEvent, ProxyConfig, ProxyEndpoint, WebContext as WryWebContext,
WebView, WebViewBuilder,
};
#[cfg(target_vendor = "apple")]
use wry::{WebViewBuilderExtDarwin, WebViewExtDarwin};

pub use tao;
pub use tao::window::{Window, WindowBuilder as TaoWindowBuilder, WindowId as TaoWindowId};
Expand Down Expand Up @@ -130,6 +131,7 @@ use std::{
pub type WebviewId = u32;
type IpcHandler = dyn Fn(Request<String>) + 'static;

mod map_device_event;
mod monitor;
#[cfg(any(
windows,
Expand Down Expand Up @@ -236,6 +238,22 @@ pub(crate) fn send_user_message<T: UserEvent>(
.map_err(|_| Error::FailedToSendMessage)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// A unique identifier for a device.
/// There is no meaning to the value of this identifier, it is just a unique identifier.
pub struct DeviceId(tao::event::DeviceId);

impl tauri_runtime::device_events::DeviceId for DeviceId {
unsafe fn dummy() -> Self {
DeviceId(unsafe { tao::event::DeviceId::dummy() })
}
}

type DeviceEventCallback = Arc<
Mutex<
Option<Box<dyn FnMut(DeviceId, tauri_runtime::device_events::DeviceEvent) + Send + 'static>>,
>,
>;

#[derive(Clone)]
pub struct Context<T: UserEvent> {
Expand All @@ -244,6 +262,7 @@ pub struct Context<T: UserEvent> {
pub proxy: TaoEventLoopProxy<Message<T>>,
main_thread: DispatcherMainThreadContext<T>,
plugins: Arc<Mutex<Vec<Box<dyn Plugin<T> + Send>>>>,
device_event_callback: DeviceEventCallback,
next_window_id: Arc<AtomicU32>,
next_webview_id: Arc<AtomicU32>,
next_window_event_id: Arc<AtomicU32>,
Expand Down Expand Up @@ -2707,6 +2726,7 @@ impl<T: UserEvent> Wry<T> {
#[cfg(feature = "tracing")]
active_tracing_spans: Default::default(),
},
device_event_callback: Default::default(),
plugins: Default::default(),
next_window_id: Default::default(),
next_webview_id: Default::default(),
Expand Down Expand Up @@ -2947,19 +2967,34 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
self.event_loop.hide_application();
}

fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
fn set_device_event_filter(&self, filter: DeviceEventFilter) {
self
.event_loop
.set_device_event_filter(DeviceEventFilterWrapper::from(filter).0);
}

type DeviceId = DeviceId;

fn set_device_event_callback<F>(&self, callback: F)
where
F: FnMut(Self::DeviceId, tauri_runtime::device_events::DeviceEvent) + Send + 'static,
{
self
.context
.device_event_callback
.lock()
.unwrap()
.replace(Box::new(callback));
}

#[cfg(desktop)]
fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) {
use tao::platform::run_return::EventLoopExtRunReturn;
let windows = self.context.main_thread.windows.clone();
let window_id_map = self.context.window_id_map.clone();
let web_context = &self.context.main_thread.web_context;
let plugins = self.context.plugins.clone();
let device_event_callback = self.context.device_event_callback.clone();

#[cfg(feature = "tracing")]
let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone();
Expand Down Expand Up @@ -2998,6 +3033,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
event,
event_loop,
control_flow,
device_event_callback.clone(),
EventLoopIterationContext {
callback: &mut callback,
windows: windows.clone(),
Expand Down Expand Up @@ -3043,35 +3079,41 @@ where
let window_id_map = runtime.context.window_id_map.clone();
let web_context = runtime.context.main_thread.web_context.clone();
let plugins = runtime.context.plugins.clone();
let device_event_callback = runtime.context.device_event_callback.clone();

#[cfg(feature = "tracing")]
let active_tracing_spans = runtime.context.main_thread.active_tracing_spans.clone();
let proxy = runtime.event_loop.create_proxy();

move |event, event_loop, control_flow| {
for p in plugins.lock().unwrap().iter_mut() {
let prevent_default = p.on_event(
&event,
event_loop,
&proxy,
control_flow,
EventLoopIterationContext {
callback: &mut callback,
window_id_map: window_id_map.clone(),
windows: windows.clone(),
#[cfg(feature = "tracing")]
active_tracing_spans: active_tracing_spans.clone(),
},
&web_context,
);
if prevent_default {
return;
// if device event skip the plugins to optimize performance
// if device filter is set to always and this is not here there will be a performance hit
if !matches!(event, Event::DeviceEvent { .. }) {
for p in plugins.lock().unwrap().iter_mut() {
let prevent_default = p.on_event(
&event,
event_loop,
&proxy,
control_flow,
EventLoopIterationContext {
callback: &mut callback,
window_id_map: window_id_map.clone(),
windows: windows.clone(),
#[cfg(feature = "tracing")]
active_tracing_spans: active_tracing_spans.clone(),
},
&web_context,
);
if prevent_default {
return;
}
}
}
handle_event_loop(
event,
event_loop,
control_flow,
device_event_callback.clone(),
EventLoopIterationContext {
callback: &mut callback,
window_id_map: window_id_map.clone(),
Expand Down Expand Up @@ -3879,6 +3921,7 @@ fn handle_event_loop<T: UserEvent>(
event: Event<'_, Message<T>>,
event_loop: &EventLoopWindowTarget<Message<T>>,
control_flow: &mut ControlFlow,
device_event_callback: DeviceEventCallback,
context: EventLoopIterationContext<'_, T>,
) {
let EventLoopIterationContext {
Expand All @@ -3893,6 +3936,15 @@ fn handle_event_loop<T: UserEvent>(
}

match event {
Event::DeviceEvent {
device_id, event, ..
} => {
if let Some(device_event_function) = device_event_callback.lock().unwrap().as_mut() {
if let Some(mapped_event) = map_device_event::map_device_event(event) {
device_event_function(DeviceId(device_id), mapped_event);
}
}
}
Event::NewEvents(StartCause::Init) => {
callback(RunEvent::Ready);
}
Expand Down
Loading
Loading