mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-09-26 21:41:48 +02:00
feat(global-shortcut): support pressed/released states (#1244)
closes #1243
This commit is contained in:
@@ -24,4 +24,4 @@ log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
|
||||
global-hotkey = "0.5"
|
||||
global-hotkey = { version = "0.5", features = ["serde"]}
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_GLOBALSHORTCUT__=function(t){"use strict";function e(t,e,s,n){if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return e.get(t)}function s(t,e,s,n,r){if("function"==typeof e?t!==e||!r:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,s),s}var n,r,i;"function"==typeof SuppressedError&&SuppressedError;class o{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,n.set(this,(()=>{})),r.set(this,0),i.set(this,{}),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((({message:t,id:o})=>{if(o===e(this,r)){s(this,r,o+1),e(this,n).call(this,t);const a=Object.keys(e(this,i));if(a.length>0){let t=o+1;for(const s of a.sort()){if(parseInt(s)!==t)break;{const r=e(this,i)[s];delete e(this,i)[s],e(this,n).call(this,r),t+=1}}}}else e(this,i)[o.toString()]=t}))}set onmessage(t){s(this,n,t)}get onmessage(){return e(this,n)}toJSON(){return`__CHANNEL__:${this.id}`}}async function a(t,e={},s){return window.__TAURI_INTERNALS__.invoke(t,e,s)}return n=new WeakMap,r=new WeakMap,i=new WeakMap,t.isRegistered=async function(t){return await a("plugin:global-shortcut|is_registered",{shortcut:t})},t.register=async function(t,e){const s=new o;s.onmessage=e,await a("plugin:global-shortcut|register",{shortcut:t,handler:s})},t.registerAll=async function(t,e){const s=new o;s.onmessage=e,await a("plugin:global-shortcut|register_all",{shortcuts:t,handler:s})},t.unregister=async function(t){await a("plugin:global-shortcut|unregister",{shortcut:t})},t.unregisterAll=async function(){await a("plugin:global-shortcut|unregister_all")},t}({});Object.defineProperty(window.__TAURI__,"globalShortcut",{value:__TAURI_PLUGIN_GLOBALSHORTCUT__})}
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_GLOBALSHORTCUT__=function(t){"use strict";function e(t,e,r,s){if("a"===r&&!s)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?s:"a"===r?s.call(t):s?s.value:e.get(t)}function r(t,e,r,s,n){if("m"===s)throw new TypeError("Private method is not writable");if("a"===s&&!n)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===s?n.call(t,r):n?n.value=r:e.set(t,r),r}var s,n,i;"function"==typeof SuppressedError&&SuppressedError;class o{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,s.set(this,(()=>{})),n.set(this,0),i.set(this,{}),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((({message:t,id:o})=>{if(o===e(this,n,"f")){r(this,n,o+1,"f"),e(this,s,"f").call(this,t);const a=Object.keys(e(this,i,"f"));if(a.length>0){let t=o+1;for(const r of a.sort()){if(parseInt(r)!==t)break;{const n=e(this,i,"f")[r];delete e(this,i,"f")[r],e(this,s,"f").call(this,n),t+=1}}}}else e(this,i,"f")[o.toString()]=t}))}set onmessage(t){r(this,s,t,"f")}get onmessage(){return e(this,s,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}async function a(t,e={},r){return window.__TAURI_INTERNALS__.invoke(t,e,r)}return s=new WeakMap,n=new WeakMap,i=new WeakMap,t.isRegistered=async function(t){return await a("plugin:global-shortcut|is_registered",{shortcut:t})},t.register=async function(t,e){const r=new o;r.onmessage=e,await a("plugin:global-shortcut|register",{shortcut:t,handler:r})},t.registerAll=async function(t,e){const r=new o;r.onmessage=e,await a("plugin:global-shortcut|register_all",{shortcuts:t,handler:r})},t.unregister=async function(t){await a("plugin:global-shortcut|unregister",{shortcut:t})},t.unregisterAll=async function(){await a("plugin:global-shortcut|unregister_all")},t}({});Object.defineProperty(window.__TAURI__,"globalShortcut",{value:__TAURI_PLUGIN_GLOBALSHORTCUT__})}
|
||||
|
||||
@@ -10,7 +10,13 @@
|
||||
|
||||
import { invoke, Channel } from "@tauri-apps/api/core";
|
||||
|
||||
export type ShortcutHandler = (shortcut: string) => void;
|
||||
export interface ShortcutEvent {
|
||||
shortcut: string;
|
||||
id: number;
|
||||
state: "Released" | "Pressed";
|
||||
}
|
||||
|
||||
export type ShortcutHandler = (event: ShortcutEvent) => void;
|
||||
|
||||
/**
|
||||
* Register a global shortcut.
|
||||
@@ -31,7 +37,7 @@ async function register(
|
||||
shortcut: string,
|
||||
handler: ShortcutHandler,
|
||||
): Promise<void> {
|
||||
const h = new Channel<string>();
|
||||
const h = new Channel<ShortcutEvent>();
|
||||
h.onmessage = handler;
|
||||
|
||||
await invoke("plugin:global-shortcut|register", {
|
||||
@@ -59,7 +65,7 @@ async function registerAll(
|
||||
shortcuts: string[],
|
||||
handler: ShortcutHandler,
|
||||
): Promise<void> {
|
||||
const h = new Channel<string>();
|
||||
const h = new Channel<ShortcutEvent>();
|
||||
h.onmessage = handler;
|
||||
|
||||
await invoke("plugin:global-shortcut|register_all", {
|
||||
|
||||
@@ -20,8 +20,12 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
pub use global_hotkey::hotkey::{Code, HotKey as Shortcut, Modifiers};
|
||||
pub use global_hotkey::{
|
||||
hotkey::{Code, HotKey as Shortcut, Modifiers},
|
||||
GlobalHotKeyEvent as ShortcutEvent, HotKeyState as ShortcutState,
|
||||
};
|
||||
use global_hotkey::{GlobalHotKeyEvent, GlobalHotKeyManager};
|
||||
use serde::Serialize;
|
||||
use tauri::{
|
||||
ipc::Channel,
|
||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||
@@ -32,8 +36,9 @@ mod error;
|
||||
|
||||
pub use error::Error;
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
type HotKeyId = u32;
|
||||
type HandlerFn<R> = Box<dyn Fn(&AppHandle<R>, &Shortcut) + Send + Sync + 'static>;
|
||||
type HandlerFn<R> = Box<dyn Fn(&AppHandle<R>, &Shortcut, ShortcutEvent) + Send + Sync + 'static>;
|
||||
|
||||
pub struct ShortcutWrapper(Shortcut);
|
||||
|
||||
@@ -63,7 +68,7 @@ pub struct GlobalShortcut<R: Runtime> {
|
||||
}
|
||||
|
||||
impl<R: Runtime> GlobalShortcut<R> {
|
||||
fn register_internal<F: Fn(&AppHandle<R>, &Shortcut) + Send + Sync + 'static>(
|
||||
fn register_internal<F: Fn(&AppHandle<R>, &Shortcut, ShortcutEvent) + Send + Sync + 'static>(
|
||||
&self,
|
||||
shortcut: Shortcut,
|
||||
handler: Option<F>,
|
||||
@@ -82,7 +87,7 @@ impl<R: Runtime> GlobalShortcut<R> {
|
||||
fn register_all_internal<S, F>(&self, shortcuts: S, handler: Option<F>) -> Result<()>
|
||||
where
|
||||
S: IntoIterator<Item = Shortcut>,
|
||||
F: Fn(&AppHandle<R>, &Shortcut) + Send + Sync + 'static,
|
||||
F: Fn(&AppHandle<R>, &Shortcut, ShortcutEvent) + Send + Sync + 'static,
|
||||
{
|
||||
let handler = handler.map(|h| Arc::new(Box::new(h) as HandlerFn<R>));
|
||||
|
||||
@@ -111,7 +116,7 @@ impl<R: Runtime> GlobalShortcut<R> {
|
||||
{
|
||||
self.register_internal(
|
||||
try_into_shortcut(shortcut)?,
|
||||
None::<fn(&AppHandle<R>, &Shortcut)>,
|
||||
None::<fn(&AppHandle<R>, &Shortcut, ShortcutEvent)>,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -120,7 +125,7 @@ impl<R: Runtime> GlobalShortcut<R> {
|
||||
where
|
||||
S: TryInto<ShortcutWrapper>,
|
||||
S::Error: std::error::Error,
|
||||
F: Fn(&AppHandle<R>, &Shortcut) + Send + Sync + 'static,
|
||||
F: Fn(&AppHandle<R>, &Shortcut, ShortcutEvent) + Send + Sync + 'static,
|
||||
{
|
||||
self.register_internal(try_into_shortcut(shortcut)?, Some(handler))
|
||||
}
|
||||
@@ -136,7 +141,7 @@ impl<R: Runtime> GlobalShortcut<R> {
|
||||
for shortcut in shortcuts {
|
||||
s.push(try_into_shortcut(shortcut)?);
|
||||
}
|
||||
self.register_all_internal(s, None::<fn(&AppHandle<R>, &Shortcut)>)
|
||||
self.register_all_internal(s, None::<fn(&AppHandle<R>, &Shortcut, ShortcutEvent)>)
|
||||
}
|
||||
|
||||
/// Register multiple shortcuts with a handler.
|
||||
@@ -145,7 +150,7 @@ impl<R: Runtime> GlobalShortcut<R> {
|
||||
S: IntoIterator<Item = T>,
|
||||
T: TryInto<ShortcutWrapper>,
|
||||
T::Error: std::error::Error,
|
||||
F: Fn(&AppHandle<R>, &Shortcut) + Send + Sync + 'static,
|
||||
F: Fn(&AppHandle<R>, &Shortcut, ShortcutEvent) + Send + Sync + 'static,
|
||||
{
|
||||
let mut s = Vec::new();
|
||||
for shortcut in shortcuts {
|
||||
@@ -225,6 +230,13 @@ where
|
||||
.map_err(|e| Error::GlobalHotkey(e.to_string()))
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ShortcutJsEvent {
|
||||
shortcut: String,
|
||||
id: u32,
|
||||
state: ShortcutState,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn register<R: Runtime>(
|
||||
_window: Window<R>,
|
||||
@@ -233,10 +245,17 @@ fn register<R: Runtime>(
|
||||
handler: Channel,
|
||||
) -> Result<()> {
|
||||
global_shortcut.register_internal(
|
||||
parse_shortcut(&shortcut)?,
|
||||
Some(move |_app: &AppHandle<R>, _shortcut: &Shortcut| {
|
||||
let _ = handler.send(&shortcut);
|
||||
}),
|
||||
parse_shortcut(shortcut)?,
|
||||
Some(
|
||||
move |_app: &AppHandle<R>, shortcut: &Shortcut, e: ShortcutEvent| {
|
||||
let js_event = ShortcutJsEvent {
|
||||
id: e.id,
|
||||
state: e.state,
|
||||
shortcut: shortcut.into_string(),
|
||||
};
|
||||
let _ = handler.send(js_event);
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -258,11 +277,16 @@ fn register_all<R: Runtime>(
|
||||
|
||||
global_shortcut.register_all_internal(
|
||||
hotkeys,
|
||||
Some(move |_app: &AppHandle<R>, shortcut: &Shortcut| {
|
||||
if let Some(shortcut_str) = shortcut_map.get(&shortcut.id()) {
|
||||
let _ = handler.send(shortcut_str);
|
||||
}
|
||||
}),
|
||||
Some(
|
||||
move |_app: &AppHandle<R>, shortcut: &Shortcut, e: ShortcutEvent| {
|
||||
let js_event = ShortcutJsEvent {
|
||||
id: e.id,
|
||||
state: e.state,
|
||||
shortcut: shortcut.into_string(),
|
||||
};
|
||||
let _ = handler.send(js_event);
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -341,7 +365,7 @@ impl<R: Runtime> Builder<R> {
|
||||
}
|
||||
|
||||
/// Specify a global shortcut handler that will be triggered for any and all shortcuts.
|
||||
pub fn with_handler<F: Fn(&AppHandle<R>, &Shortcut) + Send + Sync + 'static>(
|
||||
pub fn with_handler<F: Fn(&AppHandle<R>, &Shortcut, ShortcutEvent) + Send + Sync + 'static>(
|
||||
mut self,
|
||||
handler: F,
|
||||
) -> Self {
|
||||
@@ -381,10 +405,10 @@ impl<R: Runtime> Builder<R> {
|
||||
GlobalHotKeyEvent::set_event_handler(Some(move |e: GlobalHotKeyEvent| {
|
||||
if let Some(shortcut) = shortcuts_.lock().unwrap().get(&e.id) {
|
||||
if let Some(handler) = &shortcut.handler {
|
||||
handler(&app_handle, &shortcut.shortcut);
|
||||
handler(&app_handle, &shortcut.shortcut, e);
|
||||
}
|
||||
if let Some(handler) = &handler {
|
||||
handler(&app_handle, &shortcut.shortcut);
|
||||
handler(&app_handle, &shortcut.shortcut, e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user