From f82ea50a014d8a519a83350724594658baad278a Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 03:08:26 +1200 Subject: [PATCH 01/14] add device events callback --- crates/tauri-runtime-wry/src/lib.rs | 52 +++++++++++++++++++++++------ crates/tauri/src/app.rs | 14 ++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index ac5544a0690a..8b749b318875 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -31,23 +31,13 @@ use tauri_runtime::{ #[cfg(target_vendor = "apple")] use objc2::rc::Retained; +pub use tao::event::{DeviceEvent, DeviceId}; #[cfg(target_os = "macos")] use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS}; #[cfg(target_os = "linux")] 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, @@ -66,6 +56,7 @@ use tao::{ UserAttentionType as TaoUserAttentionType, }, }; + #[cfg(desktop)] use tauri_utils::config::PreventOverflowConfig; #[cfg(target_os = "macos")] @@ -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}; @@ -237,6 +238,9 @@ pub(crate) fn send_user_message( } } +type DeviceEventCallback = + Arc>>>; + #[derive(Clone)] pub struct Context { pub window_id_map: WindowIdStore, @@ -244,6 +248,7 @@ pub struct Context { pub proxy: TaoEventLoopProxy>, main_thread: DispatcherMainThreadContext, plugins: Arc + Send>>>>, + device_event_callback: DeviceEventCallback, next_window_id: Arc, next_webview_id: Arc, next_window_event_id: Arc, @@ -2707,6 +2712,7 @@ impl Wry { #[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(), @@ -2719,6 +2725,18 @@ impl Wry { event_loop, }) } + + pub fn set_device_event_callback(&self, f: F) + where + F: Fn(DeviceId, DeviceEvent) + Send + 'static, + { + self + .context + .device_event_callback + .lock() + .unwrap() + .replace(Box::new(f)); + } } impl Runtime for Wry { @@ -2960,6 +2978,7 @@ impl Runtime for Wry { 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(); @@ -2998,6 +3017,7 @@ impl Runtime for Wry { event, event_loop, control_flow, + device_event_callback.clone(), EventLoopIterationContext { callback: &mut callback, windows: windows.clone(), @@ -3043,6 +3063,7 @@ 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(); @@ -3072,6 +3093,7 @@ where event, event_loop, control_flow, + device_event_callback.clone(), EventLoopIterationContext { callback: &mut callback, window_id_map: window_id_map.clone(), @@ -3879,6 +3901,7 @@ fn handle_event_loop( event: Event<'_, Message>, event_loop: &EventLoopWindowTarget>, control_flow: &mut ControlFlow, + device_event_callback: DeviceEventCallback, context: EventLoopIterationContext<'_, T>, ) { let EventLoopIterationContext { @@ -3893,6 +3916,13 @@ fn handle_event_loop( } match event { + Event::DeviceEvent { + device_id, event, .. + } => { + if let Some(device_event_function) = device_event_callback.lock().unwrap().as_ref() { + device_event_function(device_id, event); + } + } Event::NewEvents(StartCause::Init) => { callback(RunEvent::Ready); } diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 9f3e97ab61e6..e05f75bf9999 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -709,6 +709,20 @@ impl App { { self.handle.runtime_handle.plugin(plugin); } + + /// Adds a callback to be called when a device event is received. + /// + /// This is only available on the Wry runtime. + pub fn set_device_event_callback(&self, callback: F) + where + F: Fn(tauri_runtime_wry::DeviceId, tauri_runtime_wry::DeviceEvent) + Send + 'static, + { + if let Some(runtime) = self.runtime.as_ref() { + runtime.set_device_event_callback(callback); + } else { + log::warn!("device event callback is not supported on this platform"); + } + } } macro_rules! shared_app_impl { From dc6fa0ba226abe37f1e3df32ed963699e644b9ae Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 03:55:37 +1200 Subject: [PATCH 02/14] feat: expose DeviceEvent and DeviceId for Wry runtime --- crates/tauri/src/app.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index e05f75bf9999..a387b3b1f65d 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -38,6 +38,9 @@ use tauri_runtime::{ }; use tauri_utils::{assets::AssetsIter, PackageInfo}; +#[cfg(feature = "wry")] +pub use tauri_runtime_wry::{DeviceEvent, DeviceId}; + use std::{ borrow::Cow, collections::HashMap, @@ -711,11 +714,11 @@ impl App { } /// Adds a callback to be called when a device event is received. - /// + /// /// This is only available on the Wry runtime. pub fn set_device_event_callback(&self, callback: F) where - F: Fn(tauri_runtime_wry::DeviceId, tauri_runtime_wry::DeviceEvent) + Send + 'static, + F: Fn(DeviceId, DeviceEvent) + Send + 'static, { if let Some(runtime) = self.runtime.as_ref() { runtime.set_device_event_callback(callback); From ce0f0aa271d090fd8245c7773b5973973cf51db2 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:29:01 +1200 Subject: [PATCH 03/14] add device events to tauri runtime --- Cargo.lock | 13 ++- crates/tauri-runtime/Cargo.toml | 15 ++-- crates/tauri-runtime/src/device_events.rs | 100 ++++++++++++++++++++++ crates/tauri-runtime/src/lib.rs | 39 +++++---- 4 files changed, 140 insertions(+), 27 deletions(-) create mode 100644 crates/tauri-runtime/src/device_events.rs diff --git a/Cargo.lock b/Cargo.lock index 7009dcf42aa3..6bee6073435e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4173,6 +4173,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "keyboard-types" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6e0f18953c66af118a70064505bd3780a226d65b06553b7293fb8933067967" +dependencies = [ + "bitflags 2.7.0", + "serde", +] + [[package]] name = "konst" version = "0.3.16" @@ -4606,7 +4616,7 @@ dependencies = [ "crossbeam-channel", "dpi", "gtk", - "keyboard-types", + "keyboard-types 0.7.0", "libxdo", "objc2 0.6.0", "objc2-app-kit", @@ -8759,6 +8769,7 @@ dependencies = [ "gtk", "http 1.2.0", "jni", + "keyboard-types 0.8.0", "objc2 0.6.0", "objc2-ui-kit", "raw-window-handle", diff --git a/crates/tauri-runtime/Cargo.toml b/crates/tauri-runtime/Cargo.toml index 721af20e5b55..5a8b79b41bf7 100644 --- a/crates/tauri-runtime/Cargo.toml +++ b/crates/tauri-runtime/Cargo.toml @@ -18,11 +18,11 @@ rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"] default-target = "x86_64-unknown-linux-gnu" targets = [ - "x86_64-pc-windows-msvc", - "x86_64-unknown-linux-gnu", - "x86_64-apple-darwin", - "x86_64-linux-android", - "x86_64-apple-ios", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-linux-android", + "x86_64-apple-ios", ] [dependencies] @@ -34,6 +34,7 @@ http = "1" raw-window-handle = "0.6" url = { version = "2" } dpi = { version = "0.1", features = ["serde"] } +keyboard-types = { version = "0.8.0", features = ["serde"] } # WARNING: cookie::Cookie is re-exported so bumping this is a breaking change, documented to be done as a minor bump cookie = "0.18" @@ -50,8 +51,8 @@ jni = "0.21" [target.'cfg(all(target_vendor = "apple", not(target_os = "macos")))'.dependencies] objc2 = "0.6" objc2-ui-kit = { version = "0.3.0", default-features = false, features = [ - "UIView", - "UIResponder", + "UIView", + "UIResponder", ] } [target."cfg(target_os = \"macos\")".dependencies] diff --git a/crates/tauri-runtime/src/device_events.rs b/crates/tauri-runtime/src/device_events.rs new file mode 100644 index 000000000000..e576acdd0a34 --- /dev/null +++ b/crates/tauri-runtime/src/device_events.rs @@ -0,0 +1,100 @@ +use dpi::PhysicalPosition; +pub use keyboard_types::{Code, KeyState}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +#[serde(tag = "type")] +pub enum DeviceEventFilter { + /// Always filter out device events. + Always, + /// Filter out device events while the window is not focused. + Unfocused, + /// Report all device events regardless of window focus. + Never, +} + +impl Default for DeviceEventFilter { + fn default() -> Self { + Self::Unfocused + } +} + +pub trait DeviceId: Copy + Clone + PartialEq + Eq + PartialOrd + Ord + std::hash::Hash { + /// # Safety + /// Returns a dummy `DeviceId`, useful for unit testing. The only guarantee made about the return + /// value of this function is that it will always be equal to itself and to future values returned + /// by this function. No other guarantees are made. This may be equal to a real `DeviceId`. + /// + /// **Passing this id to any real device will result in undefined behavior.** + unsafe fn dummy() -> Self; +} + +#[derive(Clone, Debug, PartialEq)] +pub enum DeviceEvent { + Added, + Removed, + + /// Change in physical position of a pointing device. + /// + /// This represents raw, unfiltered physical motion. Not to be confused with `WindowEvent::CursorMoved`. + MouseMotion { + /// (x, y) change in position in unspecified units. + /// + /// Different devices may use different units. + delta: (f64, f64), + }, + + /// Physical scroll event + MouseWheel { + delta: MouseScrollDelta, + }, + + /// Motion on some analog axis. This event will be reported for all arbitrary input devices + /// that tao supports on this platform, including mouse devices. If the device is a mouse + /// device then this will be reported alongside the MouseMotion event. + Motion { + axis: AxisId, + value: f64, + }, + + Button { + button: ButtonId, + state: KeyState, + }, + + Key { + pysical_key: Code, + state: KeyState, + }, + + Text { + codepoint: char, + }, +} + +/// Identifier for a specific analog axis on some device. +pub type AxisId = u32; + +/// Identifier for a specific button on some device. +/// +/// For a mouse, this is the button number (0 for left, 1 for right, etc.). +pub type ButtonId = u32; + +/// Describes a difference in the mouse scroll wheel state. +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub enum MouseScrollDelta { + /// Amount in lines or rows to scroll in the horizontal + /// and vertical directions. + /// + /// Positive values indicate movement forward + /// (away from the user) or rightwards. + LineDelta(f32, f32), + /// Amount in pixels to scroll in the horizontal and + /// vertical direction. + /// + /// Scroll events are expressed as a PixelDelta if + /// supported by the device (eg. a touchpad) and + /// platform. + PixelDelta(PhysicalPosition), +} diff --git a/crates/tauri-runtime/src/lib.rs b/crates/tauri-runtime/src/lib.rs index 201ec65b077d..9efa957f7fa0 100644 --- a/crates/tauri-runtime/src/lib.rs +++ b/crates/tauri-runtime/src/lib.rs @@ -13,6 +13,7 @@ )] #![cfg_attr(docsrs, feature(doc_cfg))] +use device_events::DeviceEventFilter; use raw_window_handle::DisplayHandle; use serde::Deserialize; use std::{borrow::Cow, fmt::Debug, sync::mpsc::Sender}; @@ -21,6 +22,7 @@ use tauri_utils::Theme; use url::Url; use webview::{DetachedWebview, PendingWebview}; +pub mod device_events; /// UI scaling utilities. pub mod dpi; /// Types useful for interacting with a user's monitors. @@ -90,23 +92,6 @@ pub enum UserAttentionType { Informational, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] -#[serde(tag = "type")] -pub enum DeviceEventFilter { - /// Always filter out device events. - Always, - /// Filter out device events while the window is not focused. - Unfocused, - /// Report all device events regardless of window focus. - Never, -} - -impl Default for DeviceEventFilter { - fn default() -> Self { - Self::Unfocused - } -} - /// Defines the orientation that a window resize will be performed. #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] pub enum ResizeDirection { @@ -434,6 +419,8 @@ pub trait Runtime: Debug + Sized + 'static { #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] fn hide(&self); + type DeviceId: device_events::DeviceId; + /// Change the device event filter mode. /// /// Since the DeviceEvent capture can lead to high CPU usage for unfocused windows, [`tao`] @@ -442,10 +429,24 @@ pub trait Runtime: Debug + Sized + 'static { /// /// ## Platform-specific /// - /// - ** Linux / macOS / iOS / Android**: Unsupported. + /// - ** Wayland / macOS / iOS / Android**: Unsupported. /// /// [`tao`]: https://crates.io/crates/tao - fn set_device_event_filter(&mut self, filter: DeviceEventFilter); + fn set_device_event_filter(&self, filter: DeviceEventFilter); + + /// Set a callback to be called when a device event is received. + /// + /// By default, the device events are filtered out when the window is not focused. + /// To change this behavior, use [`set_device_event_filter`](Runtime::set_device_event_filter). + /// + /// ## Platform-specific + /// + /// - ** Wayland / macOS / iOS / Android**: Unsupported. + /// + /// [`tao`]: https://crates.io/crates/tao + fn set_device_event_callback< F>(&self, callback: F) + where + F: FnMut(Self::DeviceId, device_events::DeviceEvent) + Send + 'static; /// Runs an iteration of the runtime event loop and returns control flow to the caller. #[cfg(desktop)] From 9f28ed51e44cb3f5f0044a2900d1e8aa681b9852 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:33:19 +1200 Subject: [PATCH 04/14] impl device event callback for wry runtime --- crates/tauri-runtime-wry/src/lib.rs | 98 ++++--- .../tauri-runtime-wry/src/map_device_event.rs | 247 ++++++++++++++++++ 2 files changed, 307 insertions(+), 38 deletions(-) create mode 100644 crates/tauri-runtime-wry/src/map_device_event.rs diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 8b749b318875..7c40353830f4 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -17,6 +17,7 @@ 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}, @@ -24,14 +25,13 @@ use tauri_runtime::{ 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")] use objc2::rc::Retained; -pub use tao::event::{DeviceEvent, DeviceId}; #[cfg(target_os = "macos")] use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS}; #[cfg(target_os = "linux")] @@ -131,6 +131,7 @@ use std::{ pub type WebviewId = u32; type IpcHandler = dyn Fn(Request) + 'static; +mod map_device_event; mod monitor; #[cfg(any( windows, @@ -237,9 +238,22 @@ pub(crate) fn send_user_message( .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); -type DeviceEventCallback = - Arc>>>; +impl tauri_runtime::device_events::DeviceId for DeviceId { + unsafe fn dummy() -> Self { + DeviceId(unsafe { tao::event::DeviceId::dummy() }) + } +} + +type DeviceEventCallback = Arc< + Mutex< + Option>, + >, +>; #[derive(Clone)] pub struct Context { @@ -2725,18 +2739,6 @@ impl Wry { event_loop, }) } - - pub fn set_device_event_callback(&self, f: F) - where - F: Fn(DeviceId, DeviceEvent) + Send + 'static, - { - self - .context - .device_event_callback - .lock() - .unwrap() - .replace(Box::new(f)); - } } impl Runtime for Wry { @@ -2965,12 +2967,26 @@ impl Runtime for Wry { 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(&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) + 'static>(&mut self, mut callback: F) { use tao::platform::run_return::EventLoopExtRunReturn; @@ -3070,23 +3086,27 @@ where 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( @@ -3919,8 +3939,10 @@ fn handle_event_loop( Event::DeviceEvent { device_id, event, .. } => { - if let Some(device_event_function) = device_event_callback.lock().unwrap().as_ref() { - device_event_function(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) => { diff --git a/crates/tauri-runtime-wry/src/map_device_event.rs b/crates/tauri-runtime-wry/src/map_device_event.rs new file mode 100644 index 000000000000..303ef033771a --- /dev/null +++ b/crates/tauri-runtime-wry/src/map_device_event.rs @@ -0,0 +1,247 @@ +use tauri_runtime::device_events::{Code, DeviceEvent, MouseScrollDelta}; + +pub fn map_device_event(event: tao::event::DeviceEvent) -> Option { + match event { + tao::event::DeviceEvent::Added => Some(DeviceEvent::Added), + tao::event::DeviceEvent::Removed => Some(DeviceEvent::Removed), + tao::event::DeviceEvent::MouseMotion { delta, .. } => Some(DeviceEvent::MouseMotion { delta }), + tao::event::DeviceEvent::MouseWheel { delta, .. } => match delta { + tao::event::MouseScrollDelta::LineDelta(x, y) => Some(DeviceEvent::MouseWheel { + delta: MouseScrollDelta::LineDelta(x, y), + }), + tao::event::MouseScrollDelta::PixelDelta(pos) => Some(DeviceEvent::MouseWheel { + delta: MouseScrollDelta::PixelDelta(pos), + }), + _ => None, + }, + tao::event::DeviceEvent::Motion { axis, value, .. } => { + Some(DeviceEvent::Motion { axis, value }) + } + tao::event::DeviceEvent::Button { button, state, .. } => Some(DeviceEvent::Button { + button, + state: map_element_state(state)?, + }), + tao::event::DeviceEvent::Key(raw_key_event) => { + let physical_key = raw_key_event.physical_key; + let state = map_element_state(raw_key_event.state)?; + Some(DeviceEvent::Key { + pysical_key: map_physical_key(physical_key)?, + state, + }) + } + tao::event::DeviceEvent::Text { codepoint, .. } => Some(DeviceEvent::Text { codepoint }), + _ => None, + } +} + +fn map_element_state( + state: tao::event::ElementState, +) -> Option { + match state { + tao::event::ElementState::Pressed => Some(tauri_runtime::device_events::KeyState::Down), + tao::event::ElementState::Released => Some(tauri_runtime::device_events::KeyState::Up), + _ => None, + } +} + +fn map_physical_key(event: tao::keyboard::KeyCode) -> Option { + match event { + tao::keyboard::KeyCode::Unidentified(native_key_code) => todo!(), + tao::keyboard::KeyCode::Backquote => Some(Code::Backquote), + tao::keyboard::KeyCode::Backslash => Some(Code::Backslash), + tao::keyboard::KeyCode::BracketLeft => Some(Code::BracketLeft), + tao::keyboard::KeyCode::BracketRight => Some(Code::BracketRight), + tao::keyboard::KeyCode::Comma => Some(Code::Comma), + tao::keyboard::KeyCode::Digit0 => Some(Code::Digit0), + tao::keyboard::KeyCode::Digit1 => Some(Code::Digit1), + tao::keyboard::KeyCode::Digit2 => Some(Code::Digit2), + tao::keyboard::KeyCode::Digit3 => Some(Code::Digit3), + tao::keyboard::KeyCode::Digit4 => Some(Code::Digit4), + tao::keyboard::KeyCode::Digit5 => Some(Code::Digit5), + tao::keyboard::KeyCode::Digit6 => Some(Code::Digit6), + tao::keyboard::KeyCode::Digit7 => Some(Code::Digit7), + tao::keyboard::KeyCode::Digit8 => Some(Code::Digit8), + tao::keyboard::KeyCode::Digit9 => Some(Code::Digit9), + tao::keyboard::KeyCode::Equal => Some(Code::Equal), + tao::keyboard::KeyCode::IntlBackslash => Some(Code::IntlBackslash), + tao::keyboard::KeyCode::IntlRo => Some(Code::IntlRo), + tao::keyboard::KeyCode::IntlYen => Some(Code::IntlYen), + tao::keyboard::KeyCode::KeyA => Some(Code::KeyA), + tao::keyboard::KeyCode::KeyB => Some(Code::KeyB), + tao::keyboard::KeyCode::KeyC => Some(Code::KeyC), + tao::keyboard::KeyCode::KeyD => Some(Code::KeyD), + tao::keyboard::KeyCode::KeyE => Some(Code::KeyE), + tao::keyboard::KeyCode::KeyF => Some(Code::KeyF), + tao::keyboard::KeyCode::KeyG => Some(Code::KeyG), + tao::keyboard::KeyCode::KeyH => Some(Code::KeyH), + tao::keyboard::KeyCode::KeyI => Some(Code::KeyI), + tao::keyboard::KeyCode::KeyJ => Some(Code::KeyJ), + tao::keyboard::KeyCode::KeyK => Some(Code::KeyK), + tao::keyboard::KeyCode::KeyL => Some(Code::KeyL), + tao::keyboard::KeyCode::KeyM => Some(Code::KeyM), + tao::keyboard::KeyCode::KeyN => Some(Code::KeyN), + tao::keyboard::KeyCode::KeyO => Some(Code::KeyO), + tao::keyboard::KeyCode::KeyP => Some(Code::KeyP), + tao::keyboard::KeyCode::KeyQ => Some(Code::KeyQ), + tao::keyboard::KeyCode::KeyR => Some(Code::KeyR), + tao::keyboard::KeyCode::KeyS => Some(Code::KeyS), + tao::keyboard::KeyCode::KeyT => Some(Code::KeyT), + tao::keyboard::KeyCode::KeyU => Some(Code::KeyU), + tao::keyboard::KeyCode::KeyV => Some(Code::KeyV), + tao::keyboard::KeyCode::KeyW => Some(Code::KeyW), + tao::keyboard::KeyCode::KeyX => Some(Code::KeyX), + tao::keyboard::KeyCode::KeyY => Some(Code::KeyY), + tao::keyboard::KeyCode::KeyZ => Some(Code::KeyZ), + tao::keyboard::KeyCode::Minus => Some(Code::Minus), + // could be wrong convertion?? + tao::keyboard::KeyCode::Plus => Some(Code::Equal), + tao::keyboard::KeyCode::Period => Some(Code::Period), + tao::keyboard::KeyCode::Quote => Some(Code::Quote), + tao::keyboard::KeyCode::Semicolon => Some(Code::Semicolon), + tao::keyboard::KeyCode::Slash => Some(Code::Slash), + tao::keyboard::KeyCode::AltLeft => Some(Code::AltLeft), + tao::keyboard::KeyCode::AltRight => Some(Code::AltRight), + tao::keyboard::KeyCode::Backspace => Some(Code::Backspace), + tao::keyboard::KeyCode::CapsLock => Some(Code::CapsLock), + tao::keyboard::KeyCode::ContextMenu => Some(Code::ContextMenu), + tao::keyboard::KeyCode::ControlLeft => Some(Code::ControlLeft), + tao::keyboard::KeyCode::ControlRight => Some(Code::ControlRight), + tao::keyboard::KeyCode::Enter => Some(Code::Enter), + tao::keyboard::KeyCode::SuperLeft => Some(Code::MetaLeft), + tao::keyboard::KeyCode::SuperRight => Some(Code::MetaRight), + tao::keyboard::KeyCode::ShiftLeft => Some(Code::ShiftLeft), + tao::keyboard::KeyCode::ShiftRight => Some(Code::ShiftRight), + tao::keyboard::KeyCode::Space => Some(Code::Space), + tao::keyboard::KeyCode::Tab => Some(Code::Tab), + tao::keyboard::KeyCode::Convert => Some(Code::Convert), + tao::keyboard::KeyCode::KanaMode => Some(Code::KanaMode), + tao::keyboard::KeyCode::Lang1 => Some(Code::Lang1), + tao::keyboard::KeyCode::Lang2 => Some(Code::Lang2), + tao::keyboard::KeyCode::Lang3 => Some(Code::Lang3), + tao::keyboard::KeyCode::Lang4 => Some(Code::Lang4), + tao::keyboard::KeyCode::Lang5 => Some(Code::Lang5), + tao::keyboard::KeyCode::NonConvert => Some(Code::NonConvert), + tao::keyboard::KeyCode::Delete => Some(Code::Delete), + tao::keyboard::KeyCode::End => Some(Code::End), + tao::keyboard::KeyCode::Help => Some(Code::Help), + tao::keyboard::KeyCode::Home => Some(Code::Home), + tao::keyboard::KeyCode::Insert => Some(Code::Insert), + tao::keyboard::KeyCode::PageDown => Some(Code::PageDown), + tao::keyboard::KeyCode::PageUp => Some(Code::PageUp), + tao::keyboard::KeyCode::ArrowDown => Some(Code::ArrowDown), + tao::keyboard::KeyCode::ArrowLeft => Some(Code::ArrowLeft), + tao::keyboard::KeyCode::ArrowRight => Some(Code::ArrowRight), + tao::keyboard::KeyCode::ArrowUp => Some(Code::ArrowUp), + tao::keyboard::KeyCode::NumLock => Some(Code::NumLock), + tao::keyboard::KeyCode::Numpad0 => Some(Code::Numpad0), + tao::keyboard::KeyCode::Numpad1 => Some(Code::Numpad1), + tao::keyboard::KeyCode::Numpad2 => Some(Code::Numpad2), + tao::keyboard::KeyCode::Numpad3 => Some(Code::Numpad3), + tao::keyboard::KeyCode::Numpad4 => Some(Code::Numpad4), + tao::keyboard::KeyCode::Numpad5 => Some(Code::Numpad5), + tao::keyboard::KeyCode::Numpad6 => Some(Code::Numpad6), + tao::keyboard::KeyCode::Numpad7 => Some(Code::Numpad7), + tao::keyboard::KeyCode::Numpad8 => Some(Code::Numpad8), + tao::keyboard::KeyCode::Numpad9 => Some(Code::Numpad9), + tao::keyboard::KeyCode::NumpadAdd => Some(Code::NumpadAdd), + tao::keyboard::KeyCode::NumpadBackspace => Some(Code::NumpadBackspace), + tao::keyboard::KeyCode::NumpadClear => Some(Code::NumpadClear), + tao::keyboard::KeyCode::NumpadClearEntry => Some(Code::NumpadClearEntry), + tao::keyboard::KeyCode::NumpadComma => Some(Code::NumpadComma), + tao::keyboard::KeyCode::NumpadDecimal => Some(Code::NumpadDecimal), + tao::keyboard::KeyCode::NumpadDivide => Some(Code::NumpadDivide), + tao::keyboard::KeyCode::NumpadEnter => Some(Code::NumpadEnter), + tao::keyboard::KeyCode::NumpadEqual => Some(Code::NumpadEqual), + tao::keyboard::KeyCode::NumpadHash => Some(Code::NumpadHash), + tao::keyboard::KeyCode::NumpadMemoryAdd => Some(Code::NumpadMemoryAdd), + tao::keyboard::KeyCode::NumpadMemoryClear => Some(Code::NumpadMemoryClear), + tao::keyboard::KeyCode::NumpadMemoryRecall => Some(Code::NumpadMemoryRecall), + tao::keyboard::KeyCode::NumpadMemoryStore => Some(Code::NumpadMemoryStore), + tao::keyboard::KeyCode::NumpadMemorySubtract => Some(Code::NumpadMemorySubtract), + tao::keyboard::KeyCode::NumpadMultiply => Some(Code::NumpadMultiply), + tao::keyboard::KeyCode::NumpadParenLeft => Some(Code::NumpadParenLeft), + tao::keyboard::KeyCode::NumpadParenRight => Some(Code::NumpadParenRight), + tao::keyboard::KeyCode::NumpadStar => Some(Code::NumpadStar), + tao::keyboard::KeyCode::NumpadSubtract => Some(Code::NumpadSubtract), + tao::keyboard::KeyCode::Escape => Some(Code::Escape), + tao::keyboard::KeyCode::Fn => Some(Code::Fn), + tao::keyboard::KeyCode::FnLock => Some(Code::FnLock), + tao::keyboard::KeyCode::PrintScreen => Some(Code::PrintScreen), + tao::keyboard::KeyCode::ScrollLock => Some(Code::ScrollLock), + tao::keyboard::KeyCode::Pause => Some(Code::Pause), + tao::keyboard::KeyCode::BrowserBack => Some(Code::BrowserBack), + tao::keyboard::KeyCode::BrowserFavorites => Some(Code::BrowserFavorites), + tao::keyboard::KeyCode::BrowserForward => Some(Code::BrowserForward), + tao::keyboard::KeyCode::BrowserHome => Some(Code::BrowserHome), + tao::keyboard::KeyCode::BrowserRefresh => Some(Code::BrowserRefresh), + tao::keyboard::KeyCode::BrowserSearch => Some(Code::BrowserSearch), + tao::keyboard::KeyCode::BrowserStop => Some(Code::BrowserStop), + tao::keyboard::KeyCode::Eject => Some(Code::Eject), + tao::keyboard::KeyCode::LaunchApp1 => Some(Code::LaunchApp1), + tao::keyboard::KeyCode::LaunchApp2 => Some(Code::LaunchApp2), + tao::keyboard::KeyCode::LaunchMail => Some(Code::LaunchMail), + tao::keyboard::KeyCode::MediaPlayPause => Some(Code::MediaPlayPause), + tao::keyboard::KeyCode::MediaSelect => Some(Code::MediaSelect), + tao::keyboard::KeyCode::MediaStop => Some(Code::MediaStop), + tao::keyboard::KeyCode::MediaTrackNext => Some(Code::MediaTrackNext), + tao::keyboard::KeyCode::MediaTrackPrevious => Some(Code::MediaTrackPrevious), + tao::keyboard::KeyCode::Power => Some(Code::Power), + tao::keyboard::KeyCode::Sleep => Some(Code::Sleep), + tao::keyboard::KeyCode::AudioVolumeDown => Some(Code::AudioVolumeDown), + tao::keyboard::KeyCode::AudioVolumeMute => Some(Code::AudioVolumeMute), + tao::keyboard::KeyCode::AudioVolumeUp => Some(Code::AudioVolumeUp), + tao::keyboard::KeyCode::WakeUp => Some(Code::WakeUp), + tao::keyboard::KeyCode::Hyper => Some(Code::Hyper), + tao::keyboard::KeyCode::Turbo => Some(Code::Turbo), + tao::keyboard::KeyCode::Abort => Some(Code::Abort), + tao::keyboard::KeyCode::Resume => Some(Code::Resume), + tao::keyboard::KeyCode::Suspend => Some(Code::Suspend), + tao::keyboard::KeyCode::Again => Some(Code::Again), + tao::keyboard::KeyCode::Copy => Some(Code::Copy), + tao::keyboard::KeyCode::Cut => Some(Code::Cut), + tao::keyboard::KeyCode::Find => Some(Code::Find), + tao::keyboard::KeyCode::Open => Some(Code::Open), + tao::keyboard::KeyCode::Paste => Some(Code::Paste), + tao::keyboard::KeyCode::Props => Some(Code::Props), + tao::keyboard::KeyCode::Select => Some(Code::Select), + tao::keyboard::KeyCode::Undo => Some(Code::Undo), + tao::keyboard::KeyCode::Hiragana => Some(Code::Hiragana), + tao::keyboard::KeyCode::Katakana => Some(Code::Katakana), + tao::keyboard::KeyCode::F1 => Some(Code::F1), + tao::keyboard::KeyCode::F2 => Some(Code::F2), + tao::keyboard::KeyCode::F3 => Some(Code::F3), + tao::keyboard::KeyCode::F4 => Some(Code::F4), + tao::keyboard::KeyCode::F5 => Some(Code::F5), + tao::keyboard::KeyCode::F6 => Some(Code::F6), + tao::keyboard::KeyCode::F7 => Some(Code::F7), + tao::keyboard::KeyCode::F8 => Some(Code::F8), + tao::keyboard::KeyCode::F9 => Some(Code::F9), + tao::keyboard::KeyCode::F10 => Some(Code::F10), + tao::keyboard::KeyCode::F11 => Some(Code::F11), + tao::keyboard::KeyCode::F12 => Some(Code::F12), + tao::keyboard::KeyCode::F13 => Some(Code::F13), + tao::keyboard::KeyCode::F14 => Some(Code::F14), + tao::keyboard::KeyCode::F15 => Some(Code::F15), + tao::keyboard::KeyCode::F16 => Some(Code::F16), + tao::keyboard::KeyCode::F17 => Some(Code::F17), + tao::keyboard::KeyCode::F18 => Some(Code::F18), + tao::keyboard::KeyCode::F19 => Some(Code::F19), + tao::keyboard::KeyCode::F20 => Some(Code::F20), + tao::keyboard::KeyCode::F21 => Some(Code::F21), + tao::keyboard::KeyCode::F22 => Some(Code::F22), + tao::keyboard::KeyCode::F23 => Some(Code::F23), + tao::keyboard::KeyCode::F24 => Some(Code::F24), + tao::keyboard::KeyCode::F25 => Some(Code::F25), + tao::keyboard::KeyCode::F26 => Some(Code::F26), + tao::keyboard::KeyCode::F27 => Some(Code::F27), + tao::keyboard::KeyCode::F28 => Some(Code::F28), + tao::keyboard::KeyCode::F29 => Some(Code::F29), + tao::keyboard::KeyCode::F30 => Some(Code::F30), + tao::keyboard::KeyCode::F31 => Some(Code::F31), + tao::keyboard::KeyCode::F32 => Some(Code::F32), + tao::keyboard::KeyCode::F33 => Some(Code::F33), + tao::keyboard::KeyCode::F34 => Some(Code::F34), + tao::keyboard::KeyCode::F35 => Some(Code::F35), + _ => None, + } +} From 3cae1d3da2dded81821951f9cae082086547617a Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:34:49 +1200 Subject: [PATCH 05/14] add device event callback to app builder struct --- crates/tauri/src/app.rs | 81 +++++++++++++++++++++++++++-------------- crates/tauri/src/lib.rs | 5 ++- 2 files changed, 58 insertions(+), 28 deletions(-) diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index a387b3b1f65d..703f2f4532c9 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -32,15 +32,13 @@ use tauri_macros::default_runtime; #[cfg(desktop)] use tauri_runtime::EventLoopProxy; use tauri_runtime::{ + device_events::DeviceEvent, dpi::{PhysicalPosition, PhysicalSize}, window::DragDropEvent, RuntimeInitArgs, }; use tauri_utils::{assets::AssetsIter, PackageInfo}; -#[cfg(feature = "wry")] -pub use tauri_runtime_wry::{DeviceEvent, DeviceId}; - use std::{ borrow::Cow, collections::HashMap, @@ -712,20 +710,6 @@ impl App { { self.handle.runtime_handle.plugin(plugin); } - - /// Adds a callback to be called when a device event is received. - /// - /// This is only available on the Wry runtime. - pub fn set_device_event_callback(&self, callback: F) - where - F: Fn(DeviceId, DeviceEvent) + Send + 'static, - { - if let Some(runtime) = self.runtime.as_ref() { - runtime.set_device_event_callback(callback); - } else { - log::warn!("device event callback is not supported on this platform"); - } - } } macro_rules! shared_app_impl { @@ -1422,6 +1406,10 @@ pub struct Builder { /// The device event filter. device_event_filter: DeviceEventFilter, + /// device event callback + device_event_callback: + Option, R::DeviceId, DeviceEvent) + Send + 'static>>, + pub(crate) invoke_key: String, } @@ -1487,6 +1475,7 @@ impl Builder { window_event_listeners: Vec::new(), webview_event_listeners: Vec::new(), device_event_filter: Default::default(), + device_event_callback: None, invoke_key, } } @@ -2060,9 +2049,9 @@ tauri::Builder::default() /// /// ## Platform-specific /// - /// - ** Linux / macOS / iOS / Android**: Unsupported. + /// - ** Wayland / macOS / iOS / Android**: Unsupported. /// - /// # Examples + /// # Example /// ```,no_run /// tauri::Builder::default() /// .device_event_filter(tauri::DeviceEventFilter::Always); @@ -2074,6 +2063,35 @@ tauri::Builder::default() self } + /// Registers a device event callback. + /// + /// if [`DeviceEventFilter`] is set to [`DeviceEventFilter::Always`], this callback will be called for all device events. + /// This leads to high CPU usage for unfocused windows, so it is recommended to use [`DeviceEventFilter::FocusedOnly`] unless nessary and keep processing to a minimum. + /// + /// ## Platform-specific + /// + /// - ** Wayland / macOS / iOS / Android**: Unsupported. + /// + /// # Example + /// ```,no_run + /// tauri::Builder::default().on_device_event(|_app, _device_id, event| match event { + /// DeviceEvent::MouseMotion { delta } => { + /// println!("Mouse moved: {:?}", delta); + /// } + /// DeviceEvent::MouseWheel { delta } => { + /// println!("Mouse wheel: {:?}", delta); + /// } + /// _ => {} + /// }); + /// ``` + pub fn on_device_event(mut self, callback: F) -> Self + where + F: FnMut(&AppHandle, R::DeviceId, DeviceEvent) + Send + 'static, + { + self.device_event_callback = Some(Box::new(callback)); + self + } + /// Builds the application. #[allow(clippy::type_complexity, unused_mut)] #[cfg_attr( @@ -2183,18 +2201,27 @@ tauri::Builder::default() let runtime_handle = runtime.handle(); + let app_handle = AppHandle { + runtime_handle: runtime_handle, + manager: manager.clone(), + event_loop: Arc::new(Mutex::new(EventLoop { + main_thread_id: std::thread::current().id(), + })), + }; + + if let Some(mut device_event_callback) = self.device_event_callback { + let app_handle_clone = app_handle.clone(); + runtime.set_device_event_callback(move |id, event| { + device_event_callback(&app_handle_clone, id, event); + }); + } + #[allow(unused_mut)] let mut app = App { runtime: Some(runtime), setup: Some(self.setup), - manager: manager.clone(), - handle: AppHandle { - runtime_handle, - manager, - event_loop: Arc::new(Mutex::new(EventLoop { - main_thread_id: std::thread::current().id(), - })), - }, + manager: manager, + handle: app_handle, ran_setup: false, }; diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs index 7809dfbfcd0e..9c430e75fb91 100644 --- a/crates/tauri/src/lib.rs +++ b/crates/tauri/src/lib.rs @@ -218,12 +218,15 @@ pub use { }, self::manager::Asset, self::runtime::{ + device_events::{ + AxisId, ButtonId, Code, DeviceEvent, DeviceEventFilter, DeviceId, KeyState, MouseScrollDelta, + }, dpi::{ LogicalPosition, LogicalRect, LogicalSize, PhysicalPosition, PhysicalRect, PhysicalSize, Pixel, Position, Rect, Size, }, window::{CursorIcon, DragDropEvent, WindowSizeConstraints}, - DeviceEventFilter, UserAttentionType, + UserAttentionType, }, self::state::{State, StateManager}, self::utils::{ From 829232ba9dc3276651c67ed4531c9c5010dd1744 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:35:03 +1200 Subject: [PATCH 06/14] feat: implement DeviceId struct and update device event filter methods in MockRuntime --- crates/tauri/src/test/mock_runtime.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/tauri/src/test/mock_runtime.rs b/crates/tauri/src/test/mock_runtime.rs index 1c1b9ca43767..01918de4cdfa 100644 --- a/crates/tauri/src/test/mock_runtime.rs +++ b/crates/tauri/src/test/mock_runtime.rs @@ -6,6 +6,7 @@ #![allow(missing_docs)] use tauri_runtime::{ + device_events::DeviceEventFilter, dpi::{PhysicalPosition, PhysicalSize, Position, Size}, monitor::Monitor, webview::{DetachedWebview, PendingWebview}, @@ -13,9 +14,9 @@ use tauri_runtime::{ CursorIcon, DetachedWindow, DetachedWindowWebview, PendingWindow, RawWindow, WindowBuilder, WindowBuilderBase, WindowEvent, WindowId, }, - DeviceEventFilter, Error, EventLoopProxy, ExitRequestedEventAction, Icon, ProgressBarState, - Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, UserEvent, - WebviewDispatch, WindowDispatch, WindowEventId, + Error, EventLoopProxy, ExitRequestedEventAction, Icon, ProgressBarState, Result, RunEvent, + Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, UserEvent, WebviewDispatch, + WindowDispatch, WindowEventId, }; #[cfg(target_os = "macos")] @@ -1111,6 +1112,14 @@ impl MockRuntime { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DeviceId(u32); +impl tauri_runtime::device_events::DeviceId for DeviceId { + unsafe fn dummy() -> Self { + Self(0) + } +} + impl Runtime for MockRuntime { type WindowDispatcher = MockWindowDispatcher; type WebviewDispatcher = MockWebviewDispatcher; @@ -1235,7 +1244,15 @@ impl Runtime for MockRuntime { #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] fn hide(&self) {} - fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {} + fn set_device_event_filter(&self, filter: DeviceEventFilter) {} + + type DeviceId = DeviceId; + + fn set_device_event_callback(&self, callback: F) + where + F: FnMut(Self::DeviceId, tauri_runtime::device_events::DeviceEvent) + Send + 'static, + { + } #[cfg(any( target_os = "macos", From e3401b5fbff20e82a031c6ab791224397427aafc Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:50:55 +1200 Subject: [PATCH 07/14] chore: add copyright and license headers to device event files --- crates/tauri-runtime-wry/src/map_device_event.rs | 4 ++++ crates/tauri-runtime/src/device_events.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/crates/tauri-runtime-wry/src/map_device_event.rs b/crates/tauri-runtime-wry/src/map_device_event.rs index 303ef033771a..4ca0dde8b37d 100644 --- a/crates/tauri-runtime-wry/src/map_device_event.rs +++ b/crates/tauri-runtime-wry/src/map_device_event.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use tauri_runtime::device_events::{Code, DeviceEvent, MouseScrollDelta}; pub fn map_device_event(event: tao::event::DeviceEvent) -> Option { diff --git a/crates/tauri-runtime/src/device_events.rs b/crates/tauri-runtime/src/device_events.rs index e576acdd0a34..38c02b68f2c6 100644 --- a/crates/tauri-runtime/src/device_events.rs +++ b/crates/tauri-runtime/src/device_events.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use dpi::PhysicalPosition; pub use keyboard_types::{Code, KeyState}; use serde::{Deserialize, Serialize}; From 93068b750fbda1696fd20a12789e0eca91982f6a Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:53:56 +1200 Subject: [PATCH 08/14] fix: update deprecated key mappings for Hyper and Turbo in map_physical_key function --- crates/tauri-runtime-wry/src/map_device_event.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/tauri-runtime-wry/src/map_device_event.rs b/crates/tauri-runtime-wry/src/map_device_event.rs index 4ca0dde8b37d..c94fb442a003 100644 --- a/crates/tauri-runtime-wry/src/map_device_event.rs +++ b/crates/tauri-runtime-wry/src/map_device_event.rs @@ -195,8 +195,10 @@ fn map_physical_key(event: tao::keyboard::KeyCode) -> Option { tao::keyboard::KeyCode::AudioVolumeMute => Some(Code::AudioVolumeMute), tao::keyboard::KeyCode::AudioVolumeUp => Some(Code::AudioVolumeUp), tao::keyboard::KeyCode::WakeUp => Some(Code::WakeUp), - tao::keyboard::KeyCode::Hyper => Some(Code::Hyper), - tao::keyboard::KeyCode::Turbo => Some(Code::Turbo), + // maybe needs to be changed but [`Code::Hyper`] is deprecated + tao::keyboard::KeyCode::Hyper => Some(Code::MetaLeft), + // maybe needs to be changed but [`Code::Super`] is deprecated + tao::keyboard::KeyCode::Turbo => Some(Code::MetaLeft), tao::keyboard::KeyCode::Abort => Some(Code::Abort), tao::keyboard::KeyCode::Resume => Some(Code::Resume), tao::keyboard::KeyCode::Suspend => Some(Code::Suspend), From b8ca0767fb47582deb91cbd00926e14089a2d2fe Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:58:23 +1200 Subject: [PATCH 09/14] fmt --- crates/tauri-runtime/Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/tauri-runtime/Cargo.toml b/crates/tauri-runtime/Cargo.toml index 5a8b79b41bf7..5ecce1e242fe 100644 --- a/crates/tauri-runtime/Cargo.toml +++ b/crates/tauri-runtime/Cargo.toml @@ -18,11 +18,11 @@ rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"] default-target = "x86_64-unknown-linux-gnu" targets = [ - "x86_64-pc-windows-msvc", - "x86_64-unknown-linux-gnu", - "x86_64-apple-darwin", - "x86_64-linux-android", - "x86_64-apple-ios", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-linux-android", + "x86_64-apple-ios", ] [dependencies] @@ -51,8 +51,8 @@ jni = "0.21" [target.'cfg(all(target_vendor = "apple", not(target_os = "macos")))'.dependencies] objc2 = "0.6" objc2-ui-kit = { version = "0.3.0", default-features = false, features = [ - "UIView", - "UIResponder", + "UIView", + "UIResponder", ] } [target."cfg(target_os = \"macos\")".dependencies] From 2d5d1d66b6ab4aead5a5170e0f2df735b1d08af8 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 22:58:47 +1200 Subject: [PATCH 10/14] cargo fmt --- crates/tauri-runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tauri-runtime/src/lib.rs b/crates/tauri-runtime/src/lib.rs index 9efa957f7fa0..0baaee4a2f8f 100644 --- a/crates/tauri-runtime/src/lib.rs +++ b/crates/tauri-runtime/src/lib.rs @@ -444,7 +444,7 @@ pub trait Runtime: Debug + Sized + 'static { /// - ** Wayland / macOS / iOS / Android**: Unsupported. /// /// [`tao`]: https://crates.io/crates/tao - fn set_device_event_callback< F>(&self, callback: F) + fn set_device_event_callback(&self, callback: F) where F: FnMut(Self::DeviceId, device_events::DeviceEvent) + Send + 'static; From d62eec204bf319f5d32368090e9b263e0b668d33 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 23:18:41 +1200 Subject: [PATCH 11/14] fix: handle unidentified key codes in map_physical_key function --- crates/tauri-runtime-wry/src/map_device_event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tauri-runtime-wry/src/map_device_event.rs b/crates/tauri-runtime-wry/src/map_device_event.rs index c94fb442a003..6a5c21fd76ab 100644 --- a/crates/tauri-runtime-wry/src/map_device_event.rs +++ b/crates/tauri-runtime-wry/src/map_device_event.rs @@ -50,7 +50,7 @@ fn map_element_state( fn map_physical_key(event: tao::keyboard::KeyCode) -> Option { match event { - tao::keyboard::KeyCode::Unidentified(native_key_code) => todo!(), + tao::keyboard::KeyCode::Unidentified(_) => None, tao::keyboard::KeyCode::Backquote => Some(Code::Backquote), tao::keyboard::KeyCode::Backslash => Some(Code::Backslash), tao::keyboard::KeyCode::BracketLeft => Some(Code::BracketLeft), From dce423b5ec71ea11951562aed05c0c365e277dfe Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 23:19:11 +1200 Subject: [PATCH 12/14] fix clippy --- crates/tauri/src/app.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 703f2f4532c9..de6c8ecc07e6 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -2202,7 +2202,7 @@ tauri::Builder::default() let runtime_handle = runtime.handle(); let app_handle = AppHandle { - runtime_handle: runtime_handle, + runtime_handle, manager: manager.clone(), event_loop: Arc::new(Mutex::new(EventLoop { main_thread_id: std::thread::current().id(), @@ -2220,7 +2220,7 @@ tauri::Builder::default() let mut app = App { runtime: Some(runtime), setup: Some(self.setup), - manager: manager, + manager, handle: app_handle, ran_setup: false, }; From 62db25becf39e49e3f9c43fd7c0bff94109e155a Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 23:26:19 +1200 Subject: [PATCH 13/14] add to change log --- .changes/feat-device-events.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changes/feat-device-events.md diff --git a/.changes/feat-device-events.md b/.changes/feat-device-events.md new file mode 100644 index 000000000000..13852dfe39f3 --- /dev/null +++ b/.changes/feat-device-events.md @@ -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 From 3292bbe40c06d8ba8b332d020098f1280aadf3a5 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 8 May 2025 23:49:33 +1200 Subject: [PATCH 14/14] fix: correct example code for device event handling in documentation --- crates/tauri/src/app.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index de6c8ecc07e6..ebb28a7ff57c 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -2073,12 +2073,12 @@ tauri::Builder::default() /// - ** Wayland / macOS / iOS / Android**: Unsupported. /// /// # Example - /// ```,no_run + /// ``` /// tauri::Builder::default().on_device_event(|_app, _device_id, event| match event { - /// DeviceEvent::MouseMotion { delta } => { + /// tauri::DeviceEvent::MouseMotion { delta } => { /// println!("Mouse moved: {:?}", delta); /// } - /// DeviceEvent::MouseWheel { delta } => { + /// tauri::DeviceEvent::MouseWheel { delta } => { /// println!("Mouse wheel: {:?}", delta); /// } /// _ => {}