refactor(global-shortcut): enhance `un/register` to accept an array, remove `un/registerAll` (#1117)

* refactor(shell): enhance `un/register` to accept an array, remove `un/registerAll`

closes #1101

* Update lib.rs

* remove permissions, cleanup docs

* bring back unregister_all

* fmt

* fix build

* bundle

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
pull/1527/head
Amr Bashir 1 year ago committed by GitHub
parent a66549329c
commit 381a466db3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,10 @@
---
"global-shortcut": "patch"
---
Refactored the Rust APIs:
- Renamed `GlobalShortcut::on_all_shortcuts` to `GlobalShortcut::on_shortcuts`
- Renamed `GlobalShortcut::register_all` to `GlobalShortcut::register_multiple`
- Changed `GlobalShortcut::unregister_all` behavior to remove all registerd shortcuts.
- Added `GlobalShortcut::unregister_multiple` to register a list of shortcuts (old behavior of `unregister_all`).

@ -0,0 +1,8 @@
---
"global-shortcut-js": "patch"
---
Refactored the JS APIs:
- Enhanced `register` and `unregister` to take either a single shortcut or an array.
- Removed `registerAll` instead use `register` with an array.

@ -4850,13 +4850,6 @@
"global-shortcut:allow-register"
]
},
{
"description": "global-shortcut:allow-register-all -> Enables the register_all command without any pre-configured scope.",
"type": "string",
"enum": [
"global-shortcut:allow-register-all"
]
},
{
"description": "global-shortcut:allow-unregister -> Enables the unregister command without any pre-configured scope.",
"type": "string",
@ -4885,13 +4878,6 @@
"global-shortcut:deny-register"
]
},
{
"description": "global-shortcut:deny-register-all -> Denies the register_all command without any pre-configured scope.",
"type": "string",
"enum": [
"global-shortcut:deny-register-all"
]
},
{
"description": "global-shortcut:deny-unregister -> Denies the unregister command without any pre-configured scope.",
"type": "string",

@ -1,9 +1,8 @@
<script>
import { writable } from "svelte/store";
import { writable, get } from "svelte/store";
import {
register as registerShortcut,
unregister as unregisterShortcut,
unregisterAll as unregisterAllShortcuts,
} from "@tauri-apps/plugin-global-shortcut";
export let onMessage;
@ -35,7 +34,7 @@
}
function unregisterAll() {
unregisterAllShortcuts()
unregisterShortcut(get(shortcuts))
.then(() => {
shortcuts.update(() => []);
onMessage(`Unregistered all shortcuts`);

@ -1 +1 @@
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("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 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),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}}r(this,n,t)}}else e(this,i,"f")[o.toString()]=t}))}set onmessage(t){r(this,s,t)}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__})}
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("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 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),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}}r(this,n,t)}}else e(this,i,"f")[o.toString()]=t}))}set onmessage(t){r(this,s,t)}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;return r.onmessage=e,await a("plugin:global-shortcut|register",{shortcuts:Array.isArray(t)?t:[t],handler:r})},t.unregister=async function(t){return await a("plugin:global-shortcut|unregister",{shortcuts:Array.isArray(t)?t:[t]})},t.unregisterAll=async function(){return await a("plugin:global-shortcut|unregister_all",{})},t}({});Object.defineProperty(window.__TAURI__,"globalShortcut",{value:__TAURI_PLUGIN_GLOBALSHORTCUT__})}

@ -2,13 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
const COMMANDS: &[&str] = &[
"register",
"register_all",
"unregister",
"unregister_all",
"is_registered",
];
const COMMANDS: &[&str] = &["register", "unregister", "unregister_all", "is_registered"];
fn main() {
tauri_plugin::Builder::new(COMMANDS)

@ -19,15 +19,28 @@ export interface ShortcutEvent {
export type ShortcutHandler = (event: ShortcutEvent) => void;
/**
* Register a global shortcut.
* Register a global shortcut or a list of shortcuts.
*
* The handler is called when any of the registered shortcuts are pressed by the user.
*
* If the shortcut is already taken by another application, the handler will not be triggered.
* Make sure the shortcut is as unique as possible while still taking user experience into consideration.
*
* @example
* ```typescript
* import { register } from '@tauri-apps/plugin-global-shortcut';
*
* // register a single hotkey
* await register('CommandOrControl+Shift+C', (event) => {
* if (event.state === "Pressed") {
* console.log('Shortcut triggered');
* }
* });
*
* // or register multiple hotkeys at once
* await register(['CommandOrControl+Shift+C', 'Alt+A'], (event) => {
* console.log(`Shortcut ${event.shortcut} triggered`);
* });
* ```
*
* @param shortcut Shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q
@ -36,97 +49,75 @@ export type ShortcutHandler = (event: ShortcutEvent) => void;
* @since 2.0.0
*/
async function register(
shortcut: string,
shortcuts: string | string[],
handler: ShortcutHandler,
): Promise<void> {
const h = new Channel<ShortcutEvent>();
h.onmessage = handler;
await invoke("plugin:global-shortcut|register", {
shortcut,
return await invoke("plugin:global-shortcut|register", {
shortcuts: Array.isArray(shortcuts) ? shortcuts : [shortcuts],
handler: h,
});
}
/**
* Register a collection of global shortcuts.
* Unregister a global shortcut or a list of shortcuts.
*
* @example
* ```typescript
* import { registerAll } from '@tauri-apps/plugin-global-shortcut';
* await registerAll(['CommandOrControl+Shift+C', 'Ctrl+Alt+F12'], (event) => {
* console.log(`Shortcut ${event.shortcut} ${event.state}`);
* });
* import { unregister } from '@tauri-apps/plugin-global-shortcut';
*
* // unregister a single hotkey
* await unregister('CmdOrControl+Space');
*
* // or unregister multiple hotkeys at the same time
* await unregister(['CmdOrControl+Space', 'Alt+A']);
* ```
*
* @param shortcuts Array of shortcut definitions, modifiers and key separated by "+" e.g. CmdOrControl+Q
* @param handler Shortcut handler callback - takes the triggered shortcut as argument
* @param shortcut shortcut definition (modifiers and key separated by "+" e.g. CmdOrControl+Q), also accepts a list of shortcuts
*
* @since 2.0.0
*/
async function registerAll(
shortcuts: string[],
handler: ShortcutHandler,
): Promise<void> {
const h = new Channel<ShortcutEvent>();
h.onmessage = handler;
await invoke("plugin:global-shortcut|register_all", {
shortcuts,
handler: h,
async function unregister(shortcuts: string | string[]): Promise<void> {
return await invoke("plugin:global-shortcut|unregister", {
shortcuts: Array.isArray(shortcuts) ? shortcuts : [shortcuts],
});
}
/**
* Determines whether the given shortcut is registered by this application or not.
*
* If the shortcut is registered by another application, it will still return `false`.
* Unregister all global shortcuts.
*
* @example
* ```typescript
* import { isRegistered } from '@tauri-apps/plugin-global-shortcut';
* const isRegistered = await isRegistered('CommandOrControl+P');
* import { unregisterAll } from '@tauri-apps/plugin-global-shortcut';
* await unregisterAll();
* ```
*
* @param shortcut shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q
*
* @since 2.0.0
*/
async function isRegistered(shortcut: string): Promise<boolean> {
return await invoke("plugin:global-shortcut|is_registered", {
shortcut,
});
async function unregisterAll(): Promise<void> {
return await invoke("plugin:global-shortcut|unregister_all", {});
}
/**
* Unregister a global shortcut.
* Determines whether the given shortcut is registered by this application or not.
*
* If the shortcut is registered by another application, it will still return `false`.
*
* @example
* ```typescript
* import { unregister } from '@tauri-apps/plugin-global-shortcut';
* await unregister('CmdOrControl+Space');
* import { isRegistered } from '@tauri-apps/plugin-global-shortcut';
* const isRegistered = await isRegistered('CommandOrControl+P');
* ```
*
* @param shortcut shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q
*
* @since 2.0.0
*/
async function unregister(shortcut: string): Promise<void> {
await invoke("plugin:global-shortcut|unregister", {
async function isRegistered(shortcut: string): Promise<boolean> {
return await invoke("plugin:global-shortcut|is_registered", {
shortcut,
});
}
/**
* Unregisters all shortcuts registered by the application.
* @example
* ```typescript
* import { unregisterAll } from '@tauri-apps/plugin-global-shortcut';
* await unregisterAll();
* ```
*
* @since 2.0.0
*/
async function unregisterAll(): Promise<void> {
await invoke("plugin:global-shortcut|unregister_all");
}
export { register, registerAll, isRegistered, unregister, unregisterAll };
export { register, unregister, unregisterAll, isRegistered };

@ -29,7 +29,7 @@ use serde::Serialize;
use tauri::{
ipc::Channel,
plugin::{Builder as PluginBuilder, TauriPlugin},
AppHandle, Manager, Runtime, State, Window,
AppHandle, Manager, Runtime, State,
};
mod error;
@ -84,7 +84,7 @@ impl<R: Runtime> GlobalShortcut<R> {
Ok(())
}
fn register_all_internal<S, F>(&self, shortcuts: S, handler: Option<F>) -> Result<()>
fn register_multiple_internal<S, F>(&self, shortcuts: S, handler: Option<F>) -> Result<()>
where
S: IntoIterator<Item = Shortcut>,
F: Fn(&AppHandle<R>, &Shortcut, ShortcutEvent) + Send + Sync + 'static,
@ -107,7 +107,9 @@ impl<R: Runtime> GlobalShortcut<R> {
Ok(())
}
}
impl<R: Runtime> GlobalShortcut<R> {
/// Register a shortcut.
pub fn register<S>(&self, shortcut: S) -> Result<()>
where
@ -131,7 +133,7 @@ impl<R: Runtime> GlobalShortcut<R> {
}
/// Register multiple shortcuts.
pub fn register_all<S, T>(&self, shortcuts: S) -> Result<()>
pub fn register_multiple<S, T>(&self, shortcuts: S) -> Result<()>
where
S: IntoIterator<Item = T>,
T: TryInto<ShortcutWrapper>,
@ -141,11 +143,11 @@ 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, ShortcutEvent)>)
self.register_multiple_internal(s, None::<fn(&AppHandle<R>, &Shortcut, ShortcutEvent)>)
}
/// Register multiple shortcuts with a handler.
pub fn on_all_shortcuts<S, T, F>(&self, shortcuts: S, handler: F) -> Result<()>
pub fn on_shortcuts<S, T, F>(&self, shortcuts: S, handler: F) -> Result<()>
where
S: IntoIterator<Item = T>,
T: TryInto<ShortcutWrapper>,
@ -156,9 +158,10 @@ impl<R: Runtime> GlobalShortcut<R> {
for shortcut in shortcuts {
s.push(try_into_shortcut(shortcut)?);
}
self.register_all_internal(s, Some(handler))
self.register_multiple_internal(s, Some(handler))
}
/// Unregister a shortcut
pub fn unregister<S: TryInto<ShortcutWrapper>>(&self, shortcut: S) -> Result<()>
where
S::Error: std::error::Error,
@ -169,7 +172,8 @@ impl<R: Runtime> GlobalShortcut<R> {
Ok(())
}
pub fn unregister_all<T: TryInto<ShortcutWrapper>, S: IntoIterator<Item = T>>(
/// Unregister multiple shortcuts.
pub fn unregister_multiple<T: TryInto<ShortcutWrapper>, S: IntoIterator<Item = T>>(
&self,
shortcuts: S,
) -> Result<()>
@ -191,6 +195,16 @@ impl<R: Runtime> GlobalShortcut<R> {
Ok(())
}
/// Unregister all registered shortcuts.
pub fn unregister_all(&self) -> Result<()> {
let mut shortcuts = self.shortcuts.lock().unwrap();
let hotkeys = std::mem::take(&mut *shortcuts);
let hotkeys = hotkeys.values().map(|s| s.shortcut).collect::<Vec<_>>();
self.manager
.unregister_all(hotkeys.as_slice())
.map_err(Into::into)
}
/// Determines whether the given shortcut is registered by this application or not.
///
/// If the shortcut is registered by another application, it will still return `false`.
@ -239,29 +253,7 @@ struct ShortcutJsEvent {
#[tauri::command]
fn register<R: Runtime>(
_window: Window<R>,
global_shortcut: State<'_, GlobalShortcut<R>>,
shortcut: String,
handler: Channel,
) -> Result<()> {
global_shortcut.register_internal(
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);
},
),
)
}
#[tauri::command]
fn register_all<R: Runtime>(
_window: Window<R>,
_app: AppHandle<R>,
global_shortcut: State<'_, GlobalShortcut<R>>,
shortcuts: Vec<String>,
handler: Channel,
@ -275,7 +267,7 @@ fn register_all<R: Runtime>(
hotkeys.push(hotkey);
}
global_shortcut.register_all_internal(
global_shortcut.register_multiple_internal(
hotkeys,
Some(
move |_app: &AppHandle<R>, shortcut: &Shortcut, e: ShortcutEvent| {
@ -294,22 +286,21 @@ fn register_all<R: Runtime>(
fn unregister<R: Runtime>(
_app: AppHandle<R>,
global_shortcut: State<'_, GlobalShortcut<R>>,
shortcut: String,
shortcuts: Vec<String>,
) -> Result<()> {
global_shortcut.unregister(parse_shortcut(shortcut)?)
let mut hotkeys = Vec::new();
for shortcut in shortcuts {
hotkeys.push(parse_shortcut(&shortcut)?);
}
global_shortcut.unregister_multiple(hotkeys)
}
#[tauri::command]
fn unregister_all<R: Runtime>(
_app: AppHandle<R>,
global_shortcut: State<'_, GlobalShortcut<R>>,
shortcuts: Vec<String>,
) -> Result<()> {
let mut hotkeys = Vec::new();
for shortcut in shortcuts {
hotkeys.push(parse_shortcut(&shortcut)?);
}
global_shortcut.unregister_all(hotkeys)
global_shortcut.unregister_all()
}
#[tauri::command]
@ -379,10 +370,9 @@ impl<R: Runtime> Builder<R> {
PluginBuilder::new("global-shortcut")
.invoke_handler(tauri::generate_handler![
register,
register_all,
unregister,
unregister_all,
is_registered
is_registered,
])
.setup(move |app, _api| {
let manager = GlobalHotKeyManager::new()?;

Loading…
Cancel
Save