feat(core): add support for Disable/Enable
This commit is contained in:
		
							parent
							
								
									d193cb749b
								
							
						
					
					
						commit
						5abea19016
					
				| 
						 | 
				
			
			@ -61,6 +61,10 @@ impl<'a> ConfigManager<'a> {
 | 
			
		|||
    let match_paths = config.match_paths();
 | 
			
		||||
    (config, self.match_store.query(&match_paths))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub fn default(&self) -> &'a dyn Config {
 | 
			
		||||
    self.config_store.default()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										46
									
								
								espanso/src/cli/worker/engine/executor/icon.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								espanso/src/cli/worker/engine/executor/icon.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use espanso_ui::{UIRemote, icons::TrayIcon};
 | 
			
		||||
 | 
			
		||||
use crate::engine::{dispatch::IconHandler, event::ui::IconStatus};
 | 
			
		||||
 | 
			
		||||
pub struct IconHandlerAdapter<'a> {
 | 
			
		||||
  remote: &'a dyn UIRemote,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> IconHandlerAdapter<'a> {
 | 
			
		||||
  pub fn new(remote: &'a dyn UIRemote) -> Self {
 | 
			
		||||
    Self { remote }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> IconHandler for IconHandlerAdapter<'a> {
 | 
			
		||||
  fn update_icon(&self, status: &IconStatus) -> anyhow::Result<()> {
 | 
			
		||||
    let icon = match status {
 | 
			
		||||
      IconStatus::Enabled => TrayIcon::Normal,
 | 
			
		||||
      IconStatus::Disabled => TrayIcon::Disabled, 
 | 
			
		||||
      IconStatus::SecureInputDisabled => TrayIcon::SystemDisabled, 
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    self.remote.update_tray_icon(icon);
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -20,4 +20,5 @@
 | 
			
		|||
pub mod clipboard_injector;
 | 
			
		||||
pub mod context_menu;
 | 
			
		||||
pub mod event_injector;
 | 
			
		||||
pub mod icon;
 | 
			
		||||
pub mod key_injector;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ pub mod match_cache;
 | 
			
		|||
pub mod matcher;
 | 
			
		||||
pub mod multiplex;
 | 
			
		||||
pub mod path;
 | 
			
		||||
pub mod process;
 | 
			
		||||
pub mod render;
 | 
			
		||||
pub mod source;
 | 
			
		||||
pub mod ui;
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +119,8 @@ pub fn initialize_and_spawn(
 | 
			
		|||
        super::engine::render::RendererAdapter::new(&match_cache, &config_manager, &renderer);
 | 
			
		||||
      let path_provider = PathProviderAdapter::new(&paths);
 | 
			
		||||
 | 
			
		||||
      let disable_options = process::middleware::disable::extract_disable_options(config_manager.default());
 | 
			
		||||
 | 
			
		||||
      let mut processor = crate::engine::process::default(
 | 
			
		||||
        &matchers,
 | 
			
		||||
        &config_manager,
 | 
			
		||||
| 
						 | 
				
			
			@ -128,6 +131,7 @@ pub fn initialize_and_spawn(
 | 
			
		|||
        &modifier_state_store,
 | 
			
		||||
        &sequencer,
 | 
			
		||||
        &path_provider,
 | 
			
		||||
        disable_options,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      let event_injector =
 | 
			
		||||
| 
						 | 
				
			
			@ -140,6 +144,7 @@ pub fn initialize_and_spawn(
 | 
			
		|||
        );
 | 
			
		||||
      let key_injector = super::engine::executor::key_injector::KeyInjectorAdapter::new(&*injector);
 | 
			
		||||
      let context_menu_adapter = super::engine::executor::context_menu::ContextMenuHandlerAdapter::new(&*ui_remote);
 | 
			
		||||
      let icon_adapter = super::engine::executor::icon::IconHandlerAdapter::new(&*ui_remote);
 | 
			
		||||
      let dispatcher = crate::engine::dispatch::default(
 | 
			
		||||
        &event_injector,
 | 
			
		||||
        &clipboard_injector,
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +153,7 @@ pub fn initialize_and_spawn(
 | 
			
		|||
        &clipboard_injector,
 | 
			
		||||
        &clipboard_injector,
 | 
			
		||||
        &context_menu_adapter,
 | 
			
		||||
        &icon_adapter,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      let mut engine = crate::engine::Engine::new(&funnel, &mut processor, &dispatcher);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								espanso/src/cli/worker/engine/process/middleware/disable.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								espanso/src/cli/worker/engine/process/middleware/disable.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
use crate::engine::{event::input::{Key, Variant}, process::DisableOptions};
 | 
			
		||||
use espanso_config::config::Config;
 | 
			
		||||
 | 
			
		||||
pub fn extract_disable_options(config: &dyn Config) -> DisableOptions {
 | 
			
		||||
  let (toggle_key, variant) = match config.toggle_key() {
 | 
			
		||||
    Some(key) => match key {
 | 
			
		||||
      espanso_config::config::ToggleKey::Ctrl => (Some(Key::Control), None),
 | 
			
		||||
      espanso_config::config::ToggleKey::Meta => (Some(Key::Meta), None),
 | 
			
		||||
      espanso_config::config::ToggleKey::Alt => (Some(Key::Alt), None),
 | 
			
		||||
      espanso_config::config::ToggleKey::Shift => (Some(Key::Shift), None),
 | 
			
		||||
      espanso_config::config::ToggleKey::RightCtrl => (Some(Key::Control), Some(Variant::Right)), 
 | 
			
		||||
      espanso_config::config::ToggleKey::RightAlt => (Some(Key::Alt), Some(Variant::Right)),
 | 
			
		||||
      espanso_config::config::ToggleKey::RightShift => (Some(Key::Shift), Some(Variant::Right)),
 | 
			
		||||
      espanso_config::config::ToggleKey::RightMeta => (Some(Key::Meta), Some(Variant::Right)),
 | 
			
		||||
      espanso_config::config::ToggleKey::LeftCtrl => (Some(Key::Control), Some(Variant::Left)),
 | 
			
		||||
      espanso_config::config::ToggleKey::LeftAlt => (Some(Key::Alt), Some(Variant::Left)),
 | 
			
		||||
      espanso_config::config::ToggleKey::LeftShift => (Some(Key::Shift), Some(Variant::Left)),
 | 
			
		||||
      espanso_config::config::ToggleKey::LeftMeta => (Some(Key::Meta), Some(Variant::Left)),
 | 
			
		||||
    },
 | 
			
		||||
    None => (None, None),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  DisableOptions {
 | 
			
		||||
    toggle_key,
 | 
			
		||||
    toggle_key_variant: variant,
 | 
			
		||||
    toggle_key_maximum_window: Duration::from_millis(1000),
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								espanso/src/cli/worker/engine/process/middleware/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								espanso/src/cli/worker/engine/process/middleware/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
pub mod disable;
 | 
			
		||||
							
								
								
									
										20
									
								
								espanso/src/cli/worker/engine/process/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								espanso/src/cli/worker/engine/process/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
pub mod middleware;
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use super::{ContextMenuHandler, Event, ImageInjector};
 | 
			
		||||
use super::{ContextMenuHandler, Event, IconHandler, ImageInjector};
 | 
			
		||||
use super::{ModeProvider, Dispatcher, Executor, KeyInjector, TextInjector, HtmlInjector};
 | 
			
		||||
 | 
			
		||||
pub struct DefaultDispatcher<'a> {
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +33,7 @@ impl<'a> DefaultDispatcher<'a> {
 | 
			
		|||
    html_injector: &'a dyn HtmlInjector,
 | 
			
		||||
    image_injector: &'a dyn ImageInjector,
 | 
			
		||||
    context_menu_handler: &'a dyn ContextMenuHandler,
 | 
			
		||||
    icon_handler: &'a dyn IconHandler,
 | 
			
		||||
  ) -> Self {
 | 
			
		||||
    Self {
 | 
			
		||||
      executors: vec![
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +53,9 @@ impl<'a> DefaultDispatcher<'a> {
 | 
			
		|||
        )),
 | 
			
		||||
        Box::new(super::executor::context_menu::ContextMenuExecutor::new(
 | 
			
		||||
          context_menu_handler,
 | 
			
		||||
        )),
 | 
			
		||||
        Box::new(super::executor::icon_update::IconUpdateExecutor::new(
 | 
			
		||||
          icon_handler,
 | 
			
		||||
        ))
 | 
			
		||||
      ],
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										53
									
								
								espanso/src/engine/dispatch/executor/icon_update.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								espanso/src/engine/dispatch/executor/icon_update.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use super::super::{Event, Executor};
 | 
			
		||||
use crate::engine::event::{EventType, ui::{IconStatus}};
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use log::error;
 | 
			
		||||
 | 
			
		||||
pub trait IconHandler {
 | 
			
		||||
  fn update_icon(&self, status: &IconStatus) -> Result<()>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct IconUpdateExecutor<'a> {
 | 
			
		||||
  handler: &'a dyn IconHandler,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> IconUpdateExecutor<'a> {
 | 
			
		||||
  pub fn new(handler: &'a dyn IconHandler) -> Self {
 | 
			
		||||
    Self { handler }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> Executor for IconUpdateExecutor<'a> {
 | 
			
		||||
  fn execute(&self, event: &Event) -> bool {
 | 
			
		||||
    if let EventType::IconStatusChange(m_event) = &event.etype {
 | 
			
		||||
      if let Err(error) = self.handler.update_icon(&m_event.status) {
 | 
			
		||||
        error!("icon handler reported an error: {:?}", error);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: test
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +18,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
pub mod context_menu;
 | 
			
		||||
pub mod icon_update;
 | 
			
		||||
pub mod image_inject;
 | 
			
		||||
pub mod html_inject;
 | 
			
		||||
pub mod key_inject;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,7 @@ pub use executor::html_inject::HtmlInjector;
 | 
			
		|||
pub use executor::text_inject::{Mode, ModeProvider, TextInjector};
 | 
			
		||||
pub use executor::image_inject::{ImageInjector};
 | 
			
		||||
pub use executor::context_menu::{ContextMenuHandler};
 | 
			
		||||
pub use executor::icon_update::IconHandler;
 | 
			
		||||
 | 
			
		||||
// TODO: move into module
 | 
			
		||||
pub trait KeyInjector {
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +52,7 @@ pub fn default<'a>(
 | 
			
		|||
  html_injector: &'a dyn HtmlInjector,
 | 
			
		||||
  image_injector: &'a dyn ImageInjector,
 | 
			
		||||
  context_menu_handler: &'a dyn ContextMenuHandler,
 | 
			
		||||
  icon_handler: &'a dyn IconHandler,
 | 
			
		||||
) -> impl Dispatcher + 'a {
 | 
			
		||||
  default::DefaultDispatcher::new(
 | 
			
		||||
    event_injector,
 | 
			
		||||
| 
						 | 
				
			
			@ -60,5 +62,6 @@ pub fn default<'a>(
 | 
			
		|||
    html_injector,
 | 
			
		||||
    image_injector,
 | 
			
		||||
    context_menu_handler,
 | 
			
		||||
    icon_handler,
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,11 @@ pub enum EventType {
 | 
			
		|||
  MatchInjected,
 | 
			
		||||
  DiscardPrevious(internal::DiscardPreviousEvent),
 | 
			
		||||
 | 
			
		||||
  Disabled,
 | 
			
		||||
  Enabled,
 | 
			
		||||
  SecureInputEnabled,
 | 
			
		||||
  SecureInputDisabled,
 | 
			
		||||
 | 
			
		||||
  // Effects
 | 
			
		||||
  TriggerCompensation(effect::TriggerCompensationEvent),
 | 
			
		||||
  CursorHintCompensation(effect::CursorHintCompensationEvent),
 | 
			
		||||
| 
						 | 
				
			
			@ -82,6 +87,7 @@ pub enum EventType {
 | 
			
		|||
 | 
			
		||||
  // UI
 | 
			
		||||
  ShowContextMenu(ui::ShowContextMenuEvent),
 | 
			
		||||
  IconStatusChange(ui::IconStatusChangeEvent),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,4 +39,16 @@ pub struct SimpleMenuItem {
 | 
			
		|||
pub struct SubMenuItem {
 | 
			
		||||
  pub label: String,
 | 
			
		||||
  pub items: Vec<MenuItem>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub struct IconStatusChangeEvent {
 | 
			
		||||
  pub status: IconStatus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub enum IconStatus {
 | 
			
		||||
  Enabled,
 | 
			
		||||
  Disabled,
 | 
			
		||||
  SecureInputDisabled,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -19,13 +19,13 @@
 | 
			
		|||
 | 
			
		||||
use log::trace;
 | 
			
		||||
 | 
			
		||||
use super::{MatchFilter, MatchInfoProvider, MatchSelector, Matcher, Middleware, Multiplexer, PathProvider, Processor, Renderer, middleware::{
 | 
			
		||||
use super::{DisableOptions, MatchFilter, MatchInfoProvider, MatchSelector, Matcher, Middleware, Multiplexer, PathProvider, Processor, Renderer, middleware::{
 | 
			
		||||
    match_select::MatchSelectMiddleware, matcher::MatcherMiddleware, multiplex::MultiplexMiddleware,
 | 
			
		||||
    render::RenderMiddleware, action::{ActionMiddleware, EventSequenceProvider}, cursor_hint::CursorHintMiddleware, cause::CauseCompensateMiddleware,
 | 
			
		||||
    delay_modifiers::{DelayForModifierReleaseMiddleware, ModifierStatusProvider}, markdown::MarkdownMiddleware,
 | 
			
		||||
    past_discard::PastEventsDiscardMiddleware,
 | 
			
		||||
  }};
 | 
			
		||||
use crate::engine::{event::{Event, EventType}, process::middleware::{context_menu::ContextMenuMiddleware, exit::ExitMiddleware, image_resolve::ImageResolverMiddleware}};
 | 
			
		||||
use crate::engine::{event::{Event, EventType}, process::middleware::{context_menu::ContextMenuMiddleware, disable::DisableMiddleware, exit::ExitMiddleware, icon_status::IconStatusMiddleware, image_resolve::ImageResolverMiddleware}};
 | 
			
		||||
use std::collections::VecDeque;
 | 
			
		||||
 | 
			
		||||
pub struct DefaultProcessor<'a> {
 | 
			
		||||
| 
						 | 
				
			
			@ -44,11 +44,14 @@ impl<'a> DefaultProcessor<'a> {
 | 
			
		|||
    modifier_status_provider: &'a dyn ModifierStatusProvider,
 | 
			
		||||
    event_sequence_provider: &'a dyn EventSequenceProvider,
 | 
			
		||||
    path_provider: &'a dyn PathProvider,
 | 
			
		||||
    disable_options: DisableOptions,
 | 
			
		||||
  ) -> DefaultProcessor<'a> {
 | 
			
		||||
    Self {
 | 
			
		||||
      event_queue: VecDeque::new(),
 | 
			
		||||
      middleware: vec![
 | 
			
		||||
        Box::new(PastEventsDiscardMiddleware::new()),
 | 
			
		||||
        Box::new(DisableMiddleware::new(disable_options)),
 | 
			
		||||
        Box::new(IconStatusMiddleware::new()),
 | 
			
		||||
        Box::new(MatcherMiddleware::new(matchers)),
 | 
			
		||||
        Box::new(ContextMenuMiddleware::new()),
 | 
			
		||||
        Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										125
									
								
								espanso/src/engine/process/middleware/disable.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								espanso/src/engine/process/middleware/disable.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,125 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::{
 | 
			
		||||
  cell::RefCell,
 | 
			
		||||
  time::{Duration, Instant},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use log::{info};
 | 
			
		||||
 | 
			
		||||
use super::super::Middleware;
 | 
			
		||||
use crate::engine::{event::{Event, EventType, input::{Key, KeyboardEvent, Status, Variant}}};
 | 
			
		||||
 | 
			
		||||
pub struct DisableOptions {
 | 
			
		||||
  pub toggle_key: Option<Key>,
 | 
			
		||||
  pub toggle_key_variant: Option<Variant>,
 | 
			
		||||
  pub toggle_key_maximum_window: Duration,
 | 
			
		||||
 | 
			
		||||
  // TODO: toggle shortcut?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct DisableMiddleware {
 | 
			
		||||
  enabled: RefCell<bool>,
 | 
			
		||||
  last_toggle_press: RefCell<Option<Instant>>,
 | 
			
		||||
  options: DisableOptions,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DisableMiddleware {
 | 
			
		||||
  pub fn new(options: DisableOptions) -> Self {
 | 
			
		||||
    Self {
 | 
			
		||||
      enabled: RefCell::new(true),
 | 
			
		||||
      last_toggle_press: RefCell::new(None),
 | 
			
		||||
      options,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Middleware for DisableMiddleware {
 | 
			
		||||
  fn name(&self) -> &'static str {
 | 
			
		||||
    "disable"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
 | 
			
		||||
    let mut has_status_changed = false;
 | 
			
		||||
    let mut enabled = self.enabled.borrow_mut();
 | 
			
		||||
 | 
			
		||||
    if let EventType::Keyboard(m_event) = &event.etype {
 | 
			
		||||
      if is_toggle_key(m_event, &self.options) {
 | 
			
		||||
        let mut last_toggle_press = self.last_toggle_press.borrow_mut();
 | 
			
		||||
        if let Some(previous_press) = *last_toggle_press {
 | 
			
		||||
          if previous_press.elapsed() < self.options.toggle_key_maximum_window {
 | 
			
		||||
            *enabled = !*enabled;
 | 
			
		||||
            *last_toggle_press = None;
 | 
			
		||||
            has_status_changed = true;
 | 
			
		||||
          } else {
 | 
			
		||||
            *last_toggle_press = Some(Instant::now());
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          *last_toggle_press = Some(Instant::now());
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if has_status_changed {
 | 
			
		||||
      info!("toggled enabled state, is_enabled = {}", *enabled);
 | 
			
		||||
      dispatch(Event::caused_by(
 | 
			
		||||
        event.source_id,
 | 
			
		||||
        if *enabled {
 | 
			
		||||
          EventType::Enabled
 | 
			
		||||
        } else {
 | 
			
		||||
          EventType::Disabled
 | 
			
		||||
        },
 | 
			
		||||
      ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Block keyboard events when disabled
 | 
			
		||||
    if let EventType::Keyboard(_) = &event.etype {
 | 
			
		||||
      if !*enabled {
 | 
			
		||||
        return Event::caused_by(event.source_id, EventType::NOOP);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // TODO: also ignore hotkey and mouse events
 | 
			
		||||
 | 
			
		||||
    event
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn is_toggle_key(event: &KeyboardEvent, options: &DisableOptions) -> bool {
 | 
			
		||||
  if event.status != Status::Released {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if options
 | 
			
		||||
    .toggle_key
 | 
			
		||||
    .as_ref()
 | 
			
		||||
    .map(|key| key == &event.key)
 | 
			
		||||
    .unwrap_or(false)
 | 
			
		||||
  {
 | 
			
		||||
    if let (Some(variant), Some(e_variant)) = (&options.toggle_key_variant, &event.variant) {
 | 
			
		||||
      variant == e_variant
 | 
			
		||||
    } else {
 | 
			
		||||
      true
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: test
 | 
			
		||||
							
								
								
									
										79
									
								
								espanso/src/engine/process/middleware/icon_status.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								espanso/src/engine/process/middleware/icon_status.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::{
 | 
			
		||||
  cell::RefCell,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::super::Middleware;
 | 
			
		||||
use crate::engine::event::{Event, EventType, ui::{IconStatus, IconStatusChangeEvent}};
 | 
			
		||||
 | 
			
		||||
pub struct IconStatusMiddleware {
 | 
			
		||||
  enabled: RefCell<bool>,
 | 
			
		||||
  secure_input_enabled: RefCell<bool>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IconStatusMiddleware {
 | 
			
		||||
  pub fn new() -> Self {
 | 
			
		||||
    Self {
 | 
			
		||||
      enabled: RefCell::new(true),
 | 
			
		||||
      secure_input_enabled: RefCell::new(false),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Middleware for IconStatusMiddleware {
 | 
			
		||||
  fn name(&self) -> &'static str {
 | 
			
		||||
    "icon_status"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
 | 
			
		||||
    let mut enabled = self.enabled.borrow_mut();
 | 
			
		||||
    let mut secure_input_enabled = self.secure_input_enabled.borrow_mut();
 | 
			
		||||
 | 
			
		||||
    let mut did_update = true;
 | 
			
		||||
    match &event.etype {
 | 
			
		||||
      EventType::Enabled => *enabled = true,
 | 
			
		||||
      EventType::Disabled => *enabled = false,
 | 
			
		||||
      EventType::SecureInputEnabled => *secure_input_enabled = true,
 | 
			
		||||
      EventType::SecureInputDisabled => *secure_input_enabled = false,
 | 
			
		||||
      _ => did_update = false,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if did_update {
 | 
			
		||||
      let status = if *enabled {
 | 
			
		||||
        if *secure_input_enabled {
 | 
			
		||||
          IconStatus::SecureInputDisabled
 | 
			
		||||
        } else {
 | 
			
		||||
          IconStatus::Enabled
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        IconStatus::Disabled
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      dispatch(Event::caused_by(event.source_id, EventType::IconStatusChange(IconStatusChangeEvent {
 | 
			
		||||
        status,
 | 
			
		||||
      })));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    event
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: test
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,9 @@ pub mod cause;
 | 
			
		|||
pub mod context_menu;
 | 
			
		||||
pub mod cursor_hint;
 | 
			
		||||
pub mod delay_modifiers;
 | 
			
		||||
pub mod disable;
 | 
			
		||||
pub mod exit;
 | 
			
		||||
pub mod icon_status;
 | 
			
		||||
pub mod image_resolve;
 | 
			
		||||
pub mod match_select;
 | 
			
		||||
pub mod matcher;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,6 +95,7 @@ pub enum RendererError {
 | 
			
		|||
pub use middleware::action::{MatchInfoProvider, EventSequenceProvider};
 | 
			
		||||
pub use middleware::delay_modifiers::ModifierStatusProvider;
 | 
			
		||||
pub use middleware::image_resolve::PathProvider;
 | 
			
		||||
pub use middleware::disable::DisableOptions;
 | 
			
		||||
 | 
			
		||||
pub fn default<'a, MatcherState>(
 | 
			
		||||
  matchers: &'a [&'a dyn Matcher<'a, MatcherState>],
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +107,7 @@ pub fn default<'a, MatcherState>(
 | 
			
		|||
  modifier_status_provider: &'a dyn ModifierStatusProvider,
 | 
			
		||||
  event_sequence_provider: &'a dyn EventSequenceProvider,
 | 
			
		||||
  path_provider: &'a dyn PathProvider,
 | 
			
		||||
  disable_options: DisableOptions,
 | 
			
		||||
) -> impl Processor + 'a {
 | 
			
		||||
  default::DefaultProcessor::new(
 | 
			
		||||
    matchers,
 | 
			
		||||
| 
						 | 
				
			
			@ -117,5 +119,6 @@ pub fn default<'a, MatcherState>(
 | 
			
		|||
    modifier_status_provider,
 | 
			
		||||
    event_sequence_provider,
 | 
			
		||||
    path_provider,
 | 
			
		||||
    disable_options,
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user