1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use super::InvokeResponse;
use crate::{Params, Window};
use serde::Deserialize;

#[cfg(global_shortcut_all)]
use crate::{api::shortcuts::ShortcutManager, runtime::Dispatch};

#[cfg(global_shortcut_all)]
type ShortcutManagerHandle = std::sync::Arc<std::sync::Mutex<ShortcutManager>>;

#[cfg(global_shortcut_all)]
pub fn manager_handle() -> &'static ShortcutManagerHandle {
  use once_cell::sync::Lazy;
  static MANAGER: Lazy<ShortcutManagerHandle> = Lazy::new(Default::default);
  &MANAGER
}

/// The API descriptor.
#[derive(Deserialize)]
#[serde(tag = "cmd", rename_all = "camelCase")]
pub enum Cmd {
  /// Register a global shortcut.
  Register { shortcut: String, handler: String },
  /// Register a list of global shortcuts.
  RegisterAll {
    shortcuts: Vec<String>,
    handler: String,
  },
  /// Unregister a global shortcut.
  Unregister { shortcut: String },
  /// Unregisters all registered shortcuts.
  UnregisterAll,
  /// Determines whether the given hotkey is registered or not.
  IsRegistered { shortcut: String },
}

#[cfg(global_shortcut_all)]
fn register_shortcut<D: Dispatch>(
  dispatcher: D,
  manager: &mut ShortcutManager,
  shortcut: String,
  handler: String,
) -> crate::Result<()> {
  manager.register(shortcut.clone(), move || {
    let callback_string = crate::api::rpc::format_callback(handler.to_string(), &shortcut)
      .expect("unable to serialize shortcut string to json");
    let _ = dispatcher.eval_script(callback_string.as_str());
  })?;
  Ok(())
}

#[cfg(not(global_shortcut_all))]
impl Cmd {
  pub fn run<P: Params>(self, _window: Window<P>) -> crate::Result<InvokeResponse> {
    Err(crate::Error::ApiNotAllowlisted(
      "globalShortcut > all".to_string(),
    ))
  }
}

#[cfg(global_shortcut_all)]
impl Cmd {
  pub fn run<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
    match self {
      Self::Register { shortcut, handler } => {
        let dispatcher = window.dispatcher();
        let mut manager = manager_handle().lock().unwrap();
        register_shortcut(dispatcher, &mut manager, shortcut, handler)?;
        Ok(().into())
      }
      Self::RegisterAll { shortcuts, handler } => {
        let dispatcher = window.dispatcher();
        let mut manager = manager_handle().lock().unwrap();
        for shortcut in shortcuts {
          let dispatch = dispatcher.clone();
          register_shortcut(dispatch, &mut manager, shortcut, handler.clone())?;
        }
        Ok(().into())
      }
      Self::Unregister { shortcut } => {
        let mut manager = manager_handle().lock().unwrap();
        manager.unregister(shortcut)?;
        Ok(().into())
      }
      Self::UnregisterAll => {
        let mut manager = manager_handle().lock().unwrap();
        manager.unregister_all()?;
        Ok(().into())
      }
      Self::IsRegistered { shortcut } => {
        let manager = manager_handle().lock().unwrap();
        Ok(manager.is_registered(shortcut)?.into())
      }
    }
  }
}