diff --git a/espanso/src/cli/worker/engine/executor/key_injector.rs b/espanso/src/cli/worker/engine/executor/key_injector.rs new file mode 100644 index 0000000..ba160af --- /dev/null +++ b/espanso/src/cli/worker/engine/executor/key_injector.rs @@ -0,0 +1,84 @@ +/* + * 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 . + */ + +use espanso_inject::Injector; + +use crate::engine::dispatch::KeyInjector; + +pub struct KeyInjectorAdapter<'a> { + injector: &'a dyn Injector, +} + +impl<'a> KeyInjectorAdapter<'a> { + pub fn new(injector: &'a dyn Injector) -> Self { + Self { injector } + } +} + +impl<'a> KeyInjector for KeyInjectorAdapter<'a> { + fn inject_sequence(&self, keys: &[crate::engine::event::keyboard::Key]) -> anyhow::Result<()> { + let converted_keys: Vec<_> = keys.iter().map(convert_to_inject_key).collect(); + self.injector.send_keys(&converted_keys, Default::default()) // TODO: handle options + } +} + +fn convert_to_inject_key(key: &crate::engine::event::keyboard::Key) -> espanso_inject::keys::Key { + match key { + crate::engine::event::keyboard::Key::Alt => espanso_inject::keys::Key::Alt, + crate::engine::event::keyboard::Key::CapsLock => espanso_inject::keys::Key::CapsLock, + crate::engine::event::keyboard::Key::Control => espanso_inject::keys::Key::Control, + crate::engine::event::keyboard::Key::Meta => espanso_inject::keys::Key::Meta, + crate::engine::event::keyboard::Key::NumLock => espanso_inject::keys::Key::NumLock, + crate::engine::event::keyboard::Key::Shift => espanso_inject::keys::Key::Shift, + crate::engine::event::keyboard::Key::Enter => espanso_inject::keys::Key::Enter, + crate::engine::event::keyboard::Key::Tab => espanso_inject::keys::Key::Tab, + crate::engine::event::keyboard::Key::Space => espanso_inject::keys::Key::Space, + crate::engine::event::keyboard::Key::ArrowDown => espanso_inject::keys::Key::ArrowDown, + crate::engine::event::keyboard::Key::ArrowLeft => espanso_inject::keys::Key::ArrowLeft, + crate::engine::event::keyboard::Key::ArrowRight => espanso_inject::keys::Key::ArrowRight, + crate::engine::event::keyboard::Key::ArrowUp => espanso_inject::keys::Key::ArrowUp, + crate::engine::event::keyboard::Key::End => espanso_inject::keys::Key::End, + crate::engine::event::keyboard::Key::Home => espanso_inject::keys::Key::Home, + crate::engine::event::keyboard::Key::PageDown => espanso_inject::keys::Key::PageDown, + crate::engine::event::keyboard::Key::PageUp => espanso_inject::keys::Key::PageUp, + crate::engine::event::keyboard::Key::Escape => espanso_inject::keys::Key::Escape, + crate::engine::event::keyboard::Key::Backspace => espanso_inject::keys::Key::Backspace, + crate::engine::event::keyboard::Key::F1 => espanso_inject::keys::Key::F1, + crate::engine::event::keyboard::Key::F2 => espanso_inject::keys::Key::F2, + crate::engine::event::keyboard::Key::F3 => espanso_inject::keys::Key::F3, + crate::engine::event::keyboard::Key::F4 => espanso_inject::keys::Key::F4, + crate::engine::event::keyboard::Key::F5 => espanso_inject::keys::Key::F5, + crate::engine::event::keyboard::Key::F6 => espanso_inject::keys::Key::F6, + crate::engine::event::keyboard::Key::F7 => espanso_inject::keys::Key::F7, + crate::engine::event::keyboard::Key::F8 => espanso_inject::keys::Key::F8, + crate::engine::event::keyboard::Key::F9 => espanso_inject::keys::Key::F9, + crate::engine::event::keyboard::Key::F10 => espanso_inject::keys::Key::F10, + crate::engine::event::keyboard::Key::F11 => espanso_inject::keys::Key::F11, + crate::engine::event::keyboard::Key::F12 => espanso_inject::keys::Key::F12, + crate::engine::event::keyboard::Key::F13 => espanso_inject::keys::Key::F13, + crate::engine::event::keyboard::Key::F14 => espanso_inject::keys::Key::F14, + crate::engine::event::keyboard::Key::F15 => espanso_inject::keys::Key::F15, + crate::engine::event::keyboard::Key::F16 => espanso_inject::keys::Key::F16, + crate::engine::event::keyboard::Key::F17 => espanso_inject::keys::Key::F17, + crate::engine::event::keyboard::Key::F18 => espanso_inject::keys::Key::F18, + crate::engine::event::keyboard::Key::F19 => espanso_inject::keys::Key::F19, + crate::engine::event::keyboard::Key::F20 => espanso_inject::keys::Key::F20, + crate::engine::event::keyboard::Key::Other(raw) => espanso_inject::keys::Key::Raw(*raw), + } +} diff --git a/espanso/src/cli/worker/engine/executor/mod.rs b/espanso/src/cli/worker/engine/executor/mod.rs index 93435fd..025aa56 100644 --- a/espanso/src/cli/worker/engine/executor/mod.rs +++ b/espanso/src/cli/worker/engine/executor/mod.rs @@ -17,4 +17,5 @@ * along with espanso. If not, see . */ -pub mod text_injector; \ No newline at end of file +pub mod text_injector; +pub mod key_injector; \ No newline at end of file diff --git a/espanso/src/cli/worker/engine/executor/text_injector.rs b/espanso/src/cli/worker/engine/executor/text_injector.rs index 2a5bc84..4b65800 100644 --- a/espanso/src/cli/worker/engine/executor/text_injector.rs +++ b/espanso/src/cli/worker/engine/executor/text_injector.rs @@ -17,21 +17,25 @@ * along with espanso. If not, see . */ +use espanso_inject::Injector; + use crate::engine::dispatch::TextInjector; -pub struct TextInjectorAdapter {} +pub struct TextInjectorAdapter<'a> { + injector: &'a dyn Injector, +} -impl TextInjectorAdapter { - pub fn new() -> Self { - Self {} +impl <'a> TextInjectorAdapter<'a> { + pub fn new(injector: &'a dyn Injector) -> Self { + Self { + injector + } } } -impl TextInjector for TextInjectorAdapter { - fn inject(&self, text: &str) -> anyhow::Result<()> { - // TODO: implement - println!("INJECT: {}", text); - - Ok(()) +impl <'a> TextInjector for TextInjectorAdapter<'a> { + fn inject_text(&self, text: &str) -> anyhow::Result<()> { + // TODO: handle injection options + self.injector.send_string(text, Default::default()) } } diff --git a/espanso/src/cli/worker/mod.rs b/espanso/src/cli/worker/mod.rs index 2d15c1a..44c79c6 100644 --- a/espanso/src/cli/worker/mod.rs +++ b/espanso/src/cli/worker/mod.rs @@ -63,8 +63,11 @@ fn worker_main(args: CliModuleArgs) { let mut processor = process::default(&matchers, &config_manager, &selector, &multiplexer, &renderer_adapter); - let text_injector = engine::executor::text_injector::TextInjectorAdapter::new(); - let dispatcher = dispatch::default(&text_injector); + let injector = espanso_inject::get_injector(Default::default()).expect("failed to initialize injector module"); // TODO: handle the options + + let text_injector = engine::executor::text_injector::TextInjectorAdapter::new(&*injector); + let key_injector = engine::executor::key_injector::KeyInjectorAdapter::new(&*injector); + let dispatcher = dispatch::default(&text_injector, &key_injector); let mut engine = Engine::new(&funnel, &mut processor, &dispatcher); engine.run(); diff --git a/espanso/src/engine/dispatch/default.rs b/espanso/src/engine/dispatch/default.rs index 3c8646b..0867ad2 100644 --- a/espanso/src/engine/dispatch/default.rs +++ b/espanso/src/engine/dispatch/default.rs @@ -17,7 +17,7 @@ * along with espanso. If not, see . */ -use super::{Dispatcher, Executor, TextInjector}; +use super::{Dispatcher, Executor, KeyInjector, TextInjector}; use super::Event; pub struct DefaultDispatcher<'a> { @@ -25,10 +25,11 @@ pub struct DefaultDispatcher<'a> { } impl <'a> DefaultDispatcher<'a> { - pub fn new(text_injector: &'a dyn TextInjector) -> Self { + pub fn new(text_injector: &'a dyn TextInjector, key_injector: &'a dyn KeyInjector) -> Self { Self { executors: vec![ Box::new(super::executor::text_inject::TextInjectExecutor::new(text_injector)), + Box::new(super::executor::key_inject::KeyInjectExecutor::new(key_injector)), ] } } diff --git a/espanso/src/engine/dispatch/executor/key_inject.rs b/espanso/src/engine/dispatch/executor/key_inject.rs new file mode 100644 index 0000000..3182a38 --- /dev/null +++ b/espanso/src/engine/dispatch/executor/key_inject.rs @@ -0,0 +1,44 @@ +/* + * 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 . + */ + +use super::super::{Event, Executor, KeyInjector}; +use log::error; + +pub struct KeyInjectExecutor<'a> { + injector: &'a dyn KeyInjector, +} + +impl<'a> KeyInjectExecutor<'a> { + pub fn new(injector: &'a dyn KeyInjector) -> Self { + Self { injector } + } +} + +impl<'a> Executor for KeyInjectExecutor<'a> { + fn execute(&self, event: &Event) -> bool { + if let Event::KeySequenceInject(inject_event) = event { + if let Err(error) = self.injector.inject_sequence(&inject_event.keys) { + error!("key injector reported an error: {}", error); + } + return true; + } + + false + } +} diff --git a/espanso/src/engine/dispatch/executor/mod.rs b/espanso/src/engine/dispatch/executor/mod.rs index 05c1a2f..9631006 100644 --- a/espanso/src/engine/dispatch/executor/mod.rs +++ b/espanso/src/engine/dispatch/executor/mod.rs @@ -17,4 +17,5 @@ * along with espanso. If not, see . */ -pub mod text_inject; \ No newline at end of file +pub mod text_inject; +pub mod key_inject; \ No newline at end of file diff --git a/espanso/src/engine/dispatch/executor/text_inject.rs b/espanso/src/engine/dispatch/executor/text_inject.rs index ca5da46..30e6ffb 100644 --- a/espanso/src/engine/dispatch/executor/text_inject.rs +++ b/espanso/src/engine/dispatch/executor/text_inject.rs @@ -18,7 +18,7 @@ */ use super::super::{Event, Executor, TextInjector}; -use crate::engine::event::inject::TextInjectMode; +use crate::engine::event::text::TextInjectMode; use log::error; pub struct TextInjectExecutor<'a> { @@ -35,7 +35,7 @@ impl<'a> Executor for TextInjectExecutor<'a> { fn execute(&self, event: &Event) -> bool { if let Event::TextInject(inject_event) = event { if let Some(TextInjectMode::Keys) = inject_event.force_mode { - if let Err(error) = self.injector.inject(&inject_event.text) { + if let Err(error) = self.injector.inject_text(&inject_event.text) { error!("text injector reported an error: {:?}", error); } return true; diff --git a/espanso/src/engine/dispatch/mod.rs b/espanso/src/engine/dispatch/mod.rs index 542e054..03a2cb6 100644 --- a/espanso/src/engine/dispatch/mod.rs +++ b/espanso/src/engine/dispatch/mod.rs @@ -18,7 +18,7 @@ */ use anyhow::Result; -use super::Event; +use super::{Event, event::keyboard::Key}; mod executor; mod default; @@ -32,11 +32,16 @@ pub trait Dispatcher { } pub trait TextInjector { - fn inject(&self, text: &str) -> Result<()>; + fn inject_text(&self, text: &str) -> Result<()>; } -pub fn default<'a>(text_injector: &'a dyn TextInjector) -> impl Dispatcher + 'a { +pub trait KeyInjector { + fn inject_sequence(&self, keys: &[Key]) -> Result<()>; +} + +pub fn default<'a>(text_injector: &'a dyn TextInjector, key_injector: &'a dyn KeyInjector) -> impl Dispatcher + 'a { default::DefaultDispatcher::new( text_injector, + key_injector, ) } \ No newline at end of file diff --git a/espanso/src/engine/event/keyboard.rs b/espanso/src/engine/event/keyboard.rs index 05fb0a8..da2d819 100644 --- a/espanso/src/engine/event/keyboard.rs +++ b/espanso/src/engine/event/keyboard.rs @@ -37,6 +37,11 @@ pub struct KeyboardEvent { pub variant: Option, } +#[derive(Debug)] +pub struct KeySequenceInjectRequest { + pub keys: Vec, +} + #[derive(Debug, Clone, PartialEq)] pub enum Key { // Modifiers diff --git a/espanso/src/engine/event/mod.rs b/espanso/src/engine/event/mod.rs index a55f080..3bfc01c 100644 --- a/espanso/src/engine/event/mod.rs +++ b/espanso/src/engine/event/mod.rs @@ -18,7 +18,7 @@ */ pub mod keyboard; -pub mod inject; +pub mod text; pub mod matches; pub mod render; @@ -38,5 +38,6 @@ pub enum Event { Rendered(render::RenderedEvent), // Effects - TextInject(inject::TextInjectRequest), + KeySequenceInject(keyboard::KeySequenceInjectRequest), + TextInject(text::TextInjectRequest), } \ No newline at end of file diff --git a/espanso/src/engine/event/inject.rs b/espanso/src/engine/event/text.rs similarity index 97% rename from espanso/src/engine/event/inject.rs rename to espanso/src/engine/event/text.rs index 1edc09a..79db95c 100644 --- a/espanso/src/engine/event/inject.rs +++ b/espanso/src/engine/event/text.rs @@ -19,7 +19,6 @@ #[derive(Debug)] pub struct TextInjectRequest { - pub delete_count: i32, pub text: String, pub force_mode: Option, } @@ -28,4 +27,5 @@ pub struct TextInjectRequest { pub enum TextInjectMode { Keys, Clipboard, -} \ No newline at end of file +} + diff --git a/espanso/src/engine/process/default.rs b/espanso/src/engine/process/default.rs index 988e965..e38132f 100644 --- a/espanso/src/engine/process/default.rs +++ b/espanso/src/engine/process/default.rs @@ -22,7 +22,7 @@ use log::trace; use super::{ middleware::{ match_select::MatchSelectMiddleware, matcher::MatchMiddleware, multiplex::MultiplexMiddleware, - render::RenderMiddleware, + render::RenderMiddleware, action::ActionMiddleware, }, Event, MatchFilter, MatchSelector, Matcher, Middleware, Multiplexer, Processor, Renderer, }; @@ -48,6 +48,7 @@ impl<'a> DefaultProcessor<'a> { Box::new(MatchSelectMiddleware::new(match_filter, match_selector)), Box::new(MultiplexMiddleware::new(multiplexer)), Box::new(RenderMiddleware::new(renderer)), + Box::new(ActionMiddleware::new()), ], } } @@ -57,7 +58,7 @@ impl<'a> DefaultProcessor<'a> { let mut current_event = event; let mut current_queue = VecDeque::new(); - let dispatch = |event: Event| { + let mut dispatch = |event: Event| { trace!("dispatched event: {:?}", event); current_queue.push_front(event); }; @@ -65,7 +66,7 @@ impl<'a> DefaultProcessor<'a> { for middleware in self.middleware.iter() { trace!("middleware received event: {:?}", current_event); - current_event = middleware.next(current_event, &dispatch); + current_event = middleware.next(current_event, &mut dispatch); trace!("middleware produced event: {:?}", current_event); } diff --git a/espanso/src/engine/process/middleware/action.rs b/espanso/src/engine/process/middleware/action.rs new file mode 100644 index 0000000..a81c030 --- /dev/null +++ b/espanso/src/engine/process/middleware/action.rs @@ -0,0 +1,57 @@ +/* + * 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 . + */ + +use log::{debug, error}; + +use super::super::Middleware; +use crate::engine::{event::{Event, keyboard::{Key, KeySequenceInjectRequest}, matches::MatchSelectedEvent, text::{TextInjectMode, TextInjectRequest}}, process::{MatchFilter, MatchSelector, Multiplexer}}; + +pub struct ActionMiddleware { +} + +impl ActionMiddleware { + pub fn new() -> Self { + Self {} + } +} + +impl Middleware for ActionMiddleware { + fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event { + if let Event::Rendered(m_event) = &event { + let delete_count = m_event.trigger.len(); + let delete_sequence: Vec<_> = (0..delete_count).map(|_| Key::Backspace).collect(); + + dispatch(Event::TextInject(TextInjectRequest { + text: m_event.body.clone(), + force_mode: Some(TextInjectMode::Keys), // TODO: determine this one dynamically + })); + + // This is executed before the dispatched event + return Event::KeySequenceInject(KeySequenceInjectRequest { + keys: delete_sequence + }) + } + + // TODO: handle images + + event + } +} + +// TODO: test diff --git a/espanso/src/engine/process/middleware/match_select.rs b/espanso/src/engine/process/middleware/match_select.rs index 146ad0b..6edb5b6 100644 --- a/espanso/src/engine/process/middleware/match_select.rs +++ b/espanso/src/engine/process/middleware/match_select.rs @@ -43,7 +43,7 @@ impl<'a> MatchSelectMiddleware<'a> { } impl<'a> Middleware for MatchSelectMiddleware<'a> { - fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event { + fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { if let Event::MatchesDetected(m_event) = event { let matches_ids: Vec = m_event.matches.iter().map(|m| m.id).collect(); diff --git a/espanso/src/engine/process/middleware/matcher.rs b/espanso/src/engine/process/middleware/matcher.rs index f9a5dfd..862c7fb 100644 --- a/espanso/src/engine/process/middleware/matcher.rs +++ b/espanso/src/engine/process/middleware/matcher.rs @@ -41,7 +41,7 @@ impl<'a, State> MatchMiddleware<'a, State> { } impl<'a, State> Middleware for MatchMiddleware<'a, State> { - fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event { + fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { let mut matcher_states = self.matcher_states.borrow_mut(); let prev_states = if !matcher_states.is_empty() { matcher_states.get(matcher_states.len() - 1) diff --git a/espanso/src/engine/process/middleware/mod.rs b/espanso/src/engine/process/middleware/mod.rs index e449e1a..082bb0f 100644 --- a/espanso/src/engine/process/middleware/mod.rs +++ b/espanso/src/engine/process/middleware/mod.rs @@ -17,6 +17,7 @@ * along with espanso. If not, see . */ +pub mod action; pub mod render; pub mod matcher; pub mod multiplex; diff --git a/espanso/src/engine/process/middleware/multiplex.rs b/espanso/src/engine/process/middleware/multiplex.rs index 9e9235b..890e91c 100644 --- a/espanso/src/engine/process/middleware/multiplex.rs +++ b/espanso/src/engine/process/middleware/multiplex.rs @@ -20,7 +20,7 @@ use log::{debug, error}; use super::super::Middleware; -use crate::engine::{event::{Event, inject::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent}, process::{MatchFilter, MatchSelector, Multiplexer}}; +use crate::engine::{event::{Event, text::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent}, process::{MatchFilter, MatchSelector, Multiplexer}}; pub struct MultiplexMiddleware<'a> { multiplexer: &'a dyn Multiplexer, @@ -33,7 +33,7 @@ impl<'a> MultiplexMiddleware<'a> { } impl<'a> Middleware for MultiplexMiddleware<'a> { - fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event { + fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { if let Event::MatchSelected(m_event) = event { return match self.multiplexer.convert(m_event.chosen.id, m_event.chosen.trigger, m_event.chosen.args) { Some(event) => event, diff --git a/espanso/src/engine/process/middleware/render.rs b/espanso/src/engine/process/middleware/render.rs index cb31040..d9ddce8 100644 --- a/espanso/src/engine/process/middleware/render.rs +++ b/espanso/src/engine/process/middleware/render.rs @@ -20,7 +20,7 @@ use log::{debug, error}; use super::super::Middleware; -use crate::engine::{event::{Event, inject::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent, render::RenderedEvent}, process::{MatchFilter, MatchSelector, Renderer, RendererError}}; +use crate::engine::{event::{Event, text::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent, render::RenderedEvent}, process::{MatchFilter, MatchSelector, Renderer, RendererError}}; pub struct RenderMiddleware<'a> { renderer: &'a dyn Renderer<'a>, @@ -33,7 +33,7 @@ impl<'a> RenderMiddleware<'a> { } impl<'a> Middleware for RenderMiddleware<'a> { - fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event { + fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { if let Event::RenderingRequested(m_event) = event { match self.renderer.render(m_event.match_id, m_event.trigger_args) { Ok(body) => { diff --git a/espanso/src/engine/process/mod.rs b/espanso/src/engine/process/mod.rs index 9258869..490e3b4 100644 --- a/espanso/src/engine/process/mod.rs +++ b/espanso/src/engine/process/mod.rs @@ -26,7 +26,7 @@ mod default; mod middleware; pub trait Middleware { - fn next(&self, event: Event, dispatch: &dyn FnMut(Event)) -> Event; + fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event; } pub trait Processor {