diff --git a/examples/overlay.rs b/examples/overlay.rs index 879a57a1b..405765ce8 100644 --- a/examples/overlay.rs +++ b/examples/overlay.rs @@ -6,7 +6,7 @@ //! We also add a global shortcut to toggle the overlay on and off, so you could build a raycast-type app with this. use dioxus::desktop::{ - tao::dpi::PhysicalPosition, use_global_shortcut, LogicalSize, WindowBuilder, + tao::dpi::PhysicalPosition, use_global_shortcut, HotKeyState, LogicalSize, WindowBuilder, }; use dioxus::prelude::*; @@ -19,7 +19,11 @@ fn main() { fn app() -> Element { let mut show_overlay = use_signal(|| true); - _ = use_global_shortcut("cmd+g", move || show_overlay.toggle()); + _ = use_global_shortcut("cmd+g", move |state| { + if state == HotKeyState::Pressed { + show_overlay.toggle(); + } + }); rsx! { document::Link { diff --git a/examples/shortcut.rs b/examples/shortcut.rs index 14e5beec3..eed58533f 100644 --- a/examples/shortcut.rs +++ b/examples/shortcut.rs @@ -5,7 +5,7 @@ //! //! These are *global* shortcuts, so they will work even if your app is not in focus. -use dioxus::desktop::use_global_shortcut; +use dioxus::desktop::{use_global_shortcut, HotKeyState}; use dioxus::prelude::*; fn main() { @@ -15,7 +15,11 @@ fn main() { fn app() -> Element { let mut toggled = use_signal(|| false); - _ = use_global_shortcut("ctrl+s", move || toggled.toggle()); + _ = use_global_shortcut("ctrl+s", move |state| { + if state == HotKeyState::Pressed { + toggled.toggle(); + } + }); rsx!("toggle: {toggled}") } diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 1966b0a7e..6243a4427 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -4,7 +4,7 @@ use crate::{ file_upload::NativeFileHover, ipc::UserWindowEvent, query::QueryEngine, - shortcut::{HotKey, ShortcutHandle, ShortcutRegistryError}, + shortcut::{HotKey, HotKeyState, ShortcutHandle, ShortcutRegistryError}, webview::WebviewInstance, AssetRequest, Config, WryEventHandler, }; @@ -214,7 +214,7 @@ impl DesktopService { pub fn create_shortcut( &self, hotkey: HotKey, - callback: impl FnMut() + 'static, + callback: impl FnMut(HotKeyState) + 'static, ) -> Result { self.shared .shortcut_manager diff --git a/packages/desktop/src/hooks.rs b/packages/desktop/src/hooks.rs index c7992fc16..0b752d3a7 100644 --- a/packages/desktop/src/hooks.rs +++ b/packages/desktop/src/hooks.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use crate::{ assets::*, ipc::UserWindowEvent, shortcut::IntoAccelerator, window, DesktopContext, - ShortcutHandle, ShortcutRegistryError, WryEventHandler, + HotKeyState, ShortcutHandle, ShortcutRegistryError, WryEventHandler, }; use dioxus_core::{ prelude::{consume_context, use_hook_with_cleanup}, @@ -116,13 +116,14 @@ pub fn use_asset_handler( /// Get a closure that executes any JavaScript in the WebView context. pub fn use_global_shortcut( accelerator: impl IntoAccelerator, - mut handler: impl FnMut() + 'static, + handler: impl FnMut(HotKeyState) + 'static, ) -> Result { // wrap the user's handler in something that keeps it up to date - let cb = use_callback(move |_| handler()); + let cb = use_callback(handler); use_hook_with_cleanup( - move || window().create_shortcut(accelerator.accelerator(), move || cb(())), + #[allow(clippy::redundant_closure)] + move || window().create_shortcut(accelerator.accelerator(), move |state| cb(state)), |handle| { if let Ok(handle) = handle { handle.remove(); diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 9eecdc6fe..341306870 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -51,5 +51,5 @@ pub use config::{Config, WindowCloseBehaviour}; pub use desktop_context::{window, DesktopContext, DesktopService, WeakDesktopContext}; pub use event_handlers::WryEventHandler; pub use hooks::*; -pub use shortcut::{ShortcutHandle, ShortcutRegistryError}; +pub use shortcut::{HotKeyState, ShortcutHandle, ShortcutRegistryError}; pub use wry::RequestAsyncResponder; diff --git a/packages/desktop/src/mobile_shortcut.rs b/packages/desktop/src/mobile_shortcut.rs index 5ff0683a1..40d77d4b9 100644 --- a/packages/desktop/src/mobile_shortcut.rs +++ b/packages/desktop/src/mobile_shortcut.rs @@ -78,6 +78,16 @@ impl fmt::Display for HotkeyError { pub struct GlobalHotKeyEvent { pub id: u32, + pub state: HotKeyState, +} + +/// Describes the state of the hotkey. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum HotKeyState { + /// The hotkey is pressed. + Pressed, + /// The hotkey is released. + Released, } pub(crate) type Code = dioxus_html::input_data::keyboard_types::Code; diff --git a/packages/desktop/src/shortcut.rs b/packages/desktop/src/shortcut.rs index 7949da2a1..49c59c774 100644 --- a/packages/desktop/src/shortcut.rs +++ b/packages/desktop/src/shortcut.rs @@ -9,7 +9,7 @@ ))] pub use global_hotkey::{ hotkey::{Code, HotKey}, - Error as HotkeyError, GlobalHotKeyEvent, GlobalHotKeyManager, + Error as HotkeyError, GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState, }; #[cfg(any(target_os = "ios", target_os = "android"))] @@ -53,7 +53,7 @@ pub(crate) struct ShortcutRegistry { struct ShortcutInner { #[allow(unused)] shortcut: HotKey, - callbacks: Slab>, + callbacks: Slab>, } impl ShortcutRegistry { @@ -68,7 +68,7 @@ impl ShortcutRegistry { pub(crate) fn call_handlers(&self, id: GlobalHotKeyEvent) { if let Some(ShortcutInner { callbacks, .. }) = self.shortcuts.borrow_mut().get_mut(&id.id) { for (_, callback) in callbacks.iter_mut() { - (callback)(); + (callback)(id.state); } } } @@ -76,7 +76,7 @@ impl ShortcutRegistry { pub(crate) fn add_shortcut( &self, hotkey: HotKey, - callback: Box, + callback: Box, ) -> Result { let accelerator_id = hotkey.clone().id();